sqlbenchdag 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (153) hide show
  1. infrastructure/debug_aws.py +40 -0
  2. scripts/dev/backfill_queries.py +44 -0
  3. scripts/dev/timestamp_capsule.py +49 -0
  4. scripts/dev/upgrade_capsule.py +63 -0
  5. scripts/dev/verify_capsule.py +79 -0
  6. scripts/dev/verify_portability.py +103 -0
  7. scripts/tools/_plotlib.py +43 -0
  8. scripts/tools/analyze_scaling.py +39 -0
  9. scripts/tools/demo_breach_detection.py +61 -0
  10. scripts/tools/extract_results.py +57 -0
  11. scripts/tools/find_kink.py +104 -0
  12. scripts/tools/gen_experiment_catalog.py +103 -0
  13. scripts/tools/load_parquet_to_local.py +98 -0
  14. scripts/tools/plot_execution_modes.py +82 -0
  15. scripts/tools/plot_scaling.py +91 -0
  16. scripts/tools/plot_selectivity.py +139 -0
  17. scripts/tools/plot_threads.py +95 -0
  18. scripts/tools/regenerate_dashboard.py +58 -0
  19. scripts/tools/verify_doc_claims.py +88 -0
  20. sql_benchmarks/__init__.py +3 -0
  21. sql_benchmarks/api/__init__.py +0 -0
  22. sql_benchmarks/api/app.py +30 -0
  23. sql_benchmarks/api/data/__init__.py +0 -0
  24. sql_benchmarks/api/data/catalog_reader.py +73 -0
  25. sql_benchmarks/api/data/reader.py +125 -0
  26. sql_benchmarks/api/logic/__init__.py +0 -0
  27. sql_benchmarks/api/logic/comparator.py +44 -0
  28. sql_benchmarks/api/logic/ranker.py +127 -0
  29. sql_benchmarks/api/models/__init__.py +0 -0
  30. sql_benchmarks/api/models/catalog.py +22 -0
  31. sql_benchmarks/api/models/experiments.py +20 -0
  32. sql_benchmarks/api/models/recommend.py +11 -0
  33. sql_benchmarks/api/models/results.py +66 -0
  34. sql_benchmarks/api/routers/__init__.py +0 -0
  35. sql_benchmarks/api/routers/catalog.py +19 -0
  36. sql_benchmarks/api/routers/experiments.py +79 -0
  37. sql_benchmarks/api/routers/recommend.py +22 -0
  38. sql_benchmarks/api/routers/results.py +51 -0
  39. sql_benchmarks/assets/__init__.py +4 -0
  40. sql_benchmarks/assets/benchmark_factory.py +222 -0
  41. sql_benchmarks/assets/data_factory.py +54 -0
  42. sql_benchmarks/assets/data_quality.py +91 -0
  43. sql_benchmarks/assets/ingestion_factory.py +88 -0
  44. sql_benchmarks/assets/maintenance.py +63 -0
  45. sql_benchmarks/assets/reporting.py +385 -0
  46. sql_benchmarks/assets/semantic_gate.py +76 -0
  47. sql_benchmarks/cli.py +69 -0
  48. sql_benchmarks/config_loader.py +104 -0
  49. sql_benchmarks/constants.py +60 -0
  50. sql_benchmarks/coordinator.py +282 -0
  51. sql_benchmarks/definitions.py +115 -0
  52. sql_benchmarks/experiments/templates/experiment_template.yaml +99 -0
  53. sql_benchmarks/harness.py +84 -0
  54. sql_benchmarks/jobs.py +8 -0
  55. sql_benchmarks/partitions.py +17 -0
  56. sql_benchmarks/plugins/data_sources/declarative_gen.py +211 -0
  57. sql_benchmarks/plugins/data_sources/local_file_loader.py +62 -0
  58. sql_benchmarks/plugins/data_sources/tpc_h.py +61 -0
  59. sql_benchmarks/resources/__init__.py +0 -0
  60. sql_benchmarks/resources/actian.py +234 -0
  61. sql_benchmarks/resources/actian_client.py +231 -0
  62. sql_benchmarks/resources/base_engine.py +58 -0
  63. sql_benchmarks/resources/base_schema_client.py +104 -0
  64. sql_benchmarks/resources/duckdb.py +58 -0
  65. sql_benchmarks/resources/duckdb_client.py +157 -0
  66. sql_benchmarks/resources/postgres.py +188 -0
  67. sql_benchmarks/resources/postgres_client.py +184 -0
  68. sql_benchmarks/resources/quack.py +56 -0
  69. sql_benchmarks/resources/quack_client.py +169 -0
  70. sql_benchmarks/resources/typedb_client.py +370 -0
  71. sql_benchmarks/resources/typedb_engine.py +303 -0
  72. sql_benchmarks/scripts/__init__.py +0 -0
  73. sql_benchmarks/scripts/sql/acid_test/duckdb/test.sql +1 -0
  74. sql_benchmarks/scripts/sql/acid_test/postgres/test.sql +1 -0
  75. sql_benchmarks/scripts/sql/analytical_wall/actian/analytical_wall.sql +15 -0
  76. sql_benchmarks/scripts/sql/analytical_wall/analytical_wall.sql.template +19 -0
  77. sql_benchmarks/scripts/sql/analytical_wall/duckdb/analytical_wall.sql +15 -0
  78. sql_benchmarks/scripts/sql/analytical_wall/postgres/analytical_wall.sql +15 -0
  79. sql_benchmarks/scripts/sql/group_by/duckdb/groupby_antipattern.sql +11 -0
  80. sql_benchmarks/scripts/sql/group_by/duckdb/groupby_recommended_cte.sql +19 -0
  81. sql_benchmarks/scripts/sql/group_by/postgres/groupby_antipattern.sql +13 -0
  82. sql_benchmarks/scripts/sql/group_by/postgres/groupby_recommended_pk.sql +11 -0
  83. sql_benchmarks/scripts/sql/hypergraph/duckdb/q_1hop.sql +5 -0
  84. sql_benchmarks/scripts/sql/hypergraph/duckdb/q_2hop.sql +6 -0
  85. sql_benchmarks/scripts/sql/hypergraph/duckdb/q_full.sql +9 -0
  86. sql_benchmarks/scripts/sql/hypergraph/typedb/q_1hop.sql +4 -0
  87. sql_benchmarks/scripts/sql/hypergraph/typedb/q_2hop.sql +5 -0
  88. sql_benchmarks/scripts/sql/hypergraph/typedb/q_full.sql +6 -0
  89. sql_benchmarks/scripts/sql/joins/duckdb/join_antipattern.sql +5 -0
  90. sql_benchmarks/scripts/sql/joins/duckdb/join_recommended.sql +4 -0
  91. sql_benchmarks/scripts/sql/joins/postgres/join_antipattern.sql +5 -0
  92. sql_benchmarks/scripts/sql/joins/postgres/join_recommended.sql +4 -0
  93. sql_benchmarks/scripts/sql/null_logic/duckdb/2VL_identity.sql +14 -0
  94. sql_benchmarks/scripts/sql/null_logic/duckdb/3VL_identity.sql +5 -0
  95. sql_benchmarks/scripts/sql/null_logic/postgres/2VL_identity.sql +14 -0
  96. sql_benchmarks/scripts/sql/null_logic/postgres/3VL_identity.sql +5 -0
  97. sql_benchmarks/scripts/sql/null_sentinel/duckdb/2VL_identity.sql +14 -0
  98. sql_benchmarks/scripts/sql/null_sentinel/duckdb/3VL_identity.sql +5 -0
  99. sql_benchmarks/scripts/sql/null_sentinel/duckdb/sentinel_optimization.sql +16 -0
  100. sql_benchmarks/scripts/sql/null_sentinel/postgres/2VL_identity.sql +14 -0
  101. sql_benchmarks/scripts/sql/null_sentinel/postgres/3VL_identity.sql +5 -0
  102. sql_benchmarks/scripts/sql/null_sentinel/postgres/sentinel_optimization.sql +21 -0
  103. sql_benchmarks/scripts/sql/recursion/duckdb/recursive_cte.sql +26 -0
  104. sql_benchmarks/scripts/sql/recursion/postgres/recursive_cte.sql +30 -0
  105. sql_benchmarks/scripts/sql/recursive_graph/duckdb/q_bounded_3hop.sql +17 -0
  106. sql_benchmarks/scripts/sql/recursive_graph/duckdb/q_fixed_2hop.sql +6 -0
  107. sql_benchmarks/scripts/sql/recursive_graph/duckdb/q_transitive_closure.sql +17 -0
  108. sql_benchmarks/scripts/sql/recursive_graph/typedb/q_bounded_3hop.sql +6 -0
  109. sql_benchmarks/scripts/sql/recursive_graph/typedb/q_fixed_2hop.sql +5 -0
  110. sql_benchmarks/scripts/sql/recursive_graph/typedb/q_transitive_closure.sql +7 -0
  111. sql_benchmarks/scripts/sql/security/acid_resilience/duckdb/test.sql +1 -0
  112. sql_benchmarks/scripts/sql/selectivity/duckdb/q_0_1_percent.sql +1 -0
  113. sql_benchmarks/scripts/sql/selectivity/duckdb/q_10_percent.sql +1 -0
  114. sql_benchmarks/scripts/sql/selectivity/duckdb/q_1_percent.sql +1 -0
  115. sql_benchmarks/scripts/sql/selectivity/duckdb/q_20_percent.sql +1 -0
  116. sql_benchmarks/scripts/sql/selectivity/duckdb/q_5_percent.sql +1 -0
  117. sql_benchmarks/scripts/sql/selectivity/duckdb/q_filler.sql +1 -0
  118. sql_benchmarks/scripts/sql/selectivity/postgres/q_0_1_percent.sql +1 -0
  119. sql_benchmarks/scripts/sql/selectivity/postgres/q_10_percent.sql +1 -0
  120. sql_benchmarks/scripts/sql/selectivity/postgres/q_1_percent.sql +1 -0
  121. sql_benchmarks/scripts/sql/selectivity/postgres/q_20_percent.sql +1 -0
  122. sql_benchmarks/scripts/sql/selectivity/postgres/q_5_percent.sql +1 -0
  123. sql_benchmarks/scripts/sql/selectivity/postgres/q_filler.sql +1 -0
  124. sql_benchmarks/scripts/sql/selectivity/typedb/q_0_1_percent.sql +4 -0
  125. sql_benchmarks/scripts/sql/selectivity/typedb/q_10_percent.sql +4 -0
  126. sql_benchmarks/scripts/sql/selectivity/typedb/q_1_percent.sql +4 -0
  127. sql_benchmarks/scripts/sql/selectivity/typedb/q_20_percent.sql +4 -0
  128. sql_benchmarks/scripts/sql/selectivity/typedb/q_5_percent.sql +4 -0
  129. sql_benchmarks/scripts/sql/selectivity/typedb/q_filler.sql +4 -0
  130. sql_benchmarks/scripts/sql/sort_spill/duckdb/sort_full.sql +25 -0
  131. sql_benchmarks/scripts/sql/sort_spill/duckdb/sort_wide_rows.sql +25 -0
  132. sql_benchmarks/scripts/sql/sort_spill/postgres/sort_full.sql +25 -0
  133. sql_benchmarks/scripts/sql/sort_spill/postgres/sort_wide_rows.sql +26 -0
  134. sql_benchmarks/scripts/sql/tpch/duckdb/q3_shipping_priority.sql +25 -0
  135. sql_benchmarks/scripts/sql/tpch/postgres/q3_shipping_priority.sql +25 -0
  136. sql_benchmarks/utils/__init__.py +0 -0
  137. sql_benchmarks/utils/common.py +260 -0
  138. sql_benchmarks/utils/ddl.py +47 -0
  139. sql_benchmarks/utils/hasher.py +124 -0
  140. sql_benchmarks/utils/integrity_monitor.py +55 -0
  141. sql_benchmarks/utils/providers.py +184 -0
  142. sql_benchmarks/utils/scaling.py +88 -0
  143. sql_benchmarks/utils/schema.py +118 -0
  144. sql_benchmarks/utils/semantic_auditor.py +81 -0
  145. sql_benchmarks/utils/system.py +100 -0
  146. sql_benchmarks/validator.py +60 -0
  147. sqlbenchdag-0.1.0.dist-info/METADATA +221 -0
  148. sqlbenchdag-0.1.0.dist-info/RECORD +153 -0
  149. sqlbenchdag-0.1.0.dist-info/WHEEL +5 -0
  150. sqlbenchdag-0.1.0.dist-info/entry_points.txt +2 -0
  151. sqlbenchdag-0.1.0.dist-info/licenses/LICENSE +202 -0
  152. sqlbenchdag-0.1.0.dist-info/top_level.txt +4 -0
  153. venv/bin/activate_this.py +59 -0
@@ -0,0 +1,15 @@
1
+ -- analytical_wall.sql (Actian)
2
+ SELECT
3
+ region,
4
+ category,
5
+ COUNT(*) as transaction_count,
6
+ ROUND(CAST(SUM(price * quantity * (1 - discount)) AS numeric), 2) as net_revenue,
7
+ ROUND(CAST(AVG(price * quantity * (1 - discount)) AS numeric), 2) as avg_transaction_value,
8
+ ROUND(CAST(SUM(CASE WHEN discount > 0.15 THEN price * quantity ELSE 0 END) / SUM(price * quantity + 0.00001) * 100 AS numeric), 2) as high_discount_impact_pct
9
+ FROM
10
+ {{ analytical_data_table }}
11
+ GROUP BY
12
+ region,
13
+ category
14
+ ORDER BY
15
+ net_revenue DESC;
@@ -0,0 +1,19 @@
1
+ -- analytical_wall.sql
2
+ -- Goal: Demonstrate Actian's X100 Vectorized Engine vs. Postgres Row-based Execution.
3
+ -- Scenario: Calculating Weighted Net Revenue Across Regions and Categories for 10M+ rows.
4
+
5
+ SELECT
6
+ region,
7
+ category,
8
+ COUNT(*) as transaction_count,
9
+ ROUND(SUM(price * quantity * (1 - discount)), 2) as net_revenue,
10
+ ROUND(AVG(price * quantity * (1 - discount)), 2) as avg_transaction_value,
11
+ -- Complex aggregation that forces per-row math
12
+ ROUND(SUM(CASE WHEN discount > 0.15 THEN price * quantity ELSE 0 END) / SUM(price * quantity + 0.00001) * 100, 2) as high_discount_impact_pct
13
+ FROM
14
+ analytical_data
15
+ GROUP BY
16
+ region,
17
+ category
18
+ ORDER BY
19
+ net_revenue DESC;
@@ -0,0 +1,15 @@
1
+ -- analytical_wall.sql (DuckDB)
2
+ SELECT
3
+ region,
4
+ category,
5
+ COUNT(*) as transaction_count,
6
+ ROUND(SUM(price * quantity * (1 - discount)), 2) as net_revenue,
7
+ ROUND(AVG(price * quantity * (1 - discount)), 2) as avg_transaction_value,
8
+ ROUND(SUM(CASE WHEN discount > 0.15 THEN price * quantity ELSE 0 END) / SUM(price * quantity + 0.00001) * 100, 2) as high_discount_impact_pct
9
+ FROM
10
+ {{ analytical_data_table }}
11
+ GROUP BY
12
+ region,
13
+ category
14
+ ORDER BY
15
+ net_revenue DESC;
@@ -0,0 +1,15 @@
1
+ -- analytical_wall.sql (Postgres)
2
+ SELECT
3
+ region,
4
+ category,
5
+ COUNT(*) as transaction_count,
6
+ ROUND(CAST(SUM(price * quantity * (1 - discount)) AS numeric), 2) as net_revenue,
7
+ ROUND(CAST(AVG(price * quantity * (1 - discount)) AS numeric), 2) as avg_transaction_value,
8
+ ROUND(CAST(SUM(CASE WHEN discount > 0.15 THEN price * quantity ELSE 0 END) / SUM(price * quantity + 0.00001) * 100 AS numeric), 2) as high_discount_impact_pct
9
+ FROM
10
+ {{ analytical_data_table }}
11
+ GROUP BY
12
+ region,
13
+ category
14
+ ORDER BY
15
+ net_revenue DESC;
@@ -0,0 +1,11 @@
1
+ SELECT
2
+ c.customer_id,
3
+ c.customer_name,
4
+ c.region,
5
+ SUM(o.amount) AS total_spend
6
+ FROM
7
+ {{ customers_table }} c
8
+ INNER JOIN
9
+ {{ orders_table }} o ON c.customer_id = o.customer_id
10
+ GROUP BY
11
+ c.customer_id, c.customer_name, c.region; -- The anti-pattern
@@ -0,0 +1,19 @@
1
+ -- The Recommended CTE Pattern: Aggregate the large table first, then join.
2
+ WITH CustomerSpend AS (
3
+ SELECT
4
+ customer_id,
5
+ SUM(amount) AS total_customer_spend
6
+ FROM
7
+ {{ orders_table }}
8
+ GROUP BY
9
+ customer_id
10
+ )
11
+ SELECT
12
+ c.customer_id,
13
+ c.customer_name,
14
+ c.region,
15
+ cs.total_customer_spend
16
+ FROM
17
+ {{ customers_table }} c
18
+ INNER JOIN
19
+ CustomerSpend cs ON c.customer_id = cs.customer_id;
@@ -0,0 +1,13 @@
1
+ -- groupby_anti_pattern.sql
2
+ SELECT
3
+ c.customer_id,
4
+ c.customer_name,
5
+ c.region,
6
+ SUM(o.amount) AS total_amount
7
+ FROM
8
+ {{ customers_table }} c
9
+ INNER JOIN
10
+ {{ orders_table }} o ON c.customer_id = o.customer_id
11
+ GROUP BY
12
+ c.customer_id, c.customer_name, c.region;
13
+
@@ -0,0 +1,11 @@
1
+ SELECT
2
+ c.customer_id,
3
+ c.customer_name,
4
+ c.region,
5
+ SUM(o.amount) AS total_amount
6
+ FROM
7
+ {{ customers_table }} c
8
+ JOIN
9
+ {{ orders_table }} o ON c.customer_id = o.customer_id
10
+ GROUP BY
11
+ c.customer_id; -- Postgres infers name/region from PK
@@ -0,0 +1,5 @@
1
+ SELECT DISTINCT b.id, b.name, b.region
2
+ FROM {{ supply_contract_table }} sc
3
+ JOIN {{ supplier_table }} s ON s.id = sc.supplier_id
4
+ JOIN {{ buyer_table }} b ON b.id = sc.buyer_id
5
+ WHERE s.country = 'US';
@@ -0,0 +1,6 @@
1
+ SELECT DISTINCT p.id, p.name, p.category
2
+ FROM {{ supply_contract_table }} sc
3
+ JOIN {{ supplier_table }} s ON s.id = sc.supplier_id
4
+ JOIN {{ product_table }} p ON p.id = sc.product_id
5
+ WHERE s.country = 'EU'
6
+ AND p.category = 'electronics';
@@ -0,0 +1,9 @@
1
+ SELECT s.id AS supplier_id, s.country,
2
+ b.id AS buyer_id, b.region,
3
+ p.id AS product_id, p.category
4
+ FROM {{ supply_contract_table }} sc
5
+ JOIN {{ supplier_table }} s ON s.id = sc.supplier_id
6
+ JOIN {{ buyer_table }} b ON b.id = sc.buyer_id
7
+ JOIN {{ product_table }} p ON p.id = sc.product_id
8
+ WHERE s.country = 'US'
9
+ AND b.region = 'APAC';
@@ -0,0 +1,4 @@
1
+ match
2
+ $s isa {{ supplier_table }}, has country "US";
3
+ $sc (supplier_role: $s, buyer_role: $b) isa {{ supply_contract_table }};
4
+ select $b;
@@ -0,0 +1,5 @@
1
+ match
2
+ $s isa {{ supplier_table }}, has country "EU";
3
+ $sc (supplier_role: $s, product_role: $p) isa {{ supply_contract_table }};
4
+ $p isa {{ product_table }}, has category "electronics";
5
+ select $p;
@@ -0,0 +1,6 @@
1
+ match
2
+ $sc (supplier_role: $s, buyer_role: $b, product_role: $p) isa {{ supply_contract_table }};
3
+ $s isa {{ supplier_table }}, has country "US";
4
+ $b isa {{ buyer_table }}, has region "APAC";
5
+ $p isa {{ product_table }};
6
+ select $s, $b, $p;
@@ -0,0 +1,5 @@
1
+ -- This query uses a Left Join and filters NULLs, which is slower than Inner Join
2
+ SELECT count(*)
3
+ FROM {{ orders_table }} o
4
+ LEFT JOIN {{ customers_table }} c ON o.customer_id = c.customer_id
5
+ WHERE c.customer_id IS NOT NULL;
@@ -0,0 +1,4 @@
1
+ -- This query uses a standard Inner Join
2
+ SELECT count(*)
3
+ FROM {{ orders_table }} o
4
+ JOIN {{ customers_table }} c ON o.customer_id = c.customer_id;
@@ -0,0 +1,5 @@
1
+ -- This query uses a Left Join and filters NULLs, which is slower than Inner Join
2
+ SELECT count(*)
3
+ FROM {{ orders_table }} o
4
+ LEFT JOIN {{ customers_table }} c ON o.customer_id = c.customer_id
5
+ WHERE c.customer_id IS NOT NULL;
@@ -0,0 +1,4 @@
1
+ -- This query uses a standard Inner Join
2
+ SELECT count(*)
3
+ FROM {{ orders_table }} o
4
+ JOIN {{ customers_table }} c ON o.customer_id = c.customer_id;
@@ -0,0 +1,14 @@
1
+ -- 1. Matches for Non-Nulls (Uses Hash Join)
2
+ SELECT count(*)
3
+ FROM {{ r_table }} r1
4
+ JOIN {{ r_table }} r2
5
+ ON r1.{{ join_key_a }} = r2.{{ join_key_a }}
6
+
7
+ UNION ALL
8
+
9
+ -- 2. Matches for Nulls (Identity)
10
+ -- This is just a cartesian of nulls, but isolated so it doesn't kill the Hash Join
11
+ SELECT count(*)
12
+ FROM {{ r_table }} r1
13
+ JOIN {{ r_table }} r2
14
+ ON r1.{{ join_key_a }} IS NULL AND r2.{{ join_key_a }} IS NULL;
@@ -0,0 +1,5 @@
1
+ -- 3VL TEST (Standard Identity Loss)
2
+ SELECT count(*)
3
+ FROM {{ r_table }} r1
4
+ JOIN {{ r_table }} r2
5
+ ON r1.{{ join_key_a }} = r2.{{ join_key_a }};
@@ -0,0 +1,14 @@
1
+ -- 1. Matches for Non-Nulls (Uses Hash Join)
2
+ SELECT count(*)
3
+ FROM {{ r_table }} r1
4
+ JOIN {{ r_table }} r2
5
+ ON r1.{{ join_key_a }} = r2.{{ join_key_a }}
6
+
7
+ UNION ALL
8
+
9
+ -- 2. Matches for Nulls (Identity)
10
+ -- This is just a cartesian of nulls, but isolated so it doesn't kill the Hash Join
11
+ SELECT count(*)
12
+ FROM {{ r_table }} r1
13
+ JOIN {{ r_table }} r2
14
+ ON r1.{{ join_key_a }} IS NULL AND r2.{{ join_key_a }} IS NULL;
@@ -0,0 +1,5 @@
1
+ -- 3VL TEST (Standard Identity Loss)
2
+ SELECT count(*)
3
+ FROM {{ r_table }} r1
4
+ JOIN {{ r_table }} r2
5
+ ON r1.{{ join_key_a }} = r2.{{ join_key_a }};
@@ -0,0 +1,14 @@
1
+ -- 1. Matches for Non-Nulls (Uses Hash Join)
2
+ SELECT count(*)
3
+ FROM {{ r_table }} r1
4
+ JOIN {{ r_table }} r2
5
+ ON r1.{{ join_key_a }} = r2.{{ join_key_a }}
6
+
7
+ UNION ALL
8
+
9
+ -- 2. Matches for Nulls (Identity)
10
+ -- This is just a cartesian of nulls, but isolated so it doesn't kill the Hash Join
11
+ SELECT count(*)
12
+ FROM {{ r_table }} r1
13
+ JOIN {{ r_table }} r2
14
+ ON r1.{{ join_key_a }} IS NULL AND r2.{{ join_key_a }} IS NULL;
@@ -0,0 +1,5 @@
1
+ -- 3VL TEST (Standard Identity Loss)
2
+ SELECT count(*)
3
+ FROM {{ r_table }} r1
4
+ JOIN {{ r_table }} r2
5
+ ON r1.{{ join_key_a }} = r2.{{ join_key_a }};
@@ -0,0 +1,16 @@
1
+ -- Benchmarks the cost of handling NULLs as a concrete value ("Identity")
2
+ -- vs letting the database skip them (Standard 3VL).
3
+ DROP TABLE IF EXISTS {{ r_table }}_sentinel;
4
+
5
+ CREATE TABLE {{ r_table }}_sentinel AS
6
+ SELECT
7
+ COALESCE({{ join_key_a }}, -1) AS {{ join_key_a }}
8
+ FROM {{ r_table }};
9
+
10
+ ANALYZE {{ r_table }}_sentinel;
11
+
12
+ SELECT count(*)
13
+ FROM {{ r_table }}_sentinel r1
14
+ JOIN {{ r_table }}_sentinel r2
15
+ ON r1.{{ join_key_a }} = r2.{{ join_key_a }};
16
+
@@ -0,0 +1,14 @@
1
+ -- 1. Matches for Non-Nulls (Uses Hash Join)
2
+ SELECT count(*)
3
+ FROM {{ r_table }} r1
4
+ JOIN {{ r_table }} r2
5
+ ON r1.{{ join_key_a }} = r2.{{ join_key_a }}
6
+
7
+ UNION ALL
8
+
9
+ -- 2. Matches for Nulls (Identity)
10
+ -- This is just a cartesian of nulls, but isolated so it doesn't kill the Hash Join
11
+ SELECT count(*)
12
+ FROM {{ r_table }} r1
13
+ JOIN {{ r_table }} r2
14
+ ON r1.{{ join_key_a }} IS NULL AND r2.{{ join_key_a }} IS NULL;
@@ -0,0 +1,5 @@
1
+ -- 3VL TEST (Standard Identity Loss)
2
+ SELECT count(*)
3
+ FROM {{ r_table }} r1
4
+ JOIN {{ r_table }} r2
5
+ ON r1.{{ join_key_a }} = r2.{{ join_key_a }};
@@ -0,0 +1,21 @@
1
+ -- Benchmarks the cost of handling NULLs as a concrete value ("Identity")
2
+ -- vs letting the database skip them (Standard 3VL).
3
+ -- [PREP_START]
4
+ DROP TABLE IF EXISTS {{ r_table }}_sentinel;
5
+
6
+ -- 1. Physical Materialization (The "Baking" Phase)
7
+ CREATE UNLOGGED TABLE {{ r_table }}_sentinel AS
8
+ SELECT
9
+ COALESCE({{ join_key_a }}, -1) AS {{ join_key_a }}
10
+ FROM {{ r_table }};
11
+
12
+ -- 2. Statistic Update (The "Notification" Phase)
13
+ ANALYZE {{ r_table }}_sentinel;
14
+ -- [PREP_END]
15
+
16
+ -- 3. The Benchmark
17
+ SELECT count(*)
18
+ FROM {{ r_table }}_sentinel r1
19
+ JOIN {{ r_table }}_sentinel r2
20
+ ON r1.{{ join_key_a }} = r2.{{ join_key_a }};
21
+
@@ -0,0 +1,26 @@
1
+ WITH RECURSIVE
2
+ -- {{ hierarchy_table }} will be rendered as `hierarchy_partitionkey` (e.g., hierarchy_small)
3
+ descendants (id, parent_id, name, depth) AS (
4
+ SELECT
5
+ id,
6
+ parent_id,
7
+ name,
8
+ 1 AS depth
9
+ FROM {{ hierarchy_data_table }}
10
+ WHERE id = 1 -- Start at a known root/branch node
11
+
12
+ UNION ALL
13
+
14
+ SELECT
15
+ t.id,
16
+ t.parent_id,
17
+ t.name,
18
+ d.depth + 1
19
+ FROM {{ hierarchy_data_table }} AS t
20
+ INNER JOIN descendants AS d
21
+ ON t.parent_id = d.id
22
+ )
23
+ SELECT
24
+ -- The final result is the count of all descendant nodes found
25
+ count(*)
26
+ FROM descendants;
@@ -0,0 +1,30 @@
1
+ -- sql_queries/postgres/recursion_cte.sql
2
+ -- Recursively finds all descendants (or ancestors) of a specific node.
3
+ -- We use node ID 1 as a common starting point.
4
+
5
+ WITH RECURSIVE
6
+ -- {{ hierarchy_table }} will be rendered as `hierarchy_partitionkey`
7
+ descendants (id, parent_id, name, depth) AS (
8
+ SELECT
9
+ id,
10
+ parent_id,
11
+ name,
12
+ 1 AS depth
13
+ FROM {{ hierarchy_data_table }} AS t
14
+ WHERE id = 1 -- Start at a known root/branch node
15
+
16
+ UNION ALL
17
+
18
+ SELECT
19
+ t.id,
20
+ t.parent_id,
21
+ t.name,
22
+ d.depth + 1
23
+ FROM {{ hierarchy_data_table }} AS t
24
+ INNER JOIN descendants AS d
25
+ ON t.parent_id = d.id
26
+ )
27
+ SELECT
28
+ -- The final result is the count of all descendant nodes found
29
+ count(*)
30
+ FROM descendants;
@@ -0,0 +1,17 @@
1
+ -- Bounded variable-depth: all companies reachable from node 1 in up to 3 hops.
2
+ -- Recursive CTE with depth guard. Intermediate result set materialised at each
3
+ -- step — this is where OOM occurs on hub-heavy Zipf graphs.
4
+ WITH RECURSIVE reachable(company_id, depth) AS (
5
+ SELECT to_id AS company_id, 1 AS depth
6
+ FROM {{ supplies_table }}
7
+ WHERE from_id = 1
8
+
9
+ UNION
10
+
11
+ SELECT s.to_id, r.depth + 1
12
+ FROM reachable r
13
+ JOIN {{ supplies_table }} s ON s.from_id = r.company_id
14
+ WHERE r.depth < 3
15
+ )
16
+ SELECT COUNT(DISTINCT company_id) AS reachable_count
17
+ FROM reachable;
@@ -0,0 +1,6 @@
1
+ -- Fixed 2-hop: companies reachable from node 1 in exactly 2 supply steps.
2
+ -- Baseline — DuckDB should win comfortably. Two plain JOINs on integer FKs.
3
+ SELECT DISTINCT s2.to_id AS company_id
4
+ FROM {{ supplies_table }} s1
5
+ JOIN {{ supplies_table }} s2 ON s1.to_id = s2.from_id
6
+ WHERE s1.from_id = 1;
@@ -0,0 +1,17 @@
1
+ -- Full transitive closure from node 1: every company that directly or
2
+ -- indirectly depends on node 1 in the supply chain.
3
+ -- No depth limit — the CTE runs until no new nodes are discovered.
4
+ -- This is the query most likely to OOM on a Zipf hub at medium scale.
5
+ WITH RECURSIVE closure(company_id) AS (
6
+ SELECT to_id AS company_id
7
+ FROM {{ supplies_table }}
8
+ WHERE from_id = 1
9
+
10
+ UNION
11
+
12
+ SELECT s.to_id
13
+ FROM closure c
14
+ JOIN {{ supplies_table }} s ON s.from_id = c.company_id
15
+ )
16
+ SELECT COUNT(DISTINCT company_id) AS total_reachable
17
+ FROM closure;
@@ -0,0 +1,6 @@
1
+ match
2
+ $root isa {{ company_table }}, has id 1;
3
+ (seller_role: $root, buyer_role: $hop1) isa {{ supplies_table }};
4
+ (seller_role: $hop1, buyer_role: $hop2) isa {{ supplies_table }};
5
+ (seller_role: $hop2, buyer_role: $leaf) isa {{ supplies_table }};
6
+ select $hop1, $hop2, $leaf;
@@ -0,0 +1,5 @@
1
+ match
2
+ (seller_role: $a, buyer_role: $b) isa {{ supplies_table }};
3
+ (seller_role: $b, buyer_role: $c) isa {{ supplies_table }};
4
+ $a isa {{ company_table }}, has id 1;
5
+ select $c;
@@ -0,0 +1,7 @@
1
+ # Full transitive closure from node 1 using a TypeDB 3.x recursive stream function.
2
+ # The 'reachable' function is defined in the schema and evaluated lazily with tabling
3
+ # (automatic cycle detection / fixed-point termination). No explicit loop needed.
4
+ match
5
+ $root isa {{ company_table }}, has id 1;
6
+ let $reachable in reachable($root);
7
+ select $reachable;
@@ -0,0 +1 @@
1
+ SELECT COUNT(*) FROM heartbeat;
@@ -0,0 +1 @@
1
+ SELECT count(*) FROM {{ skewed_data_table }} WHERE selectivity_code = 'sel_0_1';
@@ -0,0 +1 @@
1
+ SELECT count(*) FROM {{ skewed_data_table }} WHERE selectivity_code = 'sel_10';
@@ -0,0 +1 @@
1
+ SELECT count(*) FROM {{ skewed_data_table }} WHERE selectivity_code = 'sel_1';
@@ -0,0 +1 @@
1
+ SELECT count(*) FROM {{ skewed_data_table }} WHERE selectivity_code = 'sel_20';
@@ -0,0 +1 @@
1
+ SELECT count(*) FROM {{ skewed_data_table }} WHERE selectivity_code = 'sel_5';
@@ -0,0 +1 @@
1
+ SELECT count(*) FROM {{ skewed_data_table }} WHERE selectivity_code = 'filler';
@@ -0,0 +1 @@
1
+ SELECT count(*) FROM {{ skewed_data_table }} WHERE selectivity_code = 'sel_0_1';
@@ -0,0 +1 @@
1
+ SELECT count(*) FROM {{ skewed_data_table }} WHERE selectivity_code = 'sel_10';
@@ -0,0 +1 @@
1
+ SELECT count(*) FROM {{ skewed_data_table }} WHERE selectivity_code = 'sel_1';
@@ -0,0 +1 @@
1
+ SELECT count(*) FROM {{ skewed_data_table }} WHERE selectivity_code = 'sel_20';
@@ -0,0 +1 @@
1
+ SELECT count(*) FROM {{ skewed_data_table }} WHERE selectivity_code = 'sel_5';
@@ -0,0 +1 @@
1
+ SELECT count(*) FROM {{ skewed_data_table }} WHERE selectivity_code = 'filler';
@@ -0,0 +1,4 @@
1
+ match
2
+ $x isa {{ skewed_data_table }},
3
+ has selectivity_code "sel_0_1";
4
+ select $x;
@@ -0,0 +1,4 @@
1
+ match
2
+ $x isa {{ skewed_data_table }},
3
+ has selectivity_code "sel_10";
4
+ select $x;
@@ -0,0 +1,4 @@
1
+ match
2
+ $x isa {{ skewed_data_table }},
3
+ has selectivity_code "sel_1";
4
+ select $x;
@@ -0,0 +1,4 @@
1
+ match
2
+ $x isa {{ skewed_data_table }},
3
+ has selectivity_code "sel_20";
4
+ select $x;
@@ -0,0 +1,4 @@
1
+ match
2
+ $x isa {{ skewed_data_table }},
3
+ has selectivity_code "sel_5";
4
+ select $x;
@@ -0,0 +1,4 @@
1
+ match
2
+ $x isa {{ skewed_data_table }},
3
+ has selectivity_code "filler";
4
+ select $x;
@@ -0,0 +1,25 @@
1
+ -- Sort Spill: Full sort (no LIMIT) on wide rows (DuckDB control).
2
+ -- DuckDB uses vectorized execution and adaptive memory management.
3
+ -- No work_mem equivalent — spill is handled transparently.
4
+ -- Compare against postgres/sort_full.sql: without top-N optimization,
5
+ -- the full architectural cost of row-at-a-time vs vectorized sort is exposed.
6
+
7
+ SELECT
8
+ id,
9
+ region,
10
+ category,
11
+ department,
12
+ sub_category,
13
+ ROUND(price, 4) AS price,
14
+ ROUND(cost, 4) AS cost,
15
+ ROUND(margin, 4) AS margin,
16
+ quantity,
17
+ discount,
18
+ ROUND(price * quantity * (1.0 - discount), 4) AS net_revenue
19
+ FROM {{ sort_data_table }}
20
+ ORDER BY
21
+ region ASC,
22
+ category ASC,
23
+ department ASC,
24
+ net_revenue DESC,
25
+ quantity DESC;
@@ -0,0 +1,25 @@
1
+ -- Sort Spill: Multi-column sort on wide rows (DuckDB control).
2
+ -- DuckDB manages memory adaptively — no work_mem equivalent.
3
+ -- This is the control arm: same query, no spill constraint.
4
+ -- Compare against postgres/sort_wide_rows.sql to isolate the spill cost.
5
+
6
+ SELECT
7
+ id,
8
+ region,
9
+ category,
10
+ department,
11
+ sub_category,
12
+ ROUND(price, 4) AS price,
13
+ ROUND(cost, 4) AS cost,
14
+ ROUND(margin, 4) AS margin,
15
+ quantity,
16
+ discount,
17
+ ROUND(price * quantity * (1.0 - discount), 4) AS net_revenue
18
+ FROM {{ sort_data_table }}
19
+ ORDER BY
20
+ region ASC,
21
+ category ASC,
22
+ department ASC,
23
+ net_revenue DESC,
24
+ quantity DESC
25
+ LIMIT 1000;
@@ -0,0 +1,25 @@
1
+ -- Sort Spill: Full sort (no LIMIT) on wide rows.
2
+ -- Without LIMIT, Postgres cannot use the top-N heap sort optimization.
3
+ -- The entire result set must be sorted in memory or spilled to disk.
4
+ -- At tight work_mem (4MB), spill will occur at low row counts.
5
+ -- This is where the cliff actually lives.
6
+
7
+ SELECT
8
+ id,
9
+ region,
10
+ category,
11
+ department,
12
+ sub_category,
13
+ ROUND(CAST(price AS NUMERIC), 4) AS price,
14
+ ROUND(CAST(cost AS NUMERIC), 4) AS cost,
15
+ ROUND(CAST(margin AS NUMERIC), 4) AS margin,
16
+ quantity,
17
+ discount,
18
+ ROUND(CAST(price * quantity * (1.0 - discount) AS NUMERIC), 4) AS net_revenue
19
+ FROM {{ sort_data_table }}
20
+ ORDER BY
21
+ region ASC,
22
+ category ASC,
23
+ department ASC,
24
+ net_revenue DESC,
25
+ quantity DESC;