From 072d3e09714a07f9b3e7dcddac9686995cab4356 Mon Sep 17 00:00:00 2001 From: Marcus Gartner Date: Mon, 27 Jun 2022 10:49:23 -0400 Subject: [PATCH 1/2] opt: lazily convert lookup join equality columns to lookup expr Previously, the lookup join constraint builder would immediately convert equality columns to an equality expression in the lookup expression when it was determined that a lookup expression was required to perform the lookup join. Now, this conversion happens after all the equality columns and the lookup expression have been collected. This simplifies the logic. Release note: None --- .../logic_test/regional_by_row_query_behavior | 4 +- .../opt/exec/execbuilder/testdata/lookup_join | 30 ++--- .../execbuilder/testdata/lookup_join_spans | 58 +++++----- pkg/sql/opt/lookupjoin/BUILD.bazel | 1 - pkg/sql/opt/lookupjoin/constraint_builder.go | 49 ++------- pkg/sql/opt/lookupjoin/testdata/computed | 4 +- pkg/sql/opt/lookupjoin/testdata/lookup_expr | 48 ++++---- .../opt/memo/testdata/logprops/lookup-join | 12 +- pkg/sql/opt/memo/testdata/stats/lookup-join | 4 +- pkg/sql/opt/xform/testdata/external/tpce | 20 ++-- .../opt/xform/testdata/external/tpce-no-stats | 20 ++-- pkg/sql/opt/xform/testdata/external/trading | 8 +- .../xform/testdata/external/trading-mutation | 8 +- pkg/sql/opt/xform/testdata/rules/generic | 4 +- pkg/sql/opt/xform/testdata/rules/join | 104 +++++++++--------- 15 files changed, 172 insertions(+), 202 deletions(-) diff --git a/pkg/ccl/logictestccl/testdata/logic_test/regional_by_row_query_behavior b/pkg/ccl/logictestccl/testdata/logic_test/regional_by_row_query_behavior index e19558343f50..e019bbd477f0 100644 --- a/pkg/ccl/logictestccl/testdata/logic_test/regional_by_row_query_behavior +++ b/pkg/ccl/logictestccl/testdata/logic_test/regional_by_row_query_behavior @@ -1697,7 +1697,7 @@ SELECT * FROM [EXPLAIN UPSERT INTO regional_by_row_table (crdb_region, pk, pk2, │ │ │ └── • lookup join (semi) │ │ table: regional_by_row_table@new_idx -│ │ lookup condition: ((crdb_region IN ('ap-southeast-2', 'ca-central-1', 'us-east-1')) AND (column4 = a)) AND (b > 0) +│ │ lookup condition: ((crdb_region IN ('ap-southeast-2', 'ca-central-1', 'us-east-1')) AND (b > 0)) AND (column4 = a) │ │ pred: (upsert_pk != pk) OR (column1 != crdb_region) │ │ │ └── • filter @@ -1767,7 +1767,7 @@ VALUES ('us-east-1', 23, 24, 25, 26), ('ca-central-1', 30, 30, 31, 32)] OFFSET 2 │ │ │ └── • lookup join (semi) │ │ table: regional_by_row_table@new_idx -│ │ lookup condition: ((crdb_region IN ('ap-southeast-2', 'ca-central-1', 'us-east-1')) AND (column4 = a)) AND (b > 0) +│ │ lookup condition: ((crdb_region IN ('ap-southeast-2', 'ca-central-1', 'us-east-1')) AND (b > 0)) AND (column4 = a) │ │ pred: (upsert_pk != pk) OR (column1 != crdb_region) │ │ │ └── • filter diff --git a/pkg/sql/opt/exec/execbuilder/testdata/lookup_join b/pkg/sql/opt/exec/execbuilder/testdata/lookup_join index cfff5af29020..6789f1d800e0 100644 --- a/pkg/sql/opt/exec/execbuilder/testdata/lookup_join +++ b/pkg/sql/opt/exec/execbuilder/testdata/lookup_join @@ -88,7 +88,7 @@ vectorized: true │ columns: (a, b, c, d, e, f) │ estimated row count: 33 │ table: def@def_pkey -│ lookup condition: (b = f) AND (e > 1) +│ lookup condition: (e > 1) AND (b = f) │ └── • scan columns: (a, b, c) @@ -106,7 +106,7 @@ vectorized: true │ columns: (a, b, c, d, e, f) │ estimated row count: 33 │ table: def@desc_idx -│ lookup condition: (b = f) AND (e > 1) +│ lookup condition: (e > 1) AND (b = f) │ └── • scan columns: (a, b, c) @@ -126,7 +126,7 @@ vectorized: true │ columns: (a, b, c, d, e, f) │ estimated row count: 33 │ table: def@def_pkey -│ lookup condition: (b = f) AND (e > 9223372036854775807) +│ lookup condition: (e > 9223372036854775807) AND (b = f) │ └── • scan columns: (a, b, c) @@ -146,7 +146,7 @@ vectorized: true │ columns: (a, b, c, d, e, f) │ estimated row count: 33 │ table: def_e_decimal@def_e_decimal_pkey -│ lookup condition: (b = f) AND (e > 1) +│ lookup condition: (e > 1) AND (b = f) │ └── • scan columns: (a, b, c) @@ -166,7 +166,7 @@ vectorized: true │ columns: (a, b, c, d, e, f) │ estimated row count: 33 │ table: def_e_decimal@desc_idx -│ lookup condition: (b = f) AND (e >= 1) +│ lookup condition: (e >= 1) AND (b = f) │ └── • scan columns: (a, b, c) @@ -225,7 +225,7 @@ vectorized: true │ columns: (a, b, c, d, e, f) │ estimated row count: 33 │ table: def@def_pkey -│ lookup condition: (b = f) AND (a >= e) +│ lookup condition: (a >= e) AND (b = f) │ └── • scan columns: (a, b, c) @@ -244,7 +244,7 @@ vectorized: true │ columns: (a, b, c, d, e, f) │ estimated row count: 33 │ table: def@desc_idx -│ lookup condition: (b = f) AND (a >= e) +│ lookup condition: (a >= e) AND (b = f) │ └── • scan columns: (a, b, c) @@ -263,7 +263,7 @@ vectorized: true │ columns: (a, b, c, d, e, f) │ estimated row count: 33 │ table: def@def_pkey -│ lookup condition: (b = f) AND (a > e) +│ lookup condition: (a > e) AND (b = f) │ └── • scan columns: (a, b, c) @@ -282,7 +282,7 @@ vectorized: true │ columns: (a, b, c, d, e, f) │ estimated row count: 33 │ table: def@desc_idx -│ lookup condition: (b = f) AND (a > e) +│ lookup condition: (a > e) AND (b = f) │ └── • scan columns: (a, b, c) @@ -304,7 +304,7 @@ vectorized: true │ columns: (column11, a, b, c, d, e, f) │ estimated row count: 33 │ table: def_e_decimal@def_e_decimal_pkey - │ lookup condition: (b = f) AND (column11 >= e) + │ lookup condition: (column11 >= e) AND (b = f) │ └── • render │ columns: (column11, a, b, c) @@ -333,7 +333,7 @@ vectorized: true │ columns: (column11, a, b, c, d, e, f) │ estimated row count: 33 │ table: def_e_decimal@desc_idx - │ lookup condition: (b = f) AND (column11 >= e) + │ lookup condition: (column11 >= e) AND (b = f) │ └── • render │ columns: (column11, a, b, c) @@ -2186,14 +2186,14 @@ vectorized: true · • lookup join (left outer) │ table: lookup_expr@lookup_expr_r_x_y_z_w_idx -│ lookup condition: ((((r IN ('east', 'west')) AND (column2 = x)) AND (y IN (10, 20))) AND ("lookup_join_const_col_@8" = z)) AND (column1 = w) +│ lookup condition: ((((r IN ('east', 'west')) AND (y IN (10, 20))) AND (column2 = x)) AND ("lookup_join_const_col_@8" = z)) AND (column1 = w) │ └── • render │ └── • values size: 2 columns, 3 rows · -Diagram: https://cockroachdb.github.io/distsqlplan/decode.html#eJyUUm1P20AM_r5fYfkLyWSgaXk9Cek6WqagkLImoElTFUWNgYw01-UuawD1v0-XQlemDbH7cPLjl8fWYz-h_lGgwOHXy6Dvh-AM_CiOvgQuRMNgeBrDRzgbjy7Aue4HV8MIHI_A67gETpeg2xo9gvAqCFwX-hHU4CwIGheC4VkM5yM_hEKp-3qecDOvbIaBUQhOvbOAEzA7Cxf64cDipsWNi4SlyjhMZ6xRfEMPJ4TzSk1Za1VZ11Ob4GcNig5hXs5rY90TwqmqGMUTmtwUjAKv06JmvdtBwoxNmhcrRg8-gdOD6V1d3mvbcMxlxpWAfSGEH8ZHBNIjkF2cLAlVbX530Ca95bbveiR_gKKzpPdPda7ycsxpxtWu93qy-GHOYiXd6CoejlsBkXBDQrlhJ1XSJA_JY7JI8qxBwqCNwXeVl6BKAY7jOHIP7F63ONVmSwgRxWM__EywteBNh_u8CNmDE5CHa3jUVnudtTLdF9Nd53i25HgNuxYeWF1PVVHPSi2gIvhJYC-D4IHgEQlHtREguyR7JPdI7pM8IHlI8ojk8T919_7Q3fsf3ces56rU_Erz925421tOCDm75dUJalVXU76s1LTNXcFRS9Q6MtZmFfVWwC9fQtpUnM7WZ7PJ5L3J1H2LaUJ4Uyh7CSiw8_y2__K9PLQF6a22EkV3atHS2gvUKG7SQjPhRXrPAzZczfIy1yafojBVzcvlh18BAAD__1_7Qi8= +Diagram: https://cockroachdb.github.io/distsqlplan/decode.html#eJyUUu9P20AM_b6_wvIXkslA0_LzJKTraJmCQsqagCZNVRQ1BjLSXJe7rAHU_326FLoybYjdh8jPdp6t5_eE-keBAodfL4O-H4Iz8KM4-hK4EA2D4WkMH-FsPLoA57ofXA0jcDwCr-MSOF2Cbhv0CMKrIHBd6EdQg7MgaFwIhmcxnI_8EAql7ut5ws28sh0GRiE49c4CTsDsLFzohwOLmxY3LhKWKuMwnbFG8Q09nBDOKzVlrVVlU09tg581KDqEeTmvjU1PCKeqYhRPaHJTMAq8Toua9W4HCTM2aV6sGD34BE4Ppnd1ea_twDGXGVcC9oUQfhgfEUiPQHZxsiRUtfk9QZv0ltu565X8AYrOkt6_1bnKyzGnGVe73uvN4oc5i5V0o6t4OG4FRMINCeVGnFRJkzwkj8kiybMGCYO2Bt9VXoIqBTiO48g9sHfd4lSbLSFEFI_98DPB1oI3E-7zIeRR2-511lJ0X0J33dODE5CHa-hZeLyGXQsPrK6nqqhnpRZQEfwksM4geCB4RMJRbQTILskeyT2S-yQPSB6SPCJ5_E_dvT909_5H9zHruSo1v9L8vRfe9pYTQs5ueWVBrepqypeVmra9KzhqidpExtqsqt4K-OVLSZuK09naNptM3ptM3beYJoQ3hbJOQIGd57f9l8_LQ_tDequtRNGdWrS01oEaxU1aaCa8SO95wIarWV7m2uRTFKaqebn88CsAAP__a61CLw== query T EXPLAIN (DISTSQL) SELECT * FROM (VALUES (1, 10), (2, 20), (3, NULL)) AS u(w, x) WHERE NOT EXISTS ( @@ -2205,14 +2205,14 @@ vectorized: true · • lookup join (anti) │ table: lookup_expr@lookup_expr_r_x_y_z_w_idx -│ lookup condition: ((((r IN ('east', 'west')) AND (column2 = x)) AND (y IN (10, 20))) AND ("lookup_join_const_col_@8" = z)) AND (column1 = w) +│ lookup condition: ((((r IN ('east', 'west')) AND (y IN (10, 20))) AND (column2 = x)) AND ("lookup_join_const_col_@8" = z)) AND (column1 = w) │ └── • render │ └── • values size: 2 columns, 3 rows · -Diagram: https://cockroachdb.github.io/distsqlplan/decode.html#eJyUUt1O20wQvf-eYjQ32J8WyDqlRSshOSWmNTIOjQ1FqiLLigdwcbzp7loxoLx7tQ64oWoR3YvVnPk5Mzozj6h_VCgwuDqPRmEMzjhM0uRL5EISRMFxCv_DyXRyBs7lKLoIEnA4Az5wGTgeA68zhgziiyhyXRgl0ICzYtC68PVzMA0gnqQQXFlKcF4SVlLeNcuM2qWydeapwGn2VnAEZm_lwigeW9x2uHVdZFjLguJ8QRrFN-Q4Y7hUck5aS2Vdj11CWLQoBgzLetkY654xnEtFKB7RlKYiFHiZVw3p_QEyLMjkZbVh5PARnCHMb5v6TtuGU6oLUgIOhBBhnB4y8DkD38PZmqFszK8O2uQ31PXtRwrHKAZr9vapTmVZTykvSO3zl5Ol90sSEAUnKYziNITTSRgjwy0V_S07U1mb3WcP2SorixYZRl0MvsuyBlkLcBzH8d-BXfgO5drsCCGSdBrGnxjsrGjb4T4twh_CEfjve_ihq-aDXhjv2XT7HG5LDnvoWXhgZT2WVbOotQDFwN4Lg3sGD8hw0hgBvsf84V8V5r8pzP9F4Snppaw1vVD3rbvc5esZQypuaHNsWjZqTudKzrvcDZx0RJ2jIG02Ub4BYf0c0kZRvugPZJuJv8rkvcY0Y3hdSbt0FDh4ert_-J4f2oL8RluJklu56mjtrWkU13mlieFZfkdjMqQWZV1qU85RGNXQev3fzwAAAP__T4ND9Q== +Diagram: https://cockroachdb.github.io/distsqlplan/decode.html#eJyUUt1O20wQvf-eYjQ32J8WyDqlRSshOSWmNTIOjQ1FqiLLigdwcbzp7loxoLx7tQ64oWoR3YvVnPk5Mzozj6h_VCgwuDqPRmEMzjhM0uRL5EISRMFxCv_DyXRyBs7lKLoIEnA4Az5wGTgeA68zhgziiyhyXRgl0ICzYtC68PVzMA0gnqQQXFlKcF4SVlLeNcuM2qWydeapwGn2VnAEZm_lwigeW9x2uHVdZFjLguJ8QRrFN-Q4Y7hUck5aS2Vdj11CWLQoBgzLetkY654xnEtFKB7RlKYiFHiZVw3p_QEyLMjkZbVh5PARnCHMb5v6TtuGU6oLUgIOhBBhnB4y8DkD38PZmqFszK8O2uQ31PXtRwrHKAZr9vapTmVZTykvSO3zl5Ol90sSEAUnKYziNITTSRgjwy0V_S07U1mb3WcP2SorixYZRl0MvsuyBlkLcBzH8d-BXfgO5drsCCGSdBrGnxjsrGjb4T4twv_QpfNBr4T3bLp9zhCOwH_fQ27hYQ89Cw-srMeyaha1FqAY2HthcM_gARlOGiPA95g__KvC_DeF-b8oPCW9lLWmF-q-dZe7fD1jSMUNbY5Ny0bN6VzJeZe7gZOOqHMUpM0myjcgrJ9D2ijKF_2BbDPxV5m815hmDK8raZeOAgdPb_cP3_NDW5DfaCtRcitXHa29NY3iOq80MTzL72hMhtSirEttyjkKoxpar__7GQAA__9bSkP1 # The following tests check that if the joiners can separate a row request # into separate families that it does, and generates spans for each family diff --git a/pkg/sql/opt/exec/execbuilder/testdata/lookup_join_spans b/pkg/sql/opt/exec/execbuilder/testdata/lookup_join_spans index 921c7b0a962f..3ed3807a0a59 100644 --- a/pkg/sql/opt/exec/execbuilder/testdata/lookup_join_spans +++ b/pkg/sql/opt/exec/execbuilder/testdata/lookup_join_spans @@ -125,7 +125,7 @@ vectorized: true └── • lookup join │ estimated row count: 33 │ table: metric_values@metric_values_pkey - │ lookup condition: (id = metric_id) AND ("time" > '2020-01-01 00:00:00+00') + │ lookup condition: ("time" > '2020-01-01 00:00:00+00') AND (id = metric_id) │ └── • index join │ estimated row count: 1 @@ -155,7 +155,7 @@ vectorized: true │ └── • lookup join │ table: metric_values_desc@metric_values_desc_pkey - │ lookup condition: (id = metric_id) AND ("time" > '2020-01-01 00:00:00+00') + │ lookup condition: ("time" > '2020-01-01 00:00:00+00') AND (id = metric_id) │ └── • index join │ estimated row count: 1 @@ -187,7 +187,7 @@ vectorized: true └── • lookup join │ estimated row count: 33 │ table: metric_values@metric_values_pkey - │ lookup condition: (id = metric_id) AND ("time" >= '2020-01-01 00:00:00+00') + │ lookup condition: ("time" >= '2020-01-01 00:00:00+00') AND (id = metric_id) │ └── • index join │ estimated row count: 1 @@ -217,7 +217,7 @@ vectorized: true │ └── • lookup join │ table: metric_values_desc@metric_values_desc_pkey - │ lookup condition: (id = metric_id) AND ("time" >= '2020-01-01 00:00:00+00') + │ lookup condition: ("time" >= '2020-01-01 00:00:00+00') AND (id = metric_id) │ └── • index join │ estimated row count: 1 @@ -244,7 +244,7 @@ vectorized: true • lookup join │ estimated row count: 33 │ table: metric_values@metric_values_pkey -│ lookup condition: (id = metric_id) AND ("time" < '2020-01-01 00:00:00+00') +│ lookup condition: ("time" < '2020-01-01 00:00:00+00') AND (id = metric_id) │ └── • index join │ estimated row count: 1 @@ -270,7 +270,7 @@ vectorized: true · • lookup join │ table: metric_values_desc@metric_values_desc_pkey -│ lookup condition: (id = metric_id) AND ("time" < '2020-01-01 00:00:00+00') +│ lookup condition: ("time" < '2020-01-01 00:00:00+00') AND (id = metric_id) │ └── • index join │ estimated row count: 1 @@ -302,7 +302,7 @@ vectorized: true └── • lookup join │ estimated row count: 33 │ table: metric_values@metric_values_pkey - │ lookup condition: (id = metric_id) AND ("time" <= '2020-01-01 00:00:00+00') + │ lookup condition: ("time" <= '2020-01-01 00:00:00+00') AND (id = metric_id) │ └── • index join │ estimated row count: 1 @@ -332,7 +332,7 @@ vectorized: true │ └── • lookup join │ table: metric_values_desc@metric_values_desc_pkey - │ lookup condition: (id = metric_id) AND ("time" <= '2020-01-01 00:00:00+00') + │ lookup condition: ("time" <= '2020-01-01 00:00:00+00') AND (id = metric_id) │ └── • index join │ estimated row count: 1 @@ -364,7 +364,7 @@ vectorized: true └── • lookup join │ estimated row count: 33 │ table: metric_values@metric_values_pkey - │ lookup condition: (id = metric_id) AND ("time" < '2020-01-01 00:00:10+00') + │ lookup condition: ("time" < '2020-01-01 00:00:10+00') AND (id = metric_id) │ └── • index join │ estimated row count: 1 @@ -394,7 +394,7 @@ vectorized: true │ └── • lookup join │ table: metric_values_desc@metric_values_desc_pkey - │ lookup condition: (id = metric_id) AND ("time" < '2020-01-01 00:00:10+00') + │ lookup condition: ("time" < '2020-01-01 00:00:10+00') AND (id = metric_id) │ └── • index join │ estimated row count: 1 @@ -426,7 +426,7 @@ vectorized: true └── • lookup join │ estimated row count: 11 │ table: metric_values@metric_values_pkey - │ lookup condition: (id = metric_id) AND (("time" >= '2020-01-01 00:00:00+00') AND ("time" <= '2020-01-01 00:10:00+00')) + │ lookup condition: (("time" >= '2020-01-01 00:00:00+00') AND ("time" <= '2020-01-01 00:10:00+00')) AND (id = metric_id) │ └── • index join │ estimated row count: 1 @@ -456,7 +456,7 @@ vectorized: true │ └── • lookup join │ table: metric_values_desc@metric_values_desc_pkey - │ lookup condition: (id = metric_id) AND (("time" >= '2020-01-01 00:00:00+00') AND ("time" <= '2020-01-01 00:10:00+00')) + │ lookup condition: (("time" >= '2020-01-01 00:00:00+00') AND ("time" <= '2020-01-01 00:10:00+00')) AND (id = metric_id) │ └── • index join │ estimated row count: 1 @@ -488,7 +488,7 @@ vectorized: true └── • lookup join (left outer) │ estimated row count: 11 │ table: metric_values@metric_values_pkey - │ lookup condition: (id = metric_id) AND (("time" >= '2020-01-01 00:00:00+00') AND ("time" <= '2020-01-01 00:10:00+00')) + │ lookup condition: (("time" >= '2020-01-01 00:00:00+00') AND ("time" <= '2020-01-01 00:10:00+00')) AND (id = metric_id) │ pred: name = 'cpu' │ └── • scan @@ -510,7 +510,7 @@ vectorized: true • lookup join (semi) │ estimated row count: 10 │ table: metric_values@metric_values_pkey -│ lookup condition: (id = metric_id) AND (("time" >= '2020-01-01 00:00:00+00') AND ("time" <= '2020-01-01 00:10:00+00')) +│ lookup condition: (("time" >= '2020-01-01 00:00:00+00') AND ("time" <= '2020-01-01 00:10:00+00')) AND (id = metric_id) │ └── • scan estimated row count: 10 (100% of the table; stats collected ago) @@ -546,7 +546,7 @@ vectorized: true └── • lookup join │ estimated row count: 3 │ table: metric_values@secondary - │ lookup condition: ((id = metric_id) AND (nullable = nullable)) AND ("time" > '2020-01-01 00:00:00+00') + │ lookup condition: (("time" > '2020-01-01 00:00:00+00') AND (id = metric_id)) AND (nullable = nullable) │ └── • index join │ estimated row count: 1 @@ -591,7 +591,7 @@ vectorized: true └── • lookup join │ estimated row count: 0 │ table: metric_values@secondary - │ lookup condition: (id = metric_id) AND ((nullable >= -20) AND (nullable <= -10)) + │ lookup condition: ((nullable >= -20) AND (nullable <= -10)) AND (id = metric_id) │ └── • scan estimated row count: 1 (10% of the table; stats collected ago) @@ -632,7 +632,7 @@ vectorized: true └── • lookup join │ estimated row count: 0 │ table: metric_values@secondary - │ lookup condition: (id = metric_id) AND (nullable > 1) + │ lookup condition: (nullable > 1) AND (id = metric_id) │ └── • scan estimated row count: 1 (10% of the table; stats collected ago) @@ -673,7 +673,7 @@ vectorized: true └── • lookup join │ estimated row count: 0 │ table: metric_values@secondary - │ lookup condition: (id = metric_id) AND (nullable >= 1) + │ lookup condition: (nullable >= 1) AND (id = metric_id) │ └── • scan estimated row count: 1 (10% of the table; stats collected ago) @@ -715,7 +715,7 @@ vectorized: true └── • lookup join │ estimated row count: 0 │ table: metric_values@secondary - │ lookup condition: (id = metric_id) AND (nullable < -10) + │ lookup condition: (nullable < -10) AND (id = metric_id) │ └── • scan estimated row count: 1 (10% of the table; stats collected ago) @@ -756,7 +756,7 @@ vectorized: true └── • lookup join │ estimated row count: 0 │ table: metric_values@secondary - │ lookup condition: (id = metric_id) AND (nullable <= -10) + │ lookup condition: (nullable <= -10) AND (id = metric_id) │ └── • scan estimated row count: 1 (10% of the table; stats collected ago) @@ -792,7 +792,7 @@ vectorized: true └── • lookup join │ estimated row count: 3 │ table: metric_values@secondary - │ lookup condition: ((id = metric_id) AND (nullable = nullable)) AND ("time" < '2020-01-01 00:00:10+00') + │ lookup condition: (("time" < '2020-01-01 00:00:10+00') AND (id = metric_id)) AND (nullable = nullable) │ └── • index join │ estimated row count: 1 @@ -839,7 +839,7 @@ vectorized: true └── • lookup join │ estimated row count: 0 │ table: metric_values@secondary - │ lookup condition: ((id = metric_id) AND ("lookup_join_const_col_@3" = nullable)) AND ("time" < '2020-01-01 00:00:10+00') + │ lookup condition: (("time" < '2020-01-01 00:00:10+00') AND (id = metric_id)) AND ("lookup_join_const_col_@3" = nullable) │ └── • render │ @@ -876,7 +876,7 @@ vectorized: true └── • lookup join │ estimated row count: 33 │ table: metric_values@secondary - │ lookup condition: ((id = metric_id) AND (nullable <= nullable)) AND (nullable >= -20) + │ lookup condition: ((nullable <= nullable) AND (nullable >= -20)) AND (id = metric_id) │ └── • index join │ estimated row count: 1 @@ -915,7 +915,7 @@ vectorized: true └── • lookup join │ estimated row count: 33 │ table: metric_values@secondary - │ lookup condition: (id = metric_id) AND (nullable > nullable) + │ lookup condition: (nullable > nullable) AND (id = metric_id) │ └── • index join │ estimated row count: 1 @@ -954,7 +954,7 @@ vectorized: true └── • lookup join │ estimated row count: 33 │ table: metric_values@secondary - │ lookup condition: (id = metric_id) AND (nullable >= nullable) + │ lookup condition: (nullable >= nullable) AND (id = metric_id) │ └── • index join │ estimated row count: 1 @@ -994,7 +994,7 @@ vectorized: true └── • lookup join │ estimated row count: 33 │ table: metric_values@secondary - │ lookup condition: (id = metric_id) AND (nullable < nullable) + │ lookup condition: (nullable < nullable) AND (id = metric_id) │ └── • index join │ estimated row count: 1 @@ -1033,7 +1033,7 @@ vectorized: true └── • lookup join │ estimated row count: 33 │ table: metric_values@secondary - │ lookup condition: (id = metric_id) AND (nullable <= nullable) + │ lookup condition: (nullable <= nullable) AND (id = metric_id) │ └── • index join │ estimated row count: 1 @@ -1086,7 +1086,7 @@ vectorized: true │ columns: (s_i_id, ol_o_id, ol_i_id) │ estimated row count: 7,939 (missing stats) │ table: order_line@ol_io - │ lookup condition: (s_i_id = ol_i_id) AND ((ol_o_id >= 20) AND (ol_o_id <= 100)) + │ lookup condition: ((ol_o_id >= 20) AND (ol_o_id <= 100)) AND (s_i_id = ol_i_id) │ └── • scan columns: (s_i_id) @@ -1114,7 +1114,7 @@ vectorized: true │ columns: (s_i_id, ol_o_id, ol_i_id) │ estimated row count: 196 (missing stats) │ table: order_line@ol_io - │ lookup condition: (s_i_id = ol_i_id) AND (ol_o_id IN (20, 21)) + │ lookup condition: (ol_o_id IN (20, 21)) AND (s_i_id = ol_i_id) │ └── • scan columns: (s_i_id) diff --git a/pkg/sql/opt/lookupjoin/BUILD.bazel b/pkg/sql/opt/lookupjoin/BUILD.bazel index 898a10186c30..4734399b201f 100644 --- a/pkg/sql/opt/lookupjoin/BUILD.bazel +++ b/pkg/sql/opt/lookupjoin/BUILD.bazel @@ -19,7 +19,6 @@ go_library( "//pkg/sql/sem/tree", "//pkg/sql/types", "//pkg/util/intsets", - "@com_github_cockroachdb_errors//:errors", ], ) diff --git a/pkg/sql/opt/lookupjoin/constraint_builder.go b/pkg/sql/opt/lookupjoin/constraint_builder.go index 0adb716bbdb5..5c4c8fcd70cb 100644 --- a/pkg/sql/opt/lookupjoin/constraint_builder.go +++ b/pkg/sql/opt/lookupjoin/constraint_builder.go @@ -18,7 +18,6 @@ import ( "github.com/cockroachdb/cockroach/pkg/sql/sem/eval" "github.com/cockroachdb/cockroach/pkg/sql/types" "github.com/cockroachdb/cockroach/pkg/util/intsets" - "github.com/cockroachdb/errors" ) // Constraint is used to constrain a lookup join. There are two types of @@ -230,41 +229,15 @@ func (b *ConstraintBuilder) Build( var allLookupFilters memo.FiltersExpr var filterOrdsToExclude intsets.Fast foundLookupCols := false - lookupExprRequired := false var remainingFilters memo.FiltersExpr - // addEqualityColumns adds the given columns as an equality in keyCols if - // lookupExprRequired is false. Otherwise, the equality is added as an - // expression in lookupExpr. In both cases, rightCol is added to - // rightSideCols so the caller of Build can determine if the right equality - // columns form a key. + // addEqualityColumns adds the given columns as an equality in keyCols and + // rightSideCols. addEqualityColumns := func(leftCol, rightCol opt.ColumnID) { - if !lookupExprRequired { - keyCols = append(keyCols, leftCol) - } else { - lookupExpr = append(lookupExpr, b.constructColEquality(leftCol, rightCol)) - } + keyCols = append(keyCols, leftCol) rightSideCols = append(rightSideCols, rightCol) } - // convertToLookupExpr converts previously collected keyCols and - // rightSideCols to equality expressions in lookupExpr. It is used when it - // is discovered that a lookup expression is required to build a constraint, - // and keyCols and rightSideCols have already been collected. After building - // expressions, keyCols is reset to nil. - convertToLookupExpr := func() { - if lookupExprRequired { - // Return early if we've already converted the key columns to a - // lookup expression. - return - } - lookupExprRequired = true - for i := range keyCols { - lookupExpr = append(lookupExpr, b.constructColEquality(keyCols[i], rightSideCols[i])) - } - keyCols = nil - } - // All the lookup conditions must apply to the prefix of the index and so // the projected columns created must be created in order. for j := 0; j < numIndexKeyCols; j++ { @@ -335,10 +308,6 @@ func (b *ConstraintBuilder) Build( // If multiple constant values were found, we must use a lookup // expression. if ok { - // Convert previously collected keyCols and rightSideCols to - // expressions in lookupExpr and clear keyCols. - convertToLookupExpr() - valsFilter := b.allFilters[allIdx] if !isCanonicalFilter(valsFilter) { // Disable normalization rules when constructing the lookup @@ -360,14 +329,12 @@ func (b *ConstraintBuilder) Build( rightCmp, inequalityFilterOrds, b.allFilters, idxCol, idxColIsDesc, ) if foundStart { - convertToLookupExpr() lookupExpr = append(lookupExpr, b.allFilters[startIdx]) allLookupFilters = append(allLookupFilters, b.allFilters[startIdx]) filterOrdsToExclude.Add(startIdx) foundLookupCols = true } if foundEnd { - convertToLookupExpr() lookupExpr = append(lookupExpr, b.allFilters[endIdx]) allLookupFilters = append(allLookupFilters, b.allFilters[endIdx]) filterOrdsToExclude.Add(endIdx) @@ -389,7 +356,6 @@ func (b *ConstraintBuilder) Build( ) if rangeFilter != nil { // A constant range filter could be found. - convertToLookupExpr() lookupExpr = append(lookupExpr, *rangeFilter) allLookupFilters = append(allLookupFilters, b.allFilters[filterIdx]) filterOrdsToExclude.Add(filterIdx) @@ -411,8 +377,13 @@ func (b *ConstraintBuilder) Build( return Constraint{}, false } - if len(keyCols) > 0 && len(lookupExpr) > 0 { - panic(errors.AssertionFailedf("expected lookup constraint to have either KeyCols or LookupExpr, not both")) + // If a lookup expression is required, convert the equality columns to + // equalities in the lookup expression. + if len(lookupExpr) > 0 { + for i := range keyCols { + lookupExpr = append(lookupExpr, b.constructColEquality(keyCols[i], rightSideCols[i])) + } + keyCols = nil } c := Constraint{ diff --git a/pkg/sql/opt/lookupjoin/testdata/computed b/pkg/sql/opt/lookupjoin/testdata/computed index a874886a6a20..b8d1f840c2a2 100644 --- a/pkg/sql/opt/lookupjoin/testdata/computed +++ b/pkg/sql/opt/lookupjoin/testdata/computed @@ -111,7 +111,7 @@ x = a AND y IN (1, 2) input projections: v_eq = a + 10 lookup expression: - ((v_eq = v) AND (a = x)) AND (y IN (1, 2)) + ((y IN (1, 2)) AND (v_eq = v)) AND (a = x) lookup-constraints left=(a int, b int) right=(x int, y int, v int not null as (x + 10) virtual) index=(v, x, y) x = a AND y > 0 @@ -119,4 +119,4 @@ x = a AND y > 0 input projections: v_eq = a + 10 lookup expression: - ((v_eq = v) AND (a = x)) AND (y > 0) + ((y > 0) AND (v_eq = v)) AND (a = x) diff --git a/pkg/sql/opt/lookupjoin/testdata/lookup_expr b/pkg/sql/opt/lookupjoin/testdata/lookup_expr index 3d6bd3193aab..6426bd1f090c 100644 --- a/pkg/sql/opt/lookupjoin/testdata/lookup_expr +++ b/pkg/sql/opt/lookupjoin/testdata/lookup_expr @@ -59,13 +59,13 @@ lookup-constraints left=(a int, b int, c int) right=(x int, y int, z int) index= x IN (1, 2, 3) AND y = b AND z IN (4, 5, 6) ---- lookup expression: - ((x IN (1, 2, 3)) AND (b = y)) AND (z IN (4, 5, 6)) + ((x IN (1, 2, 3)) AND (z IN (4, 5, 6))) AND (b = y) lookup-constraints left=(a int, b int, c int) right=(x int, y int, z int) index=(x, y, z) x IN (1, 2, 3) AND y = b AND z IN (4, 5, 6) ---- lookup expression: - ((x IN (1, 2, 3)) AND (b = y)) AND (z IN (4, 5, 6)) + ((x IN (1, 2, 3)) AND (z IN (4, 5, 6))) AND (b = y) lookup-constraints left=(a int, b int) right=(x int, y int) index=(x, y) y = b @@ -79,14 +79,14 @@ x = a optional: y IN (1, 2, 3) ---- lookup expression: - (a = x) AND (y IN (1, 2, 3)) + (y IN (1, 2, 3)) AND (a = x) lookup-constraints left=(a int, b int) right=(x int, y int, z int) index=(x, y) x = a AND z = 1 optional: y IN (1, 2, 3) ---- lookup expression: - (a = x) AND (y IN (1, 2, 3)) + (y IN (1, 2, 3)) AND (a = x) remaining filters: z = 1 @@ -95,7 +95,7 @@ x = a optional: y IN (1, 2, 3) AND z = 1 ---- lookup expression: - (a = x) AND (y IN (1, 2, 3)) + (y IN (1, 2, 3)) AND (a = x) lookup-constraints left=(a int, b int, c int) right=(x int, y int, z int) index=(x, y, z) x = 1 AND z = c @@ -104,7 +104,7 @@ optional: y IN (3, 4) input projections: lookup_join_const_col_@7 = 1 lookup expression: - ((lookup_join_const_col_@7 = x) AND (y IN (3, 4))) AND (c = z) + ((y IN (3, 4)) AND (lookup_join_const_col_@7 = x)) AND (c = z) lookup-constraints left=(a int, b int, c int) right=(x int, y int, z int) index=(x, y, z) z = c @@ -118,7 +118,7 @@ y = b optional: x IN (1, 2) AND z IN (3, 4) ---- lookup expression: - ((x IN (1, 2)) AND (b = y)) AND (z IN (3, 4)) + ((x IN (1, 2)) AND (z IN (3, 4))) AND (b = y) # TODO(#75596): The lookup expression should not contain (z IN (3, 4)) because # it is an optional filter from a CHECK constraint. It will only increase the @@ -131,7 +131,7 @@ optional: z IN (3, 4) input projections: lookup_join_const_col_@7 = 1 lookup expression: - ((lookup_join_const_col_@7 = x) AND (b = y)) AND (z IN (3, 4)) + ((z IN (3, 4)) AND (lookup_join_const_col_@7 = x)) AND (b = y) # The most restrictive IN filter should be chosen. lookup-constraints left=(a int, b int) right=(x int, y int) index=(x, y) @@ -157,7 +157,7 @@ x = a AND y = false AND z > 0 input projections: lookup_join_const_col_@6 = false lookup expression: - ((a = x) AND (lookup_join_const_col_@6 = y)) AND (z > 0) + ((z > 0) AND (a = x)) AND (lookup_join_const_col_@6 = y) # Test for range filters. @@ -166,13 +166,13 @@ lookup-constraints left=(a int, b int) right=(x int, y int) index=(x, y) x = a AND y > 0 ---- lookup expression: - (a = x) AND (y > 0) + (y > 0) AND (a = x) lookup-constraints left=(a int, b int) right=(x int, y int) index=(x desc, y desc) x = a AND y > 0 ---- lookup expression: - (a = x) AND (y > 0) + (y > 0) AND (a = x) lookup-constraints left=(a int, b int) right=(x int, y int) index=(x, y) x > 0 @@ -189,13 +189,13 @@ x = a optional: y > 0 ---- lookup expression: - (a = x) AND (y > 0) + (y > 0) AND (a = x) lookup-constraints left=(a int, b int, c int) right=(x int, y int, z int) index=(x, y, z) x = a AND y = b AND z > 0 ---- lookup expression: - ((a = x) AND (b = y)) AND (z > 0) + ((z > 0) AND (a = x)) AND (b = y) lookup-constraints left=(a int, b int, c int) right=(x int, y int, z int) index=(x, y, z) x = 1 AND y = b AND z > 0 @@ -203,7 +203,7 @@ x = 1 AND y = b AND z > 0 input projections: lookup_join_const_col_@7 = 1 lookup expression: - ((lookup_join_const_col_@7 = x) AND (b = y)) AND (z > 0) + ((z > 0) AND (lookup_join_const_col_@7 = x)) AND (b = y) lookup-constraints left=(a int, b int, c int) right=(x int, y int, z int) index=(x, y, z) x = a AND y = 1 AND z > 0 @@ -211,7 +211,7 @@ x = a AND y = 1 AND z > 0 input projections: lookup_join_const_col_@8 = 1 lookup expression: - ((a = x) AND (lookup_join_const_col_@8 = y)) AND (z > 0) + ((z > 0) AND (a = x)) AND (lookup_join_const_col_@8 = y) lookup-constraints left=(a int, b int, c int) right=(x int, y int, z int) index=(x, y, z) x = 1 AND y = b @@ -220,14 +220,14 @@ optional: z > 0 input projections: lookup_join_const_col_@7 = 1 lookup expression: - ((lookup_join_const_col_@7 = x) AND (b = y)) AND (z > 0) + ((z > 0) AND (lookup_join_const_col_@7 = x)) AND (b = y) lookup-constraints left=(a int, b int, c int) right=(x int, y int, z int) index=(x, y) x = a AND z = 1 optional: y > 0 ---- lookup expression: - (a = x) AND (y > 0) + (y > 0) AND (a = x) remaining filters: z = 1 @@ -236,7 +236,7 @@ x = a optional: y > 0 AND z = 1 ---- lookup expression: - (a = x) AND (y > 0) + (y > 0) AND (a = x) # Test for range filters and IN filters. @@ -245,7 +245,7 @@ lookup-constraints left=(a int, b int, c int) right=(x int, y int, z int) index= x IN (1, 2) AND y = b AND z > 0 ---- lookup expression: - ((x IN (1, 2)) AND (b = y)) AND (z > 0) + ((x IN (1, 2)) AND (z > 0)) AND (b = y) lookup-constraints left=(a int, b int, c int) right=(x int, y int, z int) index=(x, y, z) x IN (1, 2) AND y > 0 AND z = c @@ -257,7 +257,7 @@ y = b AND z > 0 optional: x IN (1, 2) ---- lookup expression: - ((x IN (1, 2)) AND (b = y)) AND (z > 0) + ((x IN (1, 2)) AND (z > 0)) AND (b = y) lookup-constraints left=(a int, b int, c int) right=(x int, y int, z int) index=(x, y) y = b AND z > 0 @@ -311,25 +311,25 @@ lookup-constraints left=(a int, b int) right=(x int, y int) index=(x, y) x = a AND y > b ---- lookup expression: - (a = x) AND (y > b) + (y > b) AND (a = x) lookup-constraints left=(a int, b int) right=(x int, y int) index=(x, y) x = a AND y >= b ---- lookup expression: - (a = x) AND (y >= b) + (y >= b) AND (a = x) lookup-constraints left=(a int, b int) right=(x int, y int) index=(x, y) x = a AND y < b ---- lookup expression: - (a = x) AND (y < b) + (y < b) AND (a = x) lookup-constraints left=(a int, b int) right=(x int, y int) index=(x, y) x = a AND y <= b ---- lookup expression: - (a = x) AND (y <= b) + (y <= b) AND (a = x) lookup-constraints left=(a int, b int) right=(x int, y int) index=(x desc, y) x > a diff --git a/pkg/sql/opt/memo/testdata/logprops/lookup-join b/pkg/sql/opt/memo/testdata/logprops/lookup-join index b5a3e0d2e7e6..923b7051cdac 100644 --- a/pkg/sql/opt/memo/testdata/logprops/lookup-join +++ b/pkg/sql/opt/memo/testdata/logprops/lookup-join @@ -87,12 +87,12 @@ inner-join (lookup abcd) │ ├── columns: m:1(int!null) n:2(int) a:6(int!null) b:7(int!null) abcd.rowid:9(int!null) │ ├── lookup expression │ │ └── filters - │ │ ├── eq [type=bool, outer=(1,6), constraints=(/1: (/NULL - ]; /6: (/NULL - ]), fd=(1)==(6), (6)==(1)] - │ │ │ ├── variable: m:1 [type=int] - │ │ │ └── variable: a:6 [type=int] - │ │ └── gt [type=bool, outer=(7), constraints=(/7: [/3 - ]; tight)] - │ │ ├── variable: b:7 [type=int] - │ │ └── const: 2 [type=int] + │ │ ├── gt [type=bool, outer=(7), constraints=(/7: [/3 - ]; tight)] + │ │ │ ├── variable: b:7 [type=int] + │ │ │ └── const: 2 [type=int] + │ │ └── eq [type=bool, outer=(1,6), constraints=(/1: (/NULL - ]; /6: (/NULL - ]), fd=(1)==(6), (6)==(1)] + │ │ ├── variable: m:1 [type=int] + │ │ └── variable: a:6 [type=int] │ ├── fd: (9)-->(6,7), (1)==(6), (6)==(1) │ ├── scan small │ │ ├── columns: m:1(int) n:2(int) diff --git a/pkg/sql/opt/memo/testdata/stats/lookup-join b/pkg/sql/opt/memo/testdata/stats/lookup-join index 5d2b4781690c..a20594af5b8d 100644 --- a/pkg/sql/opt/memo/testdata/stats/lookup-join +++ b/pkg/sql/opt/memo/testdata/stats/lookup-join @@ -84,8 +84,8 @@ inner-join (lookup abcd) │ ├── columns: m:1(int!null) n:2(int) a:6(int!null) b:7(int!null) abcd.rowid:9(int!null) │ ├── lookup expression │ │ └── filters - │ │ ├── m:1 = a:6 [type=bool, outer=(1,6), constraints=(/1: (/NULL - ]; /6: (/NULL - ]), fd=(1)==(6), (6)==(1)] - │ │ └── b:7 > 2 [type=bool, outer=(7), constraints=(/7: [/3 - ]; tight)] + │ │ ├── b:7 > 2 [type=bool, outer=(7), constraints=(/7: [/3 - ]; tight)] + │ │ └── m:1 = a:6 [type=bool, outer=(1,6), constraints=(/1: (/NULL - ]; /6: (/NULL - ]), fd=(1)==(6), (6)==(1)] │ ├── stats: [rows=33, distinct(1)=10, null(1)=0, distinct(6)=10, null(6)=0, distinct(7)=33, null(7)=0] │ ├── fd: (9)-->(6,7), (1)==(6), (6)==(1) │ ├── scan small diff --git a/pkg/sql/opt/xform/testdata/external/tpce b/pkg/sql/opt/xform/testdata/external/tpce index 8a669c7544df..fbfcde4e913b 100644 --- a/pkg/sql/opt/xform/testdata/external/tpce +++ b/pkg/sql/opt/xform/testdata/external/tpce @@ -1036,8 +1036,8 @@ project │ │ │ │ │ │ │ │ ├── columns: in_id:1!null in_name:2!null co_id:6!null co_in_id:9!null │ │ │ │ │ │ │ │ ├── lookup expression │ │ │ │ │ │ │ │ │ └── filters - │ │ │ │ │ │ │ │ │ ├── in_id:1 = co_in_id:9 [outer=(1,9), constraints=(/1: (/NULL - ]; /9: (/NULL - ]), fd=(1)==(9), (9)==(1)] - │ │ │ │ │ │ │ │ │ └── (co_id:6 >= 1) AND (co_id:6 <= 5000) [outer=(6), constraints=(/6: [/1 - /5000]; tight)] + │ │ │ │ │ │ │ │ │ ├── (co_id:6 >= 1) AND (co_id:6 <= 5000) [outer=(6), constraints=(/6: [/1 - /5000]; tight)] + │ │ │ │ │ │ │ │ │ └── in_id:1 = co_in_id:9 [outer=(1,9), constraints=(/1: (/NULL - ]; /9: (/NULL - ]), fd=(1)==(9), (9)==(1)] │ │ │ │ │ │ │ │ ├── cardinality: [0 - 5000] │ │ │ │ │ │ │ │ ├── key: (6) │ │ │ │ │ │ │ │ ├── fd: ()-->(1,2,9), (1)==(9), (9)==(1) @@ -1137,8 +1137,8 @@ project │ │ │ │ │ │ │ │ ├── flags: force lookup join (into right side) │ │ │ │ │ │ │ │ ├── lookup expression │ │ │ │ │ │ │ │ │ └── filters - │ │ │ │ │ │ │ │ │ ├── in_id:1 = co_in_id:9 [outer=(1,9), constraints=(/1: (/NULL - ]; /9: (/NULL - ]), fd=(1)==(9), (9)==(1)] - │ │ │ │ │ │ │ │ │ └── (co_id:6 >= 1) AND (co_id:6 <= 5000) [outer=(6), constraints=(/6: [/1 - /5000]; tight)] + │ │ │ │ │ │ │ │ │ ├── (co_id:6 >= 1) AND (co_id:6 <= 5000) [outer=(6), constraints=(/6: [/1 - /5000]; tight)] + │ │ │ │ │ │ │ │ │ └── in_id:1 = co_in_id:9 [outer=(1,9), constraints=(/1: (/NULL - ]; /9: (/NULL - ]), fd=(1)==(9), (9)==(1)] │ │ │ │ │ │ │ │ ├── cardinality: [0 - 5000] │ │ │ │ │ │ │ │ ├── key: (6) │ │ │ │ │ │ │ │ ├── fd: ()-->(1,2,9), (1)==(9), (9)==(1) @@ -4116,10 +4116,10 @@ project │ │ ├── flags: force lookup join (into right side) │ │ ├── lookup expression │ │ │ └── filters + │ │ │ ├── cr_from_qty:48 <= 100 [outer=(48), constraints=(/48: (/NULL - /100]; tight)] │ │ │ ├── c_tier:8 = cr_c_tier:45 [outer=(8,45), constraints=(/8: (/NULL - ]; /45: (/NULL - ]), fd=(8)==(45), (45)==(8)] │ │ │ ├── "lookup_join_const_col_@46":54 = cr_tt_id:46 [outer=(46,54), constraints=(/46: (/NULL - ]; /54: (/NULL - ]), fd=(46)==(54), (54)==(46)] - │ │ │ ├── s_ex_id:31 = cr_ex_id:47 [outer=(31,47), constraints=(/31: (/NULL - ]; /47: (/NULL - ]), fd=(31)==(47), (47)==(31)] - │ │ │ └── cr_from_qty:48 <= 100 [outer=(48), constraints=(/48: (/NULL - /100]; tight)] + │ │ │ └── s_ex_id:31 = cr_ex_id:47 [outer=(31,47), constraints=(/31: (/NULL - ]; /47: (/NULL - ]), fd=(31)==(47), (47)==(31)] │ │ ├── key: (48) │ │ ├── fd: ()-->(1,8,27,30,31,45-47), (48)-->(49,50), (8)==(45), (45)==(8), (31)==(47), (47)==(31) │ │ ├── limit hint: 1.00 @@ -5394,8 +5394,8 @@ project │ │ │ │ ├── columns: t_id:1!null t_dts:2!null t_tt_id:4!null t_is_cash:5!null t_s_symb:6!null t_qty:7!null t_ca_id:9!null t_exec_name:10!null trade.t_trade_price:11 s_symb:24!null s_name:27!null │ │ │ │ ├── lookup expression │ │ │ │ │ └── filters - │ │ │ │ │ ├── s_symb:24 = t_s_symb:6 [outer=(6,24), constraints=(/6: (/NULL - ]; /24: (/NULL - ]), fd=(6)==(24), (24)==(6)] - │ │ │ │ │ └── (t_dts:2 >= '2020-06-15 22:27:42.148484') AND (t_dts:2 <= '2020-06-20 22:27:42.148484') [outer=(2), constraints=(/2: [/'2020-06-15 22:27:42.148484' - /'2020-06-20 22:27:42.148484']; tight)] + │ │ │ │ │ ├── (t_dts:2 >= '2020-06-15 22:27:42.148484') AND (t_dts:2 <= '2020-06-20 22:27:42.148484') [outer=(2), constraints=(/2: [/'2020-06-15 22:27:42.148484' - /'2020-06-20 22:27:42.148484']; tight)] + │ │ │ │ │ └── s_symb:24 = t_s_symb:6 [outer=(6,24), constraints=(/6: (/NULL - ]; /24: (/NULL - ]), fd=(6)==(24), (24)==(6)] │ │ │ │ ├── key: (1) │ │ │ │ ├── fd: ()-->(6,24,27), (1)-->(2,4,5,7,9-11), (6)==(24), (24)==(6) │ │ │ │ ├── scan security @@ -6121,8 +6121,8 @@ limit │ │ ├── columns: wi_wl_id:19!null wi_s_symb:20!null wl_id:23!null wl_c_id:24!null │ │ ├── lookup expression │ │ │ └── filters - │ │ │ ├── wl_id:23 = wi_wl_id:19 [outer=(19,23), constraints=(/19: (/NULL - ]; /23: (/NULL - ]), fd=(19)==(23), (23)==(19)] - │ │ │ └── wi_s_symb:20 > 'GOOG' [outer=(20), constraints=(/20: [/e'GOOG\x00' - ]; tight)] + │ │ │ ├── wi_s_symb:20 > 'GOOG' [outer=(20), constraints=(/20: [/e'GOOG\x00' - ]; tight)] + │ │ │ └── wl_id:23 = wi_wl_id:19 [outer=(19,23), constraints=(/19: (/NULL - ]; /23: (/NULL - ]), fd=(19)==(23), (23)==(19)] │ │ ├── key: (20,23) │ │ ├── fd: ()-->(24), (19)==(23), (23)==(19) │ │ ├── scan watch_list@watch_list_wl_c_id_idx diff --git a/pkg/sql/opt/xform/testdata/external/tpce-no-stats b/pkg/sql/opt/xform/testdata/external/tpce-no-stats index 313029363601..f74dd7fda6d0 100644 --- a/pkg/sql/opt/xform/testdata/external/tpce-no-stats +++ b/pkg/sql/opt/xform/testdata/external/tpce-no-stats @@ -1045,8 +1045,8 @@ project │ │ │ │ │ │ ├── columns: in_id:1!null in_name:2!null co_id:6!null co_in_id:9!null │ │ │ │ │ │ ├── lookup expression │ │ │ │ │ │ │ └── filters - │ │ │ │ │ │ │ ├── in_id:1 = co_in_id:9 [outer=(1,9), constraints=(/1: (/NULL - ]; /9: (/NULL - ]), fd=(1)==(9), (9)==(1)] - │ │ │ │ │ │ │ └── (co_id:6 >= 1) AND (co_id:6 <= 5000) [outer=(6), constraints=(/6: [/1 - /5000]; tight)] + │ │ │ │ │ │ │ ├── (co_id:6 >= 1) AND (co_id:6 <= 5000) [outer=(6), constraints=(/6: [/1 - /5000]; tight)] + │ │ │ │ │ │ │ └── in_id:1 = co_in_id:9 [outer=(1,9), constraints=(/1: (/NULL - ]; /9: (/NULL - ]), fd=(1)==(9), (9)==(1)] │ │ │ │ │ │ ├── cardinality: [0 - 5000] │ │ │ │ │ │ ├── key: (6) │ │ │ │ │ │ ├── fd: ()-->(1,2,9), (1)==(9), (9)==(1) @@ -1163,8 +1163,8 @@ project │ │ │ │ │ │ │ │ ├── flags: force lookup join (into right side) │ │ │ │ │ │ │ │ ├── lookup expression │ │ │ │ │ │ │ │ │ └── filters - │ │ │ │ │ │ │ │ │ ├── in_id:1 = co_in_id:9 [outer=(1,9), constraints=(/1: (/NULL - ]; /9: (/NULL - ]), fd=(1)==(9), (9)==(1)] - │ │ │ │ │ │ │ │ │ └── (co_id:6 >= 1) AND (co_id:6 <= 5000) [outer=(6), constraints=(/6: [/1 - /5000]; tight)] + │ │ │ │ │ │ │ │ │ ├── (co_id:6 >= 1) AND (co_id:6 <= 5000) [outer=(6), constraints=(/6: [/1 - /5000]; tight)] + │ │ │ │ │ │ │ │ │ └── in_id:1 = co_in_id:9 [outer=(1,9), constraints=(/1: (/NULL - ]; /9: (/NULL - ]), fd=(1)==(9), (9)==(1)] │ │ │ │ │ │ │ │ ├── cardinality: [0 - 5000] │ │ │ │ │ │ │ │ ├── key: (6) │ │ │ │ │ │ │ │ ├── fd: ()-->(1,2,9), (1)==(9), (9)==(1) @@ -4146,10 +4146,10 @@ project │ │ ├── flags: force lookup join (into right side) │ │ ├── lookup expression │ │ │ └── filters + │ │ │ ├── cr_from_qty:48 <= 100 [outer=(48), constraints=(/48: (/NULL - /100]; tight)] │ │ │ ├── c_tier:8 = cr_c_tier:45 [outer=(8,45), constraints=(/8: (/NULL - ]; /45: (/NULL - ]), fd=(8)==(45), (45)==(8)] │ │ │ ├── "lookup_join_const_col_@46":54 = cr_tt_id:46 [outer=(46,54), constraints=(/46: (/NULL - ]; /54: (/NULL - ]), fd=(46)==(54), (54)==(46)] - │ │ │ ├── s_ex_id:31 = cr_ex_id:47 [outer=(31,47), constraints=(/31: (/NULL - ]; /47: (/NULL - ]), fd=(31)==(47), (47)==(31)] - │ │ │ └── cr_from_qty:48 <= 100 [outer=(48), constraints=(/48: (/NULL - /100]; tight)] + │ │ │ └── s_ex_id:31 = cr_ex_id:47 [outer=(31,47), constraints=(/31: (/NULL - ]; /47: (/NULL - ]), fd=(31)==(47), (47)==(31)] │ │ ├── key: (48) │ │ ├── fd: ()-->(1,8,27,30,31,45-47), (48)-->(49,50), (8)==(45), (45)==(8), (31)==(47), (47)==(31) │ │ ├── limit hint: 1.00 @@ -5414,8 +5414,8 @@ project │ │ │ │ │ ├── columns: t_id:1!null t_dts:2!null t_tt_id:4!null t_is_cash:5!null t_s_symb:6!null t_qty:7!null t_ca_id:9!null t_exec_name:10!null trade.t_trade_price:11 s_symb:24!null s_name:27!null │ │ │ │ │ ├── lookup expression │ │ │ │ │ │ └── filters - │ │ │ │ │ │ ├── s_symb:24 = t_s_symb:6 [outer=(6,24), constraints=(/6: (/NULL - ]; /24: (/NULL - ]), fd=(6)==(24), (24)==(6)] - │ │ │ │ │ │ └── (t_dts:2 >= '2020-06-15 22:27:42.148484') AND (t_dts:2 <= '2020-06-20 22:27:42.148484') [outer=(2), constraints=(/2: [/'2020-06-15 22:27:42.148484' - /'2020-06-20 22:27:42.148484']; tight)] + │ │ │ │ │ │ ├── (t_dts:2 >= '2020-06-15 22:27:42.148484') AND (t_dts:2 <= '2020-06-20 22:27:42.148484') [outer=(2), constraints=(/2: [/'2020-06-15 22:27:42.148484' - /'2020-06-20 22:27:42.148484']; tight)] + │ │ │ │ │ │ └── s_symb:24 = t_s_symb:6 [outer=(6,24), constraints=(/6: (/NULL - ]; /24: (/NULL - ]), fd=(6)==(24), (24)==(6)] │ │ │ │ │ ├── key: (1) │ │ │ │ │ ├── fd: ()-->(6,24,27), (1)-->(2,4,5,7,9-11), (6)==(24), (24)==(6) │ │ │ │ │ ├── ordering: +2 opt(6,24,27) [actual: +2] @@ -6138,8 +6138,8 @@ limit │ │ ├── columns: wi_wl_id:19!null wi_s_symb:20!null wl_id:23!null wl_c_id:24!null │ │ ├── lookup expression │ │ │ └── filters - │ │ │ ├── wl_id:23 = wi_wl_id:19 [outer=(19,23), constraints=(/19: (/NULL - ]; /23: (/NULL - ]), fd=(19)==(23), (23)==(19)] - │ │ │ └── wi_s_symb:20 > 'GOOG' [outer=(20), constraints=(/20: [/e'GOOG\x00' - ]; tight)] + │ │ │ ├── wi_s_symb:20 > 'GOOG' [outer=(20), constraints=(/20: [/e'GOOG\x00' - ]; tight)] + │ │ │ └── wl_id:23 = wi_wl_id:19 [outer=(19,23), constraints=(/19: (/NULL - ]; /23: (/NULL - ]), fd=(19)==(23), (23)==(19)] │ │ ├── key: (20,23) │ │ ├── fd: ()-->(24), (19)==(23), (23)==(19) │ │ ├── scan watch_list@watch_list_wl_c_id_idx diff --git a/pkg/sql/opt/xform/testdata/external/trading b/pkg/sql/opt/xform/testdata/external/trading index 10d98297ae0c..0aa6e8b988b4 100644 --- a/pkg/sql/opt/xform/testdata/external/trading +++ b/pkg/sql/opt/xform/testdata/external/trading @@ -825,10 +825,10 @@ project │ │ │ ├── columns: id:1!null name:2!null rarity:3 setname:4 number:5!null isfoil:6!null cardsinfo.dealerid:9!null cardsinfo.cardid:10!null cardsinfo.buyprice:11!null cardsinfo.sellprice:12!null discount:13!null desiredinventory:14!null actualinventory:15!null maxinventory:16!null cardsinfo.version:17!null transactiondetails.dealerid:20 isbuy:21 transactiondate:22 transactiondetails.cardid:23 quantity:24 │ │ │ ├── lookup expression │ │ │ │ └── filters + │ │ │ │ ├── (transactiondate:22 >= '2020-02-28 00:00:00+00') AND (transactiondate:22 <= '2020-03-01 00:00:00+00') [outer=(22), constraints=(/22: [/'2020-02-28 00:00:00+00' - /'2020-03-01 00:00:00+00']; tight)] │ │ │ │ ├── "lookup_join_const_col_@20":38 = transactiondetails.dealerid:20 [outer=(20,38), constraints=(/20: (/NULL - ]; /38: (/NULL - ]), fd=(20)==(38), (38)==(20)] │ │ │ │ ├── "lookup_join_const_col_@21":39 = isbuy:21 [outer=(21,39), constraints=(/21: (/NULL - ]; /39: (/NULL - ]), fd=(21)==(39), (39)==(21)] - │ │ │ │ ├── id:1 = transactiondetails.cardid:23 [outer=(1,23), constraints=(/1: (/NULL - ]; /23: (/NULL - ]), fd=(1)==(23), (23)==(1)] - │ │ │ │ └── (transactiondate:22 >= '2020-02-28 00:00:00+00') AND (transactiondate:22 <= '2020-03-01 00:00:00+00') [outer=(22), constraints=(/22: [/'2020-02-28 00:00:00+00' - /'2020-03-01 00:00:00+00']; tight)] + │ │ │ │ └── id:1 = transactiondetails.cardid:23 [outer=(1,23), constraints=(/1: (/NULL - ]; /23: (/NULL - ]), fd=(1)==(23), (23)==(1)] │ │ │ ├── immutable │ │ │ ├── stats: [rows=519622.1, distinct(10)=19000, null(10)=0, distinct(23)=19000, null(23)=0, distinct(2,4,5,10)=29618.5, null(2,4,5,10)=0] │ │ │ ├── key: (10,22-24) @@ -1103,8 +1103,8 @@ top-k │ │ ├── lookup expression │ │ │ └── filters │ │ │ ├── dealerid:8 IN (1, 2, 3, 4, 5) [outer=(8), constraints=(/8: [/1 - /1] [/2 - /2] [/3 - /3] [/4 - /4] [/5 - /5]; tight)] - │ │ │ ├── id:6 = cardid:9 [outer=(6,9), constraints=(/6: (/NULL - ]; /9: (/NULL - ]), fd=(6)==(9), (9)==(6)] - │ │ │ └── accountname:10 IN ('account-1', 'account-2', 'account-3') [outer=(10), constraints=(/10: [/'account-1' - /'account-1'] [/'account-2' - /'account-2'] [/'account-3' - /'account-3']; tight)] + │ │ │ ├── accountname:10 IN ('account-1', 'account-2', 'account-3') [outer=(10), constraints=(/10: [/'account-1' - /'account-1'] [/'account-2' - /'account-2'] [/'account-3' - /'account-3']; tight)] + │ │ │ └── id:6 = cardid:9 [outer=(6,9), constraints=(/6: (/NULL - ]; /9: (/NULL - ]), fd=(6)==(9), (9)==(6)] │ │ ├── fd: (8-10)-->(11), (6)==(9), (9)==(6) │ │ ├── values │ │ │ ├── columns: id:6!null quantity:7!null diff --git a/pkg/sql/opt/xform/testdata/external/trading-mutation b/pkg/sql/opt/xform/testdata/external/trading-mutation index 09cae22f069f..69f545f232ee 100644 --- a/pkg/sql/opt/xform/testdata/external/trading-mutation +++ b/pkg/sql/opt/xform/testdata/external/trading-mutation @@ -829,10 +829,10 @@ project │ │ │ ├── columns: id:1!null name:2!null rarity:3 setname:4 number:5!null isfoil:6!null cardsinfo.dealerid:9!null cardsinfo.cardid:10!null cardsinfo.buyprice:11!null cardsinfo.sellprice:12!null cardsinfo.discount:13!null desiredinventory:14!null actualinventory:15!null maxinventory:16!null cardsinfo.version:17!null transactiondetails.dealerid:24 isbuy:25 transactiondate:26 transactiondetails.cardid:27 quantity:28 │ │ │ ├── lookup expression │ │ │ │ └── filters + │ │ │ │ ├── (transactiondate:26 >= '2020-02-28 00:00:00+00') AND (transactiondate:26 <= '2020-03-01 00:00:00+00') [outer=(26), constraints=(/26: [/'2020-02-28 00:00:00+00' - /'2020-03-01 00:00:00+00']; tight)] │ │ │ │ ├── "lookup_join_const_col_@24":44 = transactiondetails.dealerid:24 [outer=(24,44), constraints=(/24: (/NULL - ]; /44: (/NULL - ]), fd=(24)==(44), (44)==(24)] │ │ │ │ ├── "lookup_join_const_col_@25":45 = isbuy:25 [outer=(25,45), constraints=(/25: (/NULL - ]; /45: (/NULL - ]), fd=(25)==(45), (45)==(25)] - │ │ │ │ ├── id:1 = transactiondetails.cardid:27 [outer=(1,27), constraints=(/1: (/NULL - ]; /27: (/NULL - ]), fd=(1)==(27), (27)==(1)] - │ │ │ │ └── (transactiondate:26 >= '2020-02-28 00:00:00+00') AND (transactiondate:26 <= '2020-03-01 00:00:00+00') [outer=(26), constraints=(/26: [/'2020-02-28 00:00:00+00' - /'2020-03-01 00:00:00+00']; tight)] + │ │ │ │ └── id:1 = transactiondetails.cardid:27 [outer=(1,27), constraints=(/1: (/NULL - ]; /27: (/NULL - ]), fd=(1)==(27), (27)==(1)] │ │ │ ├── immutable │ │ │ ├── stats: [rows=519622.1, distinct(10)=19000, null(10)=0, distinct(27)=19000, null(27)=0, distinct(2,4,5,10)=29618.5, null(2,4,5,10)=0] │ │ │ ├── key: (10,26-28) @@ -1107,8 +1107,8 @@ top-k │ │ ├── lookup expression │ │ │ └── filters │ │ │ ├── dealerid:8 IN (1, 2, 3, 4, 5) [outer=(8), constraints=(/8: [/1 - /1] [/2 - /2] [/3 - /3] [/4 - /4] [/5 - /5]; tight)] - │ │ │ ├── id:6 = cardid:9 [outer=(6,9), constraints=(/6: (/NULL - ]; /9: (/NULL - ]), fd=(6)==(9), (9)==(6)] - │ │ │ └── accountname:10 IN ('account-1', 'account-2', 'account-3') [outer=(10), constraints=(/10: [/'account-1' - /'account-1'] [/'account-2' - /'account-2'] [/'account-3' - /'account-3']; tight)] + │ │ │ ├── accountname:10 IN ('account-1', 'account-2', 'account-3') [outer=(10), constraints=(/10: [/'account-1' - /'account-1'] [/'account-2' - /'account-2'] [/'account-3' - /'account-3']; tight)] + │ │ │ └── id:6 = cardid:9 [outer=(6,9), constraints=(/6: (/NULL - ]; /9: (/NULL - ]), fd=(6)==(9), (9)==(6)] │ │ ├── fd: (8-10)-->(11), (6)==(9), (9)==(6) │ │ ├── values │ │ │ ├── columns: id:6!null quantity:7!null diff --git a/pkg/sql/opt/xform/testdata/rules/generic b/pkg/sql/opt/xform/testdata/rules/generic index fed232cac6d0..035a0cf9df1f 100644 --- a/pkg/sql/opt/xform/testdata/rules/generic +++ b/pkg/sql/opt/xform/testdata/rules/generic @@ -446,8 +446,8 @@ project │ ├── flags: disallow merge join │ ├── lookup expression │ │ └── filters - │ │ ├── "$1":8 = i:2 [outer=(2,8), constraints=(/2: (/NULL - ]; /8: (/NULL - ]), fd=(2)==(8), (8)==(2)] - │ │ └── t:5 > column9:9 [outer=(5,9), constraints=(/5: (/NULL - ]; /9: (/NULL - ])] + │ │ ├── t:5 > column9:9 [outer=(5,9), constraints=(/5: (/NULL - ]; /9: (/NULL - ])] + │ │ └── "$1":8 = i:2 [outer=(2,8), constraints=(/2: (/NULL - ]; /8: (/NULL - ]), fd=(2)==(8), (8)==(2)] │ ├── stable, has-placeholder │ ├── key: (1) │ ├── fd: ()-->(2,8,9), (1)-->(5), (2)==(8), (8)==(2) diff --git a/pkg/sql/opt/xform/testdata/rules/join b/pkg/sql/opt/xform/testdata/rules/join index 6d3cf4f5f192..0ef3ddd7ed61 100644 --- a/pkg/sql/opt/xform/testdata/rules/join +++ b/pkg/sql/opt/xform/testdata/rules/join @@ -2342,8 +2342,8 @@ left-join (lookup abcd@abcd_a_b_idx) ├── columns: a:6 b:7 n:2 m:1 ├── lookup expression │ └── filters - │ ├── m:1 = a:6 [outer=(1,6), constraints=(/1: (/NULL - ]; /6: (/NULL - ]), fd=(1)==(6), (6)==(1)] - │ └── b:7 > n:2 [outer=(2,7), constraints=(/2: (/NULL - ]; /7: (/NULL - ])] + │ ├── b:7 > n:2 [outer=(2,7), constraints=(/2: (/NULL - ]; /7: (/NULL - ])] + │ └── m:1 = a:6 [outer=(1,6), constraints=(/1: (/NULL - ]; /6: (/NULL - ]), fd=(1)==(6), (6)==(1)] ├── scan small │ └── columns: m:1 n:2 └── filters (true) @@ -2396,8 +2396,8 @@ inner-join (lookup abcd) │ ├── columns: m:1!null n:2!null a:6!null b:7!null abcd.rowid:9!null │ ├── lookup expression │ │ └── filters - │ │ ├── m:1 = a:6 [outer=(1,6), constraints=(/1: (/NULL - ]; /6: (/NULL - ]), fd=(1)==(6), (6)==(1)] - │ │ └── b:7 > n:2 [outer=(2,7), constraints=(/2: (/NULL - ]; /7: (/NULL - ])] + │ │ ├── b:7 > n:2 [outer=(2,7), constraints=(/2: (/NULL - ]; /7: (/NULL - ])] + │ │ └── m:1 = a:6 [outer=(1,6), constraints=(/1: (/NULL - ]; /6: (/NULL - ]), fd=(1)==(6), (6)==(1)] │ ├── fd: (9)-->(6,7), (1)==(6), (6)==(1) │ ├── scan small │ │ └── columns: m:1 n:2 @@ -2416,8 +2416,8 @@ left-join (lookup abcd) │ ├── columns: m:1 n:2 a:6 b:7 abcd.rowid:9 │ ├── lookup expression │ │ └── filters - │ │ ├── m:1 = a:6 [outer=(1,6), constraints=(/1: (/NULL - ]; /6: (/NULL - ]), fd=(1)==(6), (6)==(1)] - │ │ └── b:7 > n:2 [outer=(2,7), constraints=(/2: (/NULL - ]; /7: (/NULL - ])] + │ │ ├── b:7 > n:2 [outer=(2,7), constraints=(/2: (/NULL - ]; /7: (/NULL - ])] + │ │ └── m:1 = a:6 [outer=(1,6), constraints=(/1: (/NULL - ]; /6: (/NULL - ]), fd=(1)==(6), (6)==(1)] │ ├── fd: (9)-->(6,7) │ ├── scan small │ │ └── columns: m:1 n:2 @@ -3060,8 +3060,8 @@ left-join (lookup lookup_expr [as=t]) │ ├── lookup expression │ │ └── filters │ │ ├── r:3 IN ('east', 'west') [outer=(3), constraints=(/3: [/'east' - /'east'] [/'west' - /'west']; tight)] - │ │ ├── column2:2 = x:8 [outer=(2,8), constraints=(/2: (/NULL - ]; /8: (/NULL - ]), fd=(2)==(8), (8)==(2)] │ │ ├── y:9 IN (10, 20) [outer=(9), constraints=(/9: [/10 - /10] [/20 - /20]; tight)] + │ │ ├── column2:2 = x:8 [outer=(2,8), constraints=(/2: (/NULL - ]; /8: (/NULL - ]), fd=(2)==(8), (8)==(2)] │ │ ├── "lookup_join_const_col_@10":13 = z:10 [outer=(10,13), constraints=(/10: (/NULL - ]; /13: (/NULL - ]), fd=(10)==(13), (13)==(10)] │ │ └── column1:1 = w:7 [outer=(1,7), constraints=(/1: (/NULL - ]; /7: (/NULL - ]), fd=(1)==(7), (7)==(1)] │ ├── cardinality: [3 - ] @@ -3098,8 +3098,8 @@ left-join (lookup lookup_expr [as=t]) │ ├── lookup expression │ │ └── filters │ │ ├── r:3 IN ('east', 'west') [outer=(3), constraints=(/3: [/'east' - /'east'] [/'west' - /'west']; tight)] - │ │ ├── column2:2 = u:5 [outer=(2,5), constraints=(/2: (/NULL - ]; /5: (/NULL - ]), fd=(2)==(5), (5)==(2)] - │ │ └── y:9 IN (10, 20) [outer=(9), constraints=(/9: [/10 - /10] [/20 - /20]; tight)] + │ │ ├── y:9 IN (10, 20) [outer=(9), constraints=(/9: [/10 - /10] [/20 - /20]; tight)] + │ │ └── column2:2 = u:5 [outer=(2,5), constraints=(/2: (/NULL - ]; /5: (/NULL - ]), fd=(2)==(5), (5)==(2)] │ ├── cardinality: [3 - ] │ ├── fd: (3,4)-->(5-7,9,10) │ ├── values @@ -3127,8 +3127,8 @@ left-join (lookup lookup_expr [as=t]) │ ├── columns: column1:1!null column2:2 r:3 k:4 v:6 w:7 │ ├── lookup expression │ │ └── filters - │ │ ├── column1:1 = v:6 [outer=(1,6), constraints=(/1: (/NULL - ]; /6: (/NULL - ]), fd=(1)==(6), (6)==(1)] │ │ ├── r:3 IN ('east', 'west') [outer=(3), constraints=(/3: [/'east' - /'east'] [/'west' - /'west']; tight)] + │ │ ├── column1:1 = v:6 [outer=(1,6), constraints=(/1: (/NULL - ]; /6: (/NULL - ]), fd=(1)==(6), (6)==(1)] │ │ └── column2:2 = w:7 [outer=(2,7), constraints=(/2: (/NULL - ]; /7: (/NULL - ]), fd=(2)==(7), (7)==(2)] │ ├── cardinality: [3 - ] │ ├── fd: (3,4)-->(6,7) @@ -3341,9 +3341,9 @@ project │ │ │ ├── columns: views.chat_id:1!null user_id:2!null id:14 items.chat_id:15 deleted:17 value:18 continuation:23 │ │ │ ├── lookup expression │ │ │ │ └── filters + │ │ │ │ ├── value:18 > 0 [outer=(18), constraints=(/18: [/1 - ]; tight)] │ │ │ │ ├── "lookup_join_const_col_@8":22 = deleted:17 [outer=(17,22), constraints=(/17: (/NULL - ]; /22: (/NULL - ]), fd=(17)==(22), (22)==(17)] - │ │ │ │ ├── views.chat_id:1 = items.chat_id:15 [outer=(1,15), constraints=(/1: (/NULL - ]; /15: (/NULL - ]), fd=(1)==(15), (15)==(1)] - │ │ │ │ └── value:18 > 0 [outer=(18), constraints=(/18: [/1 - ]; tight)] + │ │ │ │ └── views.chat_id:1 = items.chat_id:15 [outer=(1,15), constraints=(/1: (/NULL - ]; /15: (/NULL - ]), fd=(1)==(15), (15)==(1)] │ │ │ ├── first join in paired joiner; continuation column: continuation:23 │ │ │ ├── key: (14) │ │ │ ├── fd: ()-->(1,2,15,17), (14)-->(18,23) @@ -3459,8 +3459,8 @@ inner-join (lookup abcd@abcd_a_b_idx) ├── columns: a:6!null b:7!null n:2 m:1!null ├── lookup expression │ └── filters - │ ├── m:1 = a:6 [outer=(1,6), constraints=(/1: (/NULL - ]; /6: (/NULL - ]), fd=(1)==(6), (6)==(1)] - │ └── b:7 > 1 [outer=(7), constraints=(/7: [/2 - ]; tight)] + │ ├── b:7 > 1 [outer=(7), constraints=(/7: [/2 - ]; tight)] + │ └── m:1 = a:6 [outer=(1,6), constraints=(/1: (/NULL - ]; /6: (/NULL - ]), fd=(1)==(6), (6)==(1)] ├── fd: (1)==(6), (6)==(1) ├── scan small │ └── columns: m:1 n:2 @@ -3474,8 +3474,8 @@ left-join (lookup abcd@abcd_a_b_idx) ├── columns: a:6 b:7 n:2 m:1 ├── lookup expression │ └── filters - │ ├── m:1 = a:6 [outer=(1,6), constraints=(/1: (/NULL - ]; /6: (/NULL - ]), fd=(1)==(6), (6)==(1)] - │ └── b:7 > 1 [outer=(7), constraints=(/7: [/2 - ]; tight)] + │ ├── b:7 > 1 [outer=(7), constraints=(/7: [/2 - ]; tight)] + │ └── m:1 = a:6 [outer=(1,6), constraints=(/1: (/NULL - ]; /6: (/NULL - ]), fd=(1)==(6), (6)==(1)] ├── scan small │ └── columns: m:1 n:2 └── filters (true) @@ -3493,8 +3493,8 @@ inner-join (lookup abcd) │ ├── columns: m:1!null n:2 a:6!null b:7!null abcd.rowid:9!null │ ├── lookup expression │ │ └── filters - │ │ ├── m:1 = a:6 [outer=(1,6), constraints=(/1: (/NULL - ]; /6: (/NULL - ]), fd=(1)==(6), (6)==(1)] - │ │ └── b:7 > 1 [outer=(7), constraints=(/7: [/2 - ]; tight)] + │ │ ├── b:7 > 1 [outer=(7), constraints=(/7: [/2 - ]; tight)] + │ │ └── m:1 = a:6 [outer=(1,6), constraints=(/1: (/NULL - ]; /6: (/NULL - ]), fd=(1)==(6), (6)==(1)] │ ├── fd: (9)-->(6,7), (1)==(6), (6)==(1) │ ├── scan small │ │ └── columns: m:1 n:2 @@ -3513,8 +3513,8 @@ left-join (lookup abcd) │ ├── columns: m:1 n:2 a:6 b:7 abcd.rowid:9 │ ├── lookup expression │ │ └── filters - │ │ ├── m:1 = a:6 [outer=(1,6), constraints=(/1: (/NULL - ]; /6: (/NULL - ]), fd=(1)==(6), (6)==(1)] - │ │ └── b:7 > 1 [outer=(7), constraints=(/7: [/2 - ]; tight)] + │ │ ├── b:7 > 1 [outer=(7), constraints=(/7: [/2 - ]; tight)] + │ │ └── m:1 = a:6 [outer=(1,6), constraints=(/1: (/NULL - ]; /6: (/NULL - ]), fd=(1)==(6), (6)==(1)] │ ├── fd: (9)-->(6,7) │ ├── scan small │ │ └── columns: m:1 n:2 @@ -3534,8 +3534,8 @@ inner-join (lookup abcd) │ ├── columns: m:1!null n:2!null a:6!null b:7!null abcd.rowid:9!null │ ├── lookup expression │ │ └── filters - │ │ ├── m:1 = a:6 [outer=(1,6), constraints=(/1: (/NULL - ]; /6: (/NULL - ]), fd=(1)==(6), (6)==(1)] - │ │ └── b:7 > n:2 [outer=(2,7), constraints=(/2: (/NULL - ]; /7: (/NULL - ])] + │ │ ├── b:7 > n:2 [outer=(2,7), constraints=(/2: (/NULL - ]; /7: (/NULL - ])] + │ │ └── m:1 = a:6 [outer=(1,6), constraints=(/1: (/NULL - ]; /6: (/NULL - ]), fd=(1)==(6), (6)==(1)] │ ├── fd: (9)-->(6,7), (1)==(6), (6)==(1) │ ├── scan small │ │ └── columns: m:1 n:2 @@ -3555,8 +3555,8 @@ left-join (lookup abcd) │ ├── columns: m:1 n:2 a:6 b:7 abcd.rowid:9 │ ├── lookup expression │ │ └── filters - │ │ ├── m:1 = a:6 [outer=(1,6), constraints=(/1: (/NULL - ]; /6: (/NULL - ]), fd=(1)==(6), (6)==(1)] - │ │ └── b:7 > n:2 [outer=(2,7), constraints=(/2: (/NULL - ]; /7: (/NULL - ])] + │ │ ├── b:7 > n:2 [outer=(2,7), constraints=(/2: (/NULL - ]; /7: (/NULL - ])] + │ │ └── m:1 = a:6 [outer=(1,6), constraints=(/1: (/NULL - ]; /6: (/NULL - ]), fd=(1)==(6), (6)==(1)] │ ├── fd: (9)-->(6,7) │ ├── scan small │ │ └── columns: m:1 n:2 @@ -3577,8 +3577,8 @@ inner-join (lookup abcd) │ ├── columns: m:1!null n:2 a:6!null b:7!null abcd.rowid:9!null │ ├── lookup expression │ │ └── filters - │ │ ├── m:1 = a:6 [outer=(1,6), constraints=(/1: (/NULL - ]; /6: (/NULL - ]), fd=(1)==(6), (6)==(1)] - │ │ └── b:7 > 1 [outer=(7), constraints=(/7: [/2 - ]; tight)] + │ │ ├── b:7 > 1 [outer=(7), constraints=(/7: [/2 - ]; tight)] + │ │ └── m:1 = a:6 [outer=(1,6), constraints=(/1: (/NULL - ]; /6: (/NULL - ]), fd=(1)==(6), (6)==(1)] │ ├── fd: (9)-->(6,7), (1)==(6), (6)==(1) │ ├── scan small │ │ └── columns: m:1 n:2 @@ -3600,8 +3600,8 @@ left-join (lookup abcd) │ ├── columns: m:1 n:2 a:12 b:13 abcd.rowid:15 continuation:18 │ ├── lookup expression │ │ └── filters - │ │ ├── m:1 = a:12 [outer=(1,12), constraints=(/1: (/NULL - ]; /12: (/NULL - ]), fd=(1)==(12), (12)==(1)] - │ │ └── b:13 > 1 [outer=(13), constraints=(/13: [/2 - ]; tight)] + │ │ ├── b:13 > 1 [outer=(13), constraints=(/13: [/2 - ]; tight)] + │ │ └── m:1 = a:12 [outer=(1,12), constraints=(/1: (/NULL - ]; /12: (/NULL - ]), fd=(1)==(12), (12)==(1)] │ ├── first join in paired joiner; continuation column: continuation:18 │ ├── fd: (15)-->(12,13,18) │ ├── scan small @@ -3689,8 +3689,8 @@ inner-join (lookup abcde) │ ├── columns: m:1!null n:2 a:6!null b:7!null c:8 abcde.rowid:11!null │ ├── lookup expression │ │ └── filters - │ │ ├── m:1 = a:6 [outer=(1,6), constraints=(/1: (/NULL - ]; /6: (/NULL - ]), fd=(1)==(6), (6)==(1)] - │ │ └── b:7 IN (10, 20, 30) [outer=(7), constraints=(/7: [/10 - /10] [/20 - /20] [/30 - /30]; tight)] + │ │ ├── b:7 IN (10, 20, 30) [outer=(7), constraints=(/7: [/10 - /10] [/20 - /20] [/30 - /30]; tight)] + │ │ └── m:1 = a:6 [outer=(1,6), constraints=(/1: (/NULL - ]; /6: (/NULL - ]), fd=(1)==(6), (6)==(1)] │ ├── fd: (11)-->(6-8), (1)==(6), (6)==(1) │ ├── scan small │ │ └── columns: m:1 n:2 @@ -3711,8 +3711,8 @@ inner-join (lookup abcde) │ ├── columns: m:1!null n:2 a:6!null b:7!null c:8!null abcde.rowid:11!null │ ├── lookup expression │ │ └── filters - │ │ ├── m:1 = a:6 [outer=(1,6), constraints=(/1: (/NULL - ]; /6: (/NULL - ]), fd=(1)==(6), (6)==(1)] │ │ ├── b:7 IN (10, 20, 30) [outer=(7), constraints=(/7: [/10 - /10] [/20 - /20] [/30 - /30]; tight)] + │ │ ├── m:1 = a:6 [outer=(1,6), constraints=(/1: (/NULL - ]; /6: (/NULL - ]), fd=(1)==(6), (6)==(1)] │ │ └── "lookup_join_const_col_@8":14 = c:8 [outer=(8,14), constraints=(/8: (/NULL - ]; /14: (/NULL - ]), fd=(8)==(14), (14)==(8)] │ ├── fd: ()-->(8), (11)-->(6,7), (1)==(6), (6)==(1) │ ├── project @@ -3740,9 +3740,9 @@ inner-join (lookup abcde) │ ├── columns: m:1!null n:2 a:6!null b:7!null c:8!null abcde.rowid:11!null │ ├── lookup expression │ │ └── filters + │ │ ├── c:8 IN (10, 20, 30) [outer=(8), constraints=(/8: [/10 - /10] [/20 - /20] [/30 - /30]; tight)] │ │ ├── m:1 = a:6 [outer=(1,6), constraints=(/1: (/NULL - ]; /6: (/NULL - ]), fd=(1)==(6), (6)==(1)] - │ │ ├── "lookup_join_const_col_@7":14 = b:7 [outer=(7,14), constraints=(/7: (/NULL - ]; /14: (/NULL - ]), fd=(7)==(14), (14)==(7)] - │ │ └── c:8 IN (10, 20, 30) [outer=(8), constraints=(/8: [/10 - /10] [/20 - /20] [/30 - /30]; tight)] + │ │ └── "lookup_join_const_col_@7":14 = b:7 [outer=(7,14), constraints=(/7: (/NULL - ]; /14: (/NULL - ]), fd=(7)==(14), (14)==(7)] │ ├── fd: ()-->(7), (11)-->(6,8), (1)==(6), (6)==(1) │ ├── project │ │ ├── columns: "lookup_join_const_col_@7":14!null m:1 n:2 @@ -3767,9 +3767,9 @@ inner-join (lookup abcde) │ ├── columns: m:1!null n:2 a:6!null b:7!null c:8!null abcde.rowid:11!null │ ├── lookup expression │ │ └── filters - │ │ ├── m:1 = a:6 [outer=(1,6), constraints=(/1: (/NULL - ]; /6: (/NULL - ]), fd=(1)==(6), (6)==(1)] │ │ ├── b:7 IN (10, 20) [outer=(7), constraints=(/7: [/10 - /10] [/20 - /20]; tight)] - │ │ └── c:8 IN (30, 40) [outer=(8), constraints=(/8: [/30 - /30] [/40 - /40]; tight)] + │ │ ├── c:8 IN (30, 40) [outer=(8), constraints=(/8: [/30 - /30] [/40 - /40]; tight)] + │ │ └── m:1 = a:6 [outer=(1,6), constraints=(/1: (/NULL - ]; /6: (/NULL - ]), fd=(1)==(6), (6)==(1)] │ ├── fd: (11)-->(6-8), (1)==(6), (6)==(1) │ ├── scan small │ │ └── columns: m:1 n:2 @@ -3814,8 +3814,8 @@ inner-join (lookup abcde) │ ├── columns: m:1!null n:2 a:6!null b:7!null c:8 abcde.rowid:11!null │ ├── lookup expression │ │ └── filters - │ │ ├── m:1 = a:6 [outer=(1,6), constraints=(/1: (/NULL - ]; /6: (/NULL - ]), fd=(1)==(6), (6)==(1)] - │ │ └── b:7 < 10 [outer=(7), constraints=(/7: (/NULL - /9]; tight)] + │ │ ├── b:7 < 10 [outer=(7), constraints=(/7: (/NULL - /9]; tight)] + │ │ └── m:1 = a:6 [outer=(1,6), constraints=(/1: (/NULL - ]; /6: (/NULL - ]), fd=(1)==(6), (6)==(1)] │ ├── fd: (11)-->(6-8), (1)==(6), (6)==(1) │ ├── scan small │ │ └── columns: m:1 n:2 @@ -3948,8 +3948,8 @@ inner-join (lookup abcd_check) │ ├── columns: m:1!null n:2 a:6!null b:7!null c:8 abcd_check.rowid:10!null │ ├── lookup expression │ │ └── filters - │ │ ├── m:1 = a:6 [outer=(1,6), constraints=(/1: (/NULL - ]; /6: (/NULL - ]), fd=(1)==(6), (6)==(1)] - │ │ └── b:7 IN (10, 20) [outer=(7), constraints=(/7: [/10 - /10] [/20 - /20]; tight)] + │ │ ├── b:7 IN (10, 20) [outer=(7), constraints=(/7: [/10 - /10] [/20 - /20]; tight)] + │ │ └── m:1 = a:6 [outer=(1,6), constraints=(/1: (/NULL - ]; /6: (/NULL - ]), fd=(1)==(6), (6)==(1)] │ ├── fd: (10)-->(6-8), (1)==(6), (6)==(1) │ ├── scan small │ │ └── columns: m:1 n:2 @@ -3968,8 +3968,8 @@ inner-join (lookup abcd_check) │ ├── columns: m:1!null n:2 a:6!null b:7!null c:8!null abcd_check.rowid:10!null │ ├── lookup expression │ │ └── filters - │ │ ├── m:1 = a:6 [outer=(1,6), constraints=(/1: (/NULL - ]; /6: (/NULL - ]), fd=(1)==(6), (6)==(1)] │ │ ├── b:7 IN (10, 20) [outer=(7), constraints=(/7: [/10 - /10] [/20 - /20]; tight)] + │ │ ├── m:1 = a:6 [outer=(1,6), constraints=(/1: (/NULL - ]; /6: (/NULL - ]), fd=(1)==(6), (6)==(1)] │ │ └── "lookup_join_const_col_@8":13 = c:8 [outer=(8,13), constraints=(/8: (/NULL - ]; /13: (/NULL - ]), fd=(8)==(13), (13)==(8)] │ ├── fd: ()-->(8), (10)-->(6,7), (1)==(6), (6)==(1) │ ├── project @@ -4176,9 +4176,9 @@ project ├── columns: m:1!null a:6!null b:7!null c:8!null ├── lookup expression │ └── filters - │ ├── m:1 = a:6 [outer=(1,6), constraints=(/1: (/NULL - ]; /6: (/NULL - ]), fd=(1)==(6), (6)==(1)] │ ├── b:7 IN (1, 2, 3) [outer=(7), constraints=(/7: [/1 - /1] [/2 - /2] [/3 - /3]; tight)] - │ └── c:8 > 0 [outer=(8), constraints=(/8: [/1 - ]; tight)] + │ ├── c:8 > 0 [outer=(8), constraints=(/8: [/1 - ]; tight)] + │ └── m:1 = a:6 [outer=(1,6), constraints=(/1: (/NULL - ]; /6: (/NULL - ]), fd=(1)==(6), (6)==(1)] ├── fd: (1)==(6), (6)==(1) ├── scan small │ └── columns: m:1 @@ -4202,9 +4202,9 @@ inner-join (lookup t80525_bcd@t80525_bcd_b_c_d_idx) ├── flags: force lookup join (into right side) ├── lookup expression │ └── filters + │ ├── d:7 > 0 [outer=(7), constraints=(/7: [/1 - ]; tight)] │ ├── a:1 = b:5 [outer=(1,5), constraints=(/1: (/NULL - ]; /5: (/NULL - ]), fd=(1)==(5), (5)==(1)] - │ ├── "lookup_join_const_col_@6":11 = c:6 [outer=(6,11), constraints=(/6: (/NULL - ]; /11: (/NULL - ]), fd=(6)==(11), (11)==(6)] - │ └── d:7 > 0 [outer=(7), constraints=(/7: [/1 - ]; tight)] + │ └── "lookup_join_const_col_@6":11 = c:6 [outer=(6,11), constraints=(/6: (/NULL - ]; /11: (/NULL - ]), fd=(6)==(11), (11)==(6)] ├── fd: ()-->(6), (1)==(5), (5)==(1) ├── project │ ├── columns: "lookup_join_const_col_@6":11!null a:1 @@ -12162,8 +12162,8 @@ inner-join (lookup metric_values) ├── columns: metric_id:1!null time:2!null value:3 id:6!null name:7!null ├── lookup expression │ └── filters - │ ├── id:6 = metric_id:1 [outer=(1,6), constraints=(/1: (/NULL - ]; /6: (/NULL - ]), fd=(1)==(6), (6)==(1)] - │ └── (time:2 >= '2020-01-01 00:00:00+00') AND (time:2 <= '2020-01-01 00:10:00+00') [outer=(2), constraints=(/2: [/'2020-01-01 00:00:00+00' - /'2020-01-01 00:10:00+00']; tight)] + │ ├── (time:2 >= '2020-01-01 00:00:00+00') AND (time:2 <= '2020-01-01 00:10:00+00') [outer=(2), constraints=(/2: [/'2020-01-01 00:00:00+00' - /'2020-01-01 00:10:00+00']; tight)] + │ └── id:6 = metric_id:1 [outer=(1,6), constraints=(/1: (/NULL - ]; /6: (/NULL - ]), fd=(1)==(6), (6)==(1)] ├── key: (2,6) ├── fd: ()-->(7), (1,2)-->(3), (1)==(6), (6)==(1) ├── scan metrics@name_index @@ -12186,8 +12186,8 @@ inner-join (lookup metric_values) ├── columns: metric_id:1!null time:2!null value:3 id:6!null name:7!null ├── lookup expression │ └── filters - │ ├── id:6 = metric_id:1 [outer=(1,6), constraints=(/1: (/NULL - ]; /6: (/NULL - ]), fd=(1)==(6), (6)==(1)] - │ └── (time:2 >= '2020-01-01 00:00:00+00') AND (time:2 <= '2020-01-01 00:10:00+00') [outer=(2), constraints=(/2: [/'2020-01-01 00:00:00+00' - /'2020-01-01 00:10:00+00']; tight)] + │ ├── (time:2 >= '2020-01-01 00:00:00+00') AND (time:2 <= '2020-01-01 00:10:00+00') [outer=(2), constraints=(/2: [/'2020-01-01 00:00:00+00' - /'2020-01-01 00:10:00+00']; tight)] + │ └── id:6 = metric_id:1 [outer=(1,6), constraints=(/1: (/NULL - ]; /6: (/NULL - ]), fd=(1)==(6), (6)==(1)] ├── key: (2,6) ├── fd: (1,2)-->(3), (6)-->(7), (1)==(6), (6)==(1) ├── scan metrics@name_index @@ -12216,8 +12216,8 @@ inner-join (lookup metric_values) ├── columns: metric_id:1!null time:2!null value:3 id:6!null name:7!null ├── lookup expression │ └── filters - │ ├── id:6 = metric_id:1 [outer=(1,6), constraints=(/1: (/NULL - ]; /6: (/NULL - ]), fd=(1)==(6), (6)==(1)] - │ └── time:2 IN ('2022-04-08 00:00:00+00', '2022-04-09 00:00:00+00') [outer=(2), constraints=(/2: [/'2022-04-08 00:00:00+00' - /'2022-04-08 00:00:00+00'] [/'2022-04-09 00:00:00+00' - /'2022-04-09 00:00:00+00']; tight)] + │ ├── time:2 IN ('2022-04-08 00:00:00+00', '2022-04-09 00:00:00+00') [outer=(2), constraints=(/2: [/'2022-04-08 00:00:00+00' - /'2022-04-08 00:00:00+00'] [/'2022-04-09 00:00:00+00' - /'2022-04-09 00:00:00+00']; tight)] + │ └── id:6 = metric_id:1 [outer=(1,6), constraints=(/1: (/NULL - ]; /6: (/NULL - ]), fd=(1)==(6), (6)==(1)] ├── key: (2,6) ├── fd: ()-->(7), (1,2)-->(3), (1)==(6), (6)==(1) ├── scan metrics@name_index @@ -12264,8 +12264,8 @@ left-join (lookup metric_values) ├── columns: id:1!null name:2 metric_id:5 time:6 value:7 ├── lookup expression │ └── filters - │ ├── id:1 = metric_id:5 [outer=(1,5), constraints=(/1: (/NULL - ]; /5: (/NULL - ]), fd=(1)==(5), (5)==(1)] - │ └── (time:6 >= '2020-01-01 00:00:00+00') AND (time:6 <= '2020-01-01 00:10:00+00') [outer=(6), constraints=(/6: [/'2020-01-01 00:00:00+00' - /'2020-01-01 00:10:00+00']; tight)] + │ ├── (time:6 >= '2020-01-01 00:00:00+00') AND (time:6 <= '2020-01-01 00:10:00+00') [outer=(6), constraints=(/6: [/'2020-01-01 00:00:00+00' - /'2020-01-01 00:10:00+00']; tight)] + │ └── id:1 = metric_id:5 [outer=(1,5), constraints=(/1: (/NULL - ]; /5: (/NULL - ]), fd=(1)==(5), (5)==(1)] ├── key: (1,5,6) ├── fd: (1)-->(2), (5,6)-->(7) ├── scan metrics From bc493bf86c66fd54d987b6324b7193594bb5fb1a Mon Sep 17 00:00:00 2001 From: Marcus Gartner Date: Mon, 27 Jun 2022 11:50:27 -0400 Subject: [PATCH 2/2] opt: fix greedy lookup join constraints Previously, lookup joins would be planned that constrained as many index columns as possible. This is not optimal when a suffix of columns are constrained to multiple values or a range of constant values by optional filters. These suffixes increase the number of lookup spans without making the constraint more selective. In the case where suffix columns are constrained to multiple values, a lookup span is generated for each value, significantly increasing the number of lookups performed for each input row. This commit makes the building of lookup join constraints less greedy. The suffix of constrained columns will only be constrained to multiple values or a range over some constant values if those constraints originate from the query filter. Fixes #75596 Release note (performance improvement): The optimizer now plans more efficient lookup joins in some cases. --- pkg/sql/opt/lookupjoin/constraint_builder.go | 45 +++++++++-- pkg/sql/opt/lookupjoin/testdata/computed | 49 ++++++++++++ pkg/sql/opt/lookupjoin/testdata/key_cols | 53 +++++++++++++ pkg/sql/opt/lookupjoin/testdata/lookup_expr | 79 +++++++++++++------- pkg/sql/opt/xform/testdata/rules/join | 8 +- 5 files changed, 194 insertions(+), 40 deletions(-) diff --git a/pkg/sql/opt/lookupjoin/constraint_builder.go b/pkg/sql/opt/lookupjoin/constraint_builder.go index 5c4c8fcd70cb..975f714ec34f 100644 --- a/pkg/sql/opt/lookupjoin/constraint_builder.go +++ b/pkg/sql/opt/lookupjoin/constraint_builder.go @@ -224,12 +224,20 @@ func (b *ConstraintBuilder) Build( colsAlloc := make(opt.ColList, numIndexKeyCols*2) keyCols := colsAlloc[0:0:numIndexKeyCols] rightSideCols := colsAlloc[numIndexKeyCols : numIndexKeyCols : numIndexKeyCols*2] - var inputProjections memo.ProjectionsExpr - var lookupExpr memo.FiltersExpr - var allLookupFilters memo.FiltersExpr - var filterOrdsToExclude intsets.Fast foundLookupCols := false - var remainingFilters memo.FiltersExpr + var ( + inputProjections memo.ProjectionsExpr + lookupExpr memo.FiltersExpr + allLookupFilters memo.FiltersExpr + remainingFilters memo.FiltersExpr + filterOrdsToExclude intsets.Fast + ) + // We do not want a suffix of the index columns to be constrained to + // multiple values by optional filters. This would only increase the number + // of lookup spans without making the constraint more selective. We keep + // track of the suffix length of indexed columns constrained in this way so + // that we can remove them after the loop. + optionalMultiValFilterSuffixLen := 0 // addEqualityColumns adds the given columns as an equality in keyCols and // rightSideCols. @@ -249,6 +257,7 @@ func (b *ConstraintBuilder) Build( filterOrdsToExclude.Add(eqFilterOrds[eqIdx]) foundEqualityCols = true foundLookupCols = true + optionalMultiValFilterSuffixLen = 0 continue } @@ -278,6 +287,7 @@ func (b *ConstraintBuilder) Build( derivedEquivCols.Add(idxCol) foundEqualityCols = true foundLookupCols = true + optionalMultiValFilterSuffixLen = 0 continue } @@ -302,6 +312,7 @@ func (b *ConstraintBuilder) Build( allLookupFilters = append(allLookupFilters, b.allFilters[allIdx]) addEqualityColumns(constColID, idxCol) filterOrdsToExclude.Add(allIdx) + optionalMultiValFilterSuffixLen = 0 continue } @@ -319,7 +330,15 @@ func (b *ConstraintBuilder) Build( } lookupExpr = append(lookupExpr, valsFilter) allLookupFilters = append(allLookupFilters, b.allFilters[allIdx]) - filterOrdsToExclude.Add(allIdx) + if isOptional := allIdx >= len(onFilters); isOptional { + optionalMultiValFilterSuffixLen++ + } else { + // There's no need to track optional filters for reducing the + // remaining filters because they are not present in the ON + // filters to begin with. + filterOrdsToExclude.Add(allIdx) + } + continue } @@ -333,12 +352,14 @@ func (b *ConstraintBuilder) Build( allLookupFilters = append(allLookupFilters, b.allFilters[startIdx]) filterOrdsToExclude.Add(startIdx) foundLookupCols = true + optionalMultiValFilterSuffixLen = 0 } if foundEnd { lookupExpr = append(lookupExpr, b.allFilters[endIdx]) allLookupFilters = append(allLookupFilters, b.allFilters[endIdx]) filterOrdsToExclude.Add(endIdx) foundLookupCols = true + optionalMultiValFilterSuffixLen = 0 } if foundStart && foundEnd { // The column is constrained above and below by an inequality; no further @@ -351,8 +372,11 @@ func (b *ConstraintBuilder) Build( // case that only the start or end bound could be constrained with // an input column; in this case, it still may be possible to use a constant // to form the other bound. + // + // We exclude optional filters from this search because an optional + // range filter will not make the lookup more selective. rangeFilter, remaining, filterIdx := b.findJoinConstantRangeFilter( - b.allFilters, idxCol, idxColIsDesc, !foundStart, !foundEnd, + onFilters, idxCol, idxColIsDesc, !foundStart, !foundEnd, ) if rangeFilter != nil { // A constant range filter could be found. @@ -377,6 +401,13 @@ func (b *ConstraintBuilder) Build( return Constraint{}, false } + // Remove the suffix of index columns constrained to multiple values by + // optional filters. + if lookupExpr != nil && optionalMultiValFilterSuffixLen > 0 { + lookupExpr = lookupExpr[:len(lookupExpr)-optionalMultiValFilterSuffixLen] + allLookupFilters = allLookupFilters[:len(allLookupFilters)-optionalMultiValFilterSuffixLen] + } + // If a lookup expression is required, convert the equality columns to // equalities in the lookup expression. if len(lookupExpr) > 0 { diff --git a/pkg/sql/opt/lookupjoin/testdata/computed b/pkg/sql/opt/lookupjoin/testdata/computed index b8d1f840c2a2..ac085b358262 100644 --- a/pkg/sql/opt/lookupjoin/testdata/computed +++ b/pkg/sql/opt/lookupjoin/testdata/computed @@ -76,6 +76,55 @@ input projections: v_eq = a + 10 lookup_join_const_col_@7 = 0 +lookup-constraints left=(a int, b int) right=(x int, v int not null as (x + 10) virtual, y INT) index=(v, y, x) +x = a +optional: y IN (10, 20) +---- +input projections: + v_eq = a + 10 +lookup expression: + ((y IN (10, 20)) AND (v_eq = v)) AND (a = x) + +lookup-constraints left=(a int, b int) right=(x int, v int not null as (x + 10) virtual, y INT, z INT) index=(v, y, x, z) +x = a AND z > 0 +optional: y IN (10, 20) +---- +input projections: + v_eq = a + 10 +lookup expression: + (((y IN (10, 20)) AND (z > 0)) AND (v_eq = v)) AND (a = x) + +lookup-constraints left=(a int, b int) right=(x int, v int not null as (x + 10) virtual, y INT, w INT) index=(v, y, x) +x = a AND w > 0 +optional: y IN (10, 20) +---- +input projections: + v_eq = a + 10 +lookup expression: + ((y IN (10, 20)) AND (v_eq = v)) AND (a = x) +remaining filters: + w > 0 + +lookup-constraints left=(a int, b int) right=(x int, v int not null as (x + 10) virtual, z INT) index=(v, x, z) +x = a +optional: z IN (10, 20) +---- +key cols: + v = v_eq + x = a +input projections: + v_eq = a + 10 + +lookup-constraints left=(a int, b int) right=(x int, v int not null as (x + 10) virtual, z INT) index=(v, x, z) +x = a +optional: z > 0 +---- +key cols: + v = v_eq + x = a +input projections: + v_eq = a + 10 + # TODO(mgartner): We should be able to generate a lookup join by determining # that v is not null because the filter demands that x is not null, and v is # calculated from x. diff --git a/pkg/sql/opt/lookupjoin/testdata/key_cols b/pkg/sql/opt/lookupjoin/testdata/key_cols index 9d2baee87214..3447b26f1809 100644 --- a/pkg/sql/opt/lookupjoin/testdata/key_cols +++ b/pkg/sql/opt/lookupjoin/testdata/key_cols @@ -165,3 +165,56 @@ key cols: z = a input projections: lookup_join_const_col_@5 = 0 + +lookup-constraints left=(a int, b int) right=(x int, y int, z int) index=(x, y, z) +x = a AND y = b +optional: z IN (3, 4) +---- +key cols: + x = a + y = b + +lookup-constraints left=(a int, b int) right=(x int, y int, z int) index=(x, y, z) +x = 1 AND y = b +optional: z IN (3, 4) +---- +key cols: + x = lookup_join_const_col_@6 + y = b +input projections: + lookup_join_const_col_@6 = 1 + +lookup-constraints left=(a int, b int, c int) right=(x int, y int, z int) index=(x, y, z) +x = a +optional: z IN (3, 4) AND y IN (10, 20) +---- +key cols: + x = a + +lookup-constraints left=(a int, b int) right=(x int, y int, z int) index=(x, y, z) +x = a AND y = b +optional: z > 10 +---- +key cols: + x = a + y = b + +lookup-constraints left=(a int, b int) right=(x int, y int, z int) index=(x, y, z) +x = 1 AND y = b +optional: z > 10 +---- +key cols: + x = lookup_join_const_col_@6 + y = b +input projections: + lookup_join_const_col_@6 = 1 + +lookup-constraints left=(a int, b int) right=(x int, y int, z int, zz int) index=(x, y, z, zz) +x = 1 AND y = b +optional: z > 10 AND zz > 0 +---- +key cols: + x = lookup_join_const_col_@6 + y = b +input projections: + lookup_join_const_col_@6 = 1 diff --git a/pkg/sql/opt/lookupjoin/testdata/lookup_expr b/pkg/sql/opt/lookupjoin/testdata/lookup_expr index 6426bd1f090c..283d3556a2a1 100644 --- a/pkg/sql/opt/lookupjoin/testdata/lookup_expr +++ b/pkg/sql/opt/lookupjoin/testdata/lookup_expr @@ -78,15 +78,15 @@ lookup-constraints left=(a int, b int) right=(x int, y int) index=(x, y) x = a optional: y IN (1, 2, 3) ---- -lookup expression: - (y IN (1, 2, 3)) AND (a = x) +key cols: + x = a lookup-constraints left=(a int, b int) right=(x int, y int, z int) index=(x, y) x = a AND z = 1 optional: y IN (1, 2, 3) ---- -lookup expression: - (y IN (1, 2, 3)) AND (a = x) +key cols: + x = a remaining filters: z = 1 @@ -94,8 +94,17 @@ lookup-constraints left=(a int, b int) right=(x int, y int, z int) index=(x, y) x = a optional: y IN (1, 2, 3) AND z = 1 ---- +key cols: + x = a + +lookup-constraints left=(a int, b int) right=(x int, y int, z int) index=(x, y, z) +x = a +optional: y IN (1, 2, 3) AND z = 1 +---- +input projections: + lookup_join_const_col_@8 = 1 lookup expression: - (y IN (1, 2, 3)) AND (a = x) + ((y IN (1, 2, 3)) AND (a = x)) AND (lookup_join_const_col_@8 = z) lookup-constraints left=(a int, b int, c int) right=(x int, y int, z int) index=(x, y, z) x = 1 AND z = c @@ -118,20 +127,7 @@ y = b optional: x IN (1, 2) AND z IN (3, 4) ---- lookup expression: - ((x IN (1, 2)) AND (z IN (3, 4))) AND (b = y) - -# TODO(#75596): The lookup expression should not contain (z IN (3, 4)) because -# it is an optional filter from a CHECK constraint. It will only increase the -# number of lookup spans generated without increasing the selectivity of the -# lookup. -lookup-constraints left=(a int, b int, c int) right=(x int, y int, z int) index=(x, y, z) -x = 1 AND y = b -optional: z IN (3, 4) ----- -input projections: - lookup_join_const_col_@7 = 1 -lookup expression: - ((z IN (3, 4)) AND (lookup_join_const_col_@7 = x)) AND (b = y) + (x IN (1, 2)) AND (b = y) # The most restrictive IN filter should be chosen. lookup-constraints left=(a int, b int) right=(x int, y int) index=(x, y) @@ -188,8 +184,8 @@ lookup-constraints left=(a int, b int) right=(x int, y int) index=(x, y) x = a optional: y > 0 ---- -lookup expression: - (y > 0) AND (a = x) +key cols: + x = a lookup-constraints left=(a int, b int, c int) right=(x int, y int, z int) index=(x, y, z) x = a AND y = b AND z > 0 @@ -217,17 +213,18 @@ lookup-constraints left=(a int, b int, c int) right=(x int, y int, z int) index= x = 1 AND y = b optional: z > 0 ---- +key cols: + x = lookup_join_const_col_@7 + y = b input projections: lookup_join_const_col_@7 = 1 -lookup expression: - ((z > 0) AND (lookup_join_const_col_@7 = x)) AND (b = y) lookup-constraints left=(a int, b int, c int) right=(x int, y int, z int) index=(x, y) x = a AND z = 1 optional: y > 0 ---- -lookup expression: - (y > 0) AND (a = x) +key cols: + x = a remaining filters: z = 1 @@ -235,8 +232,8 @@ lookup-constraints left=(a int, b int, c int) right=(x int, y int, z int) index= x = a optional: y > 0 AND z = 1 ---- -lookup expression: - (y > 0) AND (a = x) +key cols: + x = a # Test for range filters and IN filters. @@ -281,6 +278,20 @@ x IN (10, 20, 30, 40) AND y = b AND x > 10 lookup expression: (x IN (20, 30, 40)) AND (b = y) +lookup-constraints left=(a int) right=(x int, y int, z int) index=(x, y, z) +x IN (1, 2) AND y = a +optional: z > 10 +---- +lookup expression: + (x IN (1, 2)) AND (a = y) + +lookup-constraints left=(a int, b int) right=(x int, y int, z int, zz int) index=(x, y, z, zz) +x IN (1, 2) AND y = b +optional: z IN (10, 20, 30) AND zz > 0 +---- +lookup expression: + (x IN (1, 2)) AND (b = y) + # Test for range filters on input columns. lookup-constraints left=(a int, b int) right=(x int, y int) index=(x, y) @@ -464,3 +475,17 @@ x <= a ---- lookup expression: x <= a + +lookup-constraints left=(a int, b int) right=(x int, y int) index=(x, y) +y > b +optional: x IN (10, 20, 30) +---- +lookup expression: + (x IN (10, 20, 30)) AND (y > b) + +lookup-constraints left=(a int, b int, c int) right=(x int, y int, z int) index=(x, y, z) +x = a AND z > b +optional: y IN (10, 20, 30) +---- +lookup expression: + ((y IN (10, 20, 30)) AND (z > b)) AND (a = x) diff --git a/pkg/sql/opt/xform/testdata/rules/join b/pkg/sql/opt/xform/testdata/rules/join index 0ef3ddd7ed61..ae0fbf0851b9 100644 --- a/pkg/sql/opt/xform/testdata/rules/join +++ b/pkg/sql/opt/xform/testdata/rules/join @@ -3081,7 +3081,7 @@ left-join (lookup lookup_expr [as=t]) │ └── filters (true) └── filters (true) -# The filters in the lookup expression should constrain only the first 3 columns +# The filters in the lookup expression should constrain only the first 2 columns # of idx_u_etc. opt expect=GenerateLookupJoins SELECT * FROM (VALUES (1, 10), (2, 20), (3, NULL)) AS q(w, u) LEFT JOIN lookup_expr t @@ -3098,7 +3098,6 @@ left-join (lookup lookup_expr [as=t]) │ ├── lookup expression │ │ └── filters │ │ ├── r:3 IN ('east', 'west') [outer=(3), constraints=(/3: [/'east' - /'east'] [/'west' - /'west']; tight)] - │ │ ├── y:9 IN (10, 20) [outer=(9), constraints=(/9: [/10 - /10] [/20 - /20]; tight)] │ │ └── column2:2 = u:5 [outer=(2,5), constraints=(/2: (/NULL - ]; /5: (/NULL - ]), fd=(2)==(5), (5)==(2)] │ ├── cardinality: [3 - ] │ ├── fd: (3,4)-->(5-7,9,10) @@ -3946,10 +3945,7 @@ inner-join (lookup abcd_check) ├── fd: (1)==(6), (6)==(1) ├── inner-join (lookup abcd_check@abcd_check_a_b_c_idx) │ ├── columns: m:1!null n:2 a:6!null b:7!null c:8 abcd_check.rowid:10!null - │ ├── lookup expression - │ │ └── filters - │ │ ├── b:7 IN (10, 20) [outer=(7), constraints=(/7: [/10 - /10] [/20 - /20]; tight)] - │ │ └── m:1 = a:6 [outer=(1,6), constraints=(/1: (/NULL - ]; /6: (/NULL - ]), fd=(1)==(6), (6)==(1)] + │ ├── key columns: [1] = [6] │ ├── fd: (10)-->(6-8), (1)==(6), (6)==(1) │ ├── scan small │ │ └── columns: m:1 n:2