From 5be5e687459746a318655e327aa99e790c4bb342 Mon Sep 17 00:00:00 2001 From: Marcus Gartner Date: Thu, 6 Apr 2023 20:17:19 +0000 Subject: [PATCH] opt: hoist uncorrelated equality subqueries MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Subqueries that are in equality expressions with a variable are now hoisted. When these expressions exist in a filter, hoisting the subquery can allow the main query to plan a lookup join, rather than an inefficient full-table scan. For example, consider the table and query: CREATE TABLE t ( a INT, INDEX (a) ); SELECT * FROM t WHERE a = (SELECT max(a) FROM t); Prior to this commit, the query plan for this query required a full table scan: select ├── columns: a:1 ├── scan t@t_a_idx │ ├── columns: a:1 │ └── constraint: /1/2: (/NULL - ] └── filters └── eq ├── a:1 └── subquery └── scalar-group-by ├── columns: max:9 ├── scan t@t_a_idx,rev │ ├── columns: a:5 │ ├── constraint: /5/6: (/NULL - ] │ └── limit: 1(rev) └── aggregations └── const-agg [as=max:9, outer=(5)] └── a:5 By hoisting the subquery, the full table scan is replaced with a lookup join: project ├── columns: a:1 └── inner-join (lookup t@t_a_idx) ├── columns: a:1 max:9 ├── key columns: [9] = [1] ├── scalar-group-by │ ├── columns: max:9 │ ├── scan t@t_a_idx,rev │ │ ├── columns: a:5 │ │ ├── constraint: /5/6: (/NULL - ] │ │ └── limit: 1(rev) │ └── aggregations │ └── const-agg [as=max:9, outer=(5)] │ └── a:5 └── filters (true) This hoisting is enabled by default, but can be disabled by setting the `optimizer_hoist_uncorrelated_equality_subqueries` session setting to `false`. Fixes #83392 Informs #51820 Informs #93829 Informs #100855 Release note (performance improvement): Queries that have subqueries in equality expressions are now more efficiently planned by the optimizer. --- pkg/sql/exec_util.go | 4 + .../testdata/logic_test/information_schema | 1 + .../logictest/testdata/logic_test/pg_catalog | 3 + .../logictest/testdata/logic_test/show_source | 1 + .../opt/exec/execbuilder/testdata/subquery | 80 +++-- .../opt/exec/execbuilder/testdata/tpch_vec | 23 +- pkg/sql/opt/exec/execbuilder/testdata/udf | 60 ++-- pkg/sql/opt/memo/memo.go | 5 +- pkg/sql/opt/memo/memo_test.go | 6 + .../opt/memo/testdata/stats_quality/tpch/q15 | 239 +++++++------- pkg/sql/opt/norm/decorrelate_funcs.go | 23 +- pkg/sql/opt/norm/testdata/rules/decorrelate | 298 +++++++++++++++--- pkg/sql/opt/norm/testdata/rules/inline | 42 +-- pkg/sql/opt/norm/testdata/rules/join | 96 +++--- pkg/sql/opt/testutils/opttester/opt_tester.go | 1 + pkg/sql/opt/xform/testdata/external/tpch | 98 +++--- .../opt/xform/testdata/external/tpch-no-stats | 85 +++-- .../local_only_session_data.proto | 5 + pkg/sql/vars.go | 17 + 19 files changed, 671 insertions(+), 416 deletions(-) diff --git a/pkg/sql/exec_util.go b/pkg/sql/exec_util.go index 829995f3b8b6..4926d2698b61 100644 --- a/pkg/sql/exec_util.go +++ b/pkg/sql/exec_util.go @@ -3513,6 +3513,10 @@ func (m *sessionDataMutator) SetOptimizerAlwaysUseHistograms(val bool) { m.data.OptimizerAlwaysUseHistograms = val } +func (m *sessionDataMutator) SetOptimizerHoistUncorrelatedEqualitySubqueries(val bool) { + m.data.OptimizerHoistUncorrelatedEqualitySubqueries = val +} + func (m *sessionDataMutator) SetEnableCreateStatsUsingExtremes(val bool) { m.data.EnableCreateStatsUsingExtremes = val } diff --git a/pkg/sql/logictest/testdata/logic_test/information_schema b/pkg/sql/logictest/testdata/logic_test/information_schema index b538b43730ea..41ad97e9952a 100644 --- a/pkg/sql/logictest/testdata/logic_test/information_schema +++ b/pkg/sql/logictest/testdata/logic_test/information_schema @@ -5272,6 +5272,7 @@ on_update_rehome_row_enabled on opt_split_scan_limit 2048 optimizer on optimizer_always_use_histograms on +optimizer_hoist_uncorrelated_equality_subqueries on optimizer_use_forecasts on optimizer_use_histograms on optimizer_use_improved_disjunction_stats on diff --git a/pkg/sql/logictest/testdata/logic_test/pg_catalog b/pkg/sql/logictest/testdata/logic_test/pg_catalog index 5404b05c4fbd..30ab01634d5a 100644 --- a/pkg/sql/logictest/testdata/logic_test/pg_catalog +++ b/pkg/sql/logictest/testdata/logic_test/pg_catalog @@ -2759,6 +2759,7 @@ null_ordered_last off NULL on_update_rehome_row_enabled on NULL NULL NULL string opt_split_scan_limit 2048 NULL NULL NULL string optimizer_always_use_histograms on NULL NULL NULL string +optimizer_hoist_uncorrelated_equality_subqueries on NULL NULL NULL string optimizer_use_forecasts on NULL NULL NULL string optimizer_use_histograms on NULL NULL NULL string optimizer_use_improved_disjunction_stats on NULL NULL NULL string @@ -2913,6 +2914,7 @@ null_ordered_last off NULL on_update_rehome_row_enabled on NULL user NULL on on opt_split_scan_limit 2048 NULL user NULL 2048 2048 optimizer_always_use_histograms on NULL user NULL on on +optimizer_hoist_uncorrelated_equality_subqueries on NULL user NULL on on optimizer_use_forecasts on NULL user NULL on on optimizer_use_histograms on NULL user NULL on on optimizer_use_improved_disjunction_stats on NULL user NULL on on @@ -3067,6 +3069,7 @@ on_update_rehome_row_enabled NULL NULL NULL opt_split_scan_limit NULL NULL NULL NULL NULL optimizer NULL NULL NULL NULL NULL optimizer_always_use_histograms NULL NULL NULL NULL NULL +optimizer_hoist_uncorrelated_equality_subqueries NULL NULL NULL NULL NULL optimizer_use_forecasts NULL NULL NULL NULL NULL optimizer_use_histograms NULL NULL NULL NULL NULL optimizer_use_improved_disjunction_stats NULL NULL NULL NULL NULL diff --git a/pkg/sql/logictest/testdata/logic_test/show_source b/pkg/sql/logictest/testdata/logic_test/show_source index ee4eb0a6aa52..d30d7bb529a2 100644 --- a/pkg/sql/logictest/testdata/logic_test/show_source +++ b/pkg/sql/logictest/testdata/logic_test/show_source @@ -113,6 +113,7 @@ null_ordered_last off on_update_rehome_row_enabled on opt_split_scan_limit 2048 optimizer_always_use_histograms on +optimizer_hoist_uncorrelated_equality_subqueries on optimizer_use_forecasts on optimizer_use_histograms on optimizer_use_improved_disjunction_stats on diff --git a/pkg/sql/opt/exec/execbuilder/testdata/subquery b/pkg/sql/opt/exec/execbuilder/testdata/subquery index 6acffc7c9805..08cf07c3ab3b 100644 --- a/pkg/sql/opt/exec/execbuilder/testdata/subquery +++ b/pkg/sql/opt/exec/execbuilder/testdata/subquery @@ -121,64 +121,58 @@ vectorized: true • root │ columns: (a, b, c) │ -├── • filter +├── • project │ │ columns: (a, b, c) -│ │ estimated row count: 333 (missing stats) -│ │ filter: a = @S2 │ │ -│ └── • scan -│ columns: (a, b, c) -│ estimated row count: 1,000 (missing stats) -│ table: abc@abc_pkey -│ spans: FULL SCAN -│ -├── • subquery -│ │ id: @S1 -│ │ original sql: (SELECT * FROM abc WHERE c = (a + 3)) -│ │ exec mode: one row -│ │ -│ └── • render -│ │ columns: (column16) -│ │ render column16: true +│ └── • lookup join (inner) +│ │ columns: (any_not_null, a, b, c) +│ │ estimated row count: 1 (missing stats) +│ │ table: abc@abc_pkey +│ │ equality: (any_not_null) = (a) +│ │ equality cols are key │ │ -│ └── • limit -│ │ columns: (a, c) -│ │ count: 1 +│ └── • group (scalar) +│ │ columns: (any_not_null) +│ │ estimated row count: 1 (missing stats) +│ │ aggregate 0: any_not_null(a) │ │ -│ └── • filter -│ │ columns: (a, c) -│ │ estimated row count: 330 (missing stats) -│ │ filter: c = (a + 3) +│ └── • limit +│ │ columns: (a) +│ │ count: 1 │ │ -│ └── • scan -│ columns: (a, c) -│ estimated row count: 1,000 (missing stats) -│ table: abc@abc_pkey -│ spans: FULL SCAN (SOFT LIMIT) +│ └── • filter +│ │ columns: (a) +│ │ ordering: -a +│ │ estimated row count: 333 (missing stats) +│ │ filter: COALESCE(@S1, false) +│ │ +│ └── • revscan +│ columns: (a) +│ ordering: -a +│ estimated row count: 1,000 (missing stats) +│ table: abc@abc_pkey +│ spans: FULL SCAN (SOFT LIMIT) │ └── • subquery - │ id: @S2 - │ original sql: (SELECT max(a) FROM abc WHERE EXISTS (SELECT * FROM abc WHERE c = (a + 3))) + │ id: @S1 + │ original sql: (SELECT * FROM abc WHERE c = (a + 3)) │ exec mode: one row │ - └── • group (scalar) - │ columns: (any_not_null) - │ estimated row count: 1 (missing stats) - │ aggregate 0: any_not_null(a) + └── • render + │ columns: (column16) + │ render column16: true │ └── • limit - │ columns: (a) + │ columns: (a, c) │ count: 1 │ └── • filter - │ columns: (a) - │ ordering: -a - │ estimated row count: 333 (missing stats) - │ filter: COALESCE(@S1, false) + │ columns: (a, c) + │ estimated row count: 330 (missing stats) + │ filter: c = (a + 3) │ - └── • revscan - columns: (a) - ordering: -a + └── • scan + columns: (a, c) estimated row count: 1,000 (missing stats) table: abc@abc_pkey spans: FULL SCAN (SOFT LIMIT) diff --git a/pkg/sql/opt/exec/execbuilder/testdata/tpch_vec b/pkg/sql/opt/exec/execbuilder/testdata/tpch_vec index 6859b6dedc08..73c1a473fbaf 100644 --- a/pkg/sql/opt/exec/execbuilder/testdata/tpch_vec +++ b/pkg/sql/opt/exec/execbuilder/testdata/tpch_vec @@ -20848,17 +20848,20 @@ EXPLAIN (VEC) SELECT s_suppkey, s_name, s_address, s_phone, total_revenue FROM s ---- │ └ Node 1 - └ *colexecjoin.mergeJoinInnerOp - ├ *colfetcher.ColBatchScan + └ *rowexec.joinReader └ *colexec.sortOp - └ *colexecsel.selEQFloat64Float64Op - └ *colexecbase.castOpNullAny - └ *colexecbase.constNullOp - └ *colexec.hashAggregator - └ *colexecproj.projMultFloat64Float64Op - └ *colexecprojconst.projMinusFloat64ConstFloat64Op - └ *colfetcher.ColIndexJoin - └ *colfetcher.ColBatchScan + └ *colexecjoin.hashJoiner + ├ *colexec.hashAggregator + │ └ *colexecproj.projMultFloat64Float64Op + │ └ *colexecprojconst.projMinusFloat64ConstFloat64Op + │ └ *colfetcher.ColIndexJoin + │ └ *colfetcher.ColBatchScan + └ *colexec.orderedAggregator + └ *colexec.hashAggregator + └ *colexecproj.projMultFloat64Float64Op + └ *colexecprojconst.projMinusFloat64ConstFloat64Op + └ *colfetcher.ColIndexJoin + └ *colfetcher.ColBatchScan statement ok DROP VIEW revenue0 diff --git a/pkg/sql/opt/exec/execbuilder/testdata/udf b/pkg/sql/opt/exec/execbuilder/testdata/udf index 71ac848d8b33..2fed5279a3d1 100644 --- a/pkg/sql/opt/exec/execbuilder/testdata/udf +++ b/pkg/sql/opt/exec/execbuilder/testdata/udf @@ -116,40 +116,40 @@ EXPLAIN (VERBOSE) SELECT * FROM sub3 WHERE sub_fn() = 3 AND (SELECT max(a) FROM distribution: local vectorized: true · -• root +• project │ columns: (a) │ -├── • filter -│ │ columns: (a) -│ │ estimated row count: 111 (missing stats) -│ │ filter: (sub_fn() = 3) AND (a = @S1) -│ │ -│ └── • scan -│ columns: (a) -│ estimated row count: 1,000 (missing stats) -│ table: sub3@sub3_pkey -│ spans: FULL SCAN -│ -└── • subquery - │ id: @S1 - │ original sql: (SELECT max(a) FROM sub2) - │ exec mode: one row +└── • lookup join (inner) + │ columns: (any_not_null, a) + │ estimated row count: 1 (missing stats) + │ table: sub3@sub3_pkey + │ equality: (any_not_null) = (a) + │ equality cols are key + │ pred: sub_fn() = 3 │ - └── • group (scalar) + └── • filter │ columns: (any_not_null) - │ estimated row count: 1 (missing stats) - │ aggregate 0: any_not_null(a) + │ estimated row count: 0 (missing stats) + │ filter: sub_fn() = 3 │ - └── • revscan - columns: (a) - estimated row count: 1 (missing stats) - table: sub2@sub2_pkey - spans: LIMITED SCAN - limit: 1 + └── • group (scalar) + │ columns: (any_not_null) + │ estimated row count: 1 (missing stats) + │ aggregate 0: any_not_null(a) + │ + └── • revscan + columns: (a) + estimated row count: 1 (missing stats) + table: sub2@sub2_pkey + spans: LIMITED SCAN + limit: 1 + +statement ok +CREATE FUNCTION sub_fn_lt() RETURNS INT LANGUAGE SQL AS 'SELECT a FROM sub1 WHERE a < (SELECT max(a) FROM sub2)' # The uncorrelated subquery in the UDF body is executed only once. query T kvtrace -SELECT sub_fn() +SELECT sub_fn_lt() ---- Scan /Table/112/{1-2} Scan /Table/113/{1-2} @@ -157,7 +157,7 @@ Scan /Table/113/{1-2} # The uncorrelated subquery in the UDF body is executed only once per row # produced by generate_series. query T kvtrace -SELECT sub_fn() FROM generate_series(1, 3) +SELECT sub_fn_lt() FROM generate_series(1, 3) ---- Scan /Table/112/{1-2} Scan /Table/113/{1-2} @@ -174,12 +174,12 @@ CREATE FUNCTION sub_fn2() RETURNS INT LANGUAGE SQL AS 'SELECT a FROM sub1 WHERE query T kvtrace SELECT sub_fn2() FROM generate_series(1, 3) ---- -Scan /Table/112/{1-2} Scan /Table/113/1/30/0 -Scan /Table/112/{1-2} +Scan /Table/112/1/30/0 Scan /Table/113/1/30/0 -Scan /Table/112/{1-2} +Scan /Table/112/1/30/0 Scan /Table/113/1/30/0 +Scan /Table/112/1/30/0 statement ok CREATE FUNCTION sub_fn3() RETURNS INT LANGUAGE SQL AS 'SELECT a FROM sub1 WHERE EXISTS (SELECT a FROM sub2 WHERE a = 30)' diff --git a/pkg/sql/opt/memo/memo.go b/pkg/sql/opt/memo/memo.go index b592288b8e19..427fb5f6bc6e 100644 --- a/pkg/sql/opt/memo/memo.go +++ b/pkg/sql/opt/memo/memo.go @@ -163,6 +163,7 @@ type Memo struct { useLimitOrderingForStreamingGroupBy bool useImprovedSplitDisjunctionForJoins bool alwaysUseHistograms bool + hoistUncorrelatedEqualitySubqueries bool // curRank is the highest currently in-use scalar expression rank. curRank opt.ScalarRank @@ -221,6 +222,7 @@ func (m *Memo) Init(ctx context.Context, evalCtx *eval.Context) { useLimitOrderingForStreamingGroupBy: evalCtx.SessionData().OptimizerUseLimitOrderingForStreamingGroupBy, useImprovedSplitDisjunctionForJoins: evalCtx.SessionData().OptimizerUseImprovedSplitDisjunctionForJoins, alwaysUseHistograms: evalCtx.SessionData().OptimizerAlwaysUseHistograms, + hoistUncorrelatedEqualitySubqueries: evalCtx.SessionData().OptimizerHoistUncorrelatedEqualitySubqueries, } m.metadata.Init() m.logPropsBuilder.init(ctx, evalCtx, m) @@ -362,7 +364,8 @@ func (m *Memo) IsStale( m.useImprovedDisjunctionStats != evalCtx.SessionData().OptimizerUseImprovedDisjunctionStats || m.useLimitOrderingForStreamingGroupBy != evalCtx.SessionData().OptimizerUseLimitOrderingForStreamingGroupBy || m.useImprovedSplitDisjunctionForJoins != evalCtx.SessionData().OptimizerUseImprovedSplitDisjunctionForJoins || - m.alwaysUseHistograms != evalCtx.SessionData().OptimizerAlwaysUseHistograms { + m.alwaysUseHistograms != evalCtx.SessionData().OptimizerAlwaysUseHistograms || + m.hoistUncorrelatedEqualitySubqueries != evalCtx.SessionData().OptimizerHoistUncorrelatedEqualitySubqueries { return true, nil } diff --git a/pkg/sql/opt/memo/memo_test.go b/pkg/sql/opt/memo/memo_test.go index 22497c47dae3..430c19bad99f 100644 --- a/pkg/sql/opt/memo/memo_test.go +++ b/pkg/sql/opt/memo/memo_test.go @@ -354,6 +354,12 @@ func TestMemoIsStale(t *testing.T) { evalCtx.SessionData().OptimizerAlwaysUseHistograms = false notStale() + // Stale optimizer_hoist_uncorrelated_equality_subqueries. + evalCtx.SessionData().OptimizerHoistUncorrelatedEqualitySubqueries = true + stale() + evalCtx.SessionData().OptimizerHoistUncorrelatedEqualitySubqueries = false + notStale() + // Stale data sources and schema. Create new catalog so that data sources are // recreated and can be modified independently. catalog = testcat.New() diff --git a/pkg/sql/opt/memo/testdata/stats_quality/tpch/q15 b/pkg/sql/opt/memo/testdata/stats_quality/tpch/q15 index 300610f61813..9b7275f1243d 100644 --- a/pkg/sql/opt/memo/testdata/stats_quality/tpch/q15 +++ b/pkg/sql/opt/memo/testdata/stats_quality/tpch/q15 @@ -55,52 +55,38 @@ project ├── save-table-name: q15_project_1 ├── columns: s_suppkey:1(int!null) s_name:2(char!null) s_address:3(varchar!null) s_phone:5(char!null) total_revenue:29(float!null) ├── immutable - ├── stats: [rows=3333.333, distinct(1)=3306.67, null(1)=0, distinct(2)=2834.36, null(2)=0, distinct(3)=2834.81, null(3)=0, distinct(5)=2834.81, null(5)=0, distinct(29)=2100.04, null(29)=0] + ├── stats: [rows=1.008065, distinct(1)=1, null(1)=0, distinct(2)=1.00806, null(2)=0, distinct(3)=1.00806, null(3)=0, distinct(5)=1.00806, null(5)=0, distinct(29)=0.635094, null(29)=0] ├── key: (1) - ├── fd: (1)-->(2,3,5,29) - ├── ordering: +1 - └── inner-join (merge) - ├── save-table-name: q15_merge_join_2 - ├── columns: s_suppkey:1(int!null) s_name:2(char!null) s_address:3(varchar!null) s_phone:5(char!null) l_suppkey:12(int!null) sum:29(float!null) - ├── left ordering: +1 - ├── right ordering: +12 + ├── fd: ()-->(29), (1)-->(2,3,5) + ├── ordering: +1 opt(29) [actual: +1] + └── inner-join (lookup supplier) + ├── save-table-name: q15_lookup_join_2 + ├── columns: s_suppkey:1(int!null) s_name:2(char!null) s_address:3(varchar!null) s_phone:5(char!null) l_suppkey:12(int!null) sum:29(float!null) max:50(float!null) + ├── key columns: [12] = [1] + ├── lookup columns are key ├── immutable - ├── stats: [rows=3333.333, distinct(1)=3306.67, null(1)=0, distinct(2)=2834.36, null(2)=0, distinct(3)=2834.81, null(3)=0, distinct(5)=2834.81, null(5)=0, distinct(12)=3306.67, null(12)=0, distinct(29)=2100.04, null(29)=0] + ├── stats: [rows=1.008065, distinct(1)=1, null(1)=0, distinct(2)=1.00806, null(2)=0, distinct(3)=1.00806, null(3)=0, distinct(5)=1.00806, null(5)=0, distinct(12)=1, null(12)=0, distinct(29)=0.635094, null(29)=0, distinct(50)=0.635094, null(50)=0] ├── key: (12) - ├── fd: (1)-->(2,3,5), (12)-->(29), (1)==(12), (12)==(1) - ├── ordering: +(1|12) [actual: +1] - ├── scan supplier - │ ├── save-table-name: q15_scan_3 - │ ├── columns: s_suppkey:1(int!null) s_name:2(char!null) s_address:3(varchar!null) s_phone:5(char!null) - │ ├── stats: [rows=10000, distinct(1)=9920, null(1)=0, distinct(2)=9990, null(2)=0, distinct(3)=10000, null(3)=0, distinct(5)=10000, null(5)=0] - │ │ histogram(1)= 0 0 0 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 49 1 50 1 50 1 50 1 50 1 50 1 50 1 50 1 50 1 50 1 50 1 50 1 50 1 50 1 50 1 50 1 50 1 50 1 50 1 50 1 50 1 50 1 50 1 50 1 50 1 50 1 50 1 50 1 50 1 50 1 50 1 50 1 50 1 50 1 50 1 50 1 50 1 50 1 50 1 50 1 50 1 50 1 50 1 50 1 50 1 50 1 50 1 50 1 50 1 50 1 0 0 - │ │ <--- -9223372036854775808 --- 1 ---- 51 ---- 101 ---- 151 ---- 201 ---- 251 ---- 301 ---- 351 ---- 401 ---- 451 ---- 501 ---- 551 ---- 601 ---- 651 ---- 701 ---- 751 ---- 801 ---- 851 ---- 901 ---- 951 ---- 1001 ---- 1051 ---- 1101 ---- 1151 ---- 1201 ---- 1251 ---- 1301 ---- 1351 ---- 1401 ---- 1451 ---- 1501 ---- 1551 ---- 1601 ---- 1651 ---- 1701 ---- 1751 ---- 1801 ---- 1851 ---- 1901 ---- 1951 ---- 2001 ---- 2051 ---- 2101 ---- 2151 ---- 2201 ---- 2251 ---- 2301 ---- 2351 ---- 2401 ---- 2451 ---- 2501 ---- 2551 ---- 2601 ---- 2651 ---- 2701 ---- 2751 ---- 2801 ---- 2851 ---- 2901 ---- 2951 ---- 3001 ---- 3051 ---- 3101 ---- 3151 ---- 3201 ---- 3251 ---- 3301 ---- 3351 ---- 3401 ---- 3451 ---- 3501 ---- 3551 ---- 3601 ---- 3651 ---- 3701 ---- 3751 ---- 3801 ---- 3851 ---- 3901 ---- 3951 ---- 4001 ---- 4051 ---- 4101 ---- 4151 ---- 4201 ---- 4251 ---- 4301 ---- 4351 ---- 4401 ---- 4451 ---- 4501 ---- 4551 ---- 4601 ---- 4651 ---- 4701 ---- 4751 ---- 4801 ---- 4851 ---- 4901 ---- 4951 ---- 5001 ---- 5051 ---- 5101 ---- 5151 ---- 5201 ---- 5251 ---- 5301 ---- 5351 ---- 5401 ---- 5451 ---- 5501 ---- 5551 ---- 5601 ---- 5651 ---- 5701 ---- 5751 ---- 5801 ---- 5851 ---- 5901 ---- 5951 ---- 6001 ---- 6051 ---- 6101 ---- 6151 ---- 6201 ---- 6251 ---- 6301 ---- 6351 ---- 6401 ---- 6451 ---- 6501 ---- 6551 ---- 6601 ---- 6651 ---- 6701 ---- 6751 ---- 6801 ---- 6851 ---- 6901 ---- 6951 ---- 7001 ---- 7051 ---- 7101 ---- 7151 ---- 7201 ---- 7251 ---- 7301 ---- 7351 ---- 7401 ---- 7451 ---- 7501 ---- 7552 ---- 7603 ---- 7654 ---- 7705 ---- 7756 ---- 7807 ---- 7858 ---- 7909 ---- 7960 ---- 8011 ---- 8062 ---- 8113 ---- 8164 ---- 8215 ---- 8266 ---- 8317 ---- 8368 ---- 8419 ---- 8470 ---- 8521 ---- 8572 ---- 8623 ---- 8674 ---- 8725 ---- 8776 ---- 8827 ---- 8878 ---- 8929 ---- 8980 ---- 9031 ---- 9082 ---- 9133 ---- 9184 ---- 9235 ---- 9286 ---- 9337 ---- 9388 ---- 9439 ---- 9490 ---- 9541 ---- 9592 ---- 9643 ---- 9694 ---- 9745 ---- 9796 ---- 9847 ---- 9898 ---- 9949 ---- 10000 --- 9223372036854775807 - │ │ histogram(2)= 0 1 9998 1 - │ │ <--- 'Supplier#000000001' ------ 'Supplier#000010000' - │ │ histogram(3)= 0 1 9998 1 - │ │ <--- ' 9aW1wwnBJJPnCx,nox0MA48Y0zpI1IeVfYZ' ------ 'zzfDhdtZcvmVzA8rNFU,Yctj1zBN' - │ │ histogram(5)= 0 1 9998 1 - │ │ <--- '10-102-116-6785' ------ '34-998-900-4911' - │ ├── key: (1) - │ ├── fd: (1)-->(2,3,5) - │ └── ordering: +1 + ├── fd: ()-->(29,50), (1)-->(2,3,5), (29)==(50), (50)==(29), (1)==(12), (12)==(1) + ├── ordering: +(1|12) opt(29,50) [actual: +12] ├── sort - │ ├── save-table-name: q15_sort_4 - │ ├── columns: l_suppkey:12(int!null) sum:29(float!null) + │ ├── save-table-name: q15_sort_3 + │ ├── columns: l_suppkey:12(int!null) sum:29(float!null) max:50(float!null) │ ├── immutable - │ ├── stats: [rows=3306.667, distinct(12)=3306.67, null(12)=0, distinct(29)=3306.67, null(29)=0] + │ ├── stats: [rows=1, distinct(12)=1, null(12)=0, distinct(29)=1, null(29)=0, distinct(50)=1, null(50)=0] │ ├── key: (12) - │ ├── fd: (12)-->(29) - │ ├── ordering: +12 - │ └── select - │ ├── save-table-name: q15_select_5 - │ ├── columns: l_suppkey:12(int!null) sum:29(float!null) + │ ├── fd: ()-->(29,50), (29)==(50), (50)==(29) + │ ├── ordering: +12 opt(29,50) [actual: +12] + │ └── inner-join (hash) + │ ├── save-table-name: q15_inner_join_4 + │ ├── columns: l_suppkey:12(int!null) sum:29(float!null) max:50(float!null) + │ ├── multiplicity: left-rows(zero-or-one), right-rows(zero-or-more) │ ├── immutable - │ ├── stats: [rows=3306.667, distinct(12)=3306.67, null(12)=0, distinct(29)=3306.67, null(29)=0] + │ ├── stats: [rows=1, distinct(12)=1, null(12)=0, distinct(29)=1, null(29)=0, distinct(50)=1, null(50)=0] │ ├── key: (12) - │ ├── fd: (12)-->(29) + │ ├── fd: ()-->(29,50), (29)==(50), (50)==(29) │ ├── group-by (hash) - │ │ ├── save-table-name: q15_group_by_6 + │ │ ├── save-table-name: q15_group_by_5 │ │ ├── columns: l_suppkey:12(int!null) sum:29(float!null) │ │ ├── grouping columns: l_suppkey:12(int!null) │ │ ├── immutable @@ -108,18 +94,18 @@ project │ │ ├── key: (12) │ │ ├── fd: (12)-->(29) │ │ ├── project - │ │ │ ├── save-table-name: q15_project_7 + │ │ │ ├── save-table-name: q15_project_6 │ │ │ ├── columns: column28:28(float!null) l_suppkey:12(int!null) │ │ │ ├── immutable │ │ │ ├── stats: [rows=238668.4, distinct(12)=9920, null(12)=0, distinct(28)=238668, null(28)=0] │ │ │ ├── index-join lineitem - │ │ │ │ ├── save-table-name: q15_index_join_8 + │ │ │ │ ├── save-table-name: q15_index_join_7 │ │ │ │ ├── columns: l_suppkey:12(int!null) l_extendedprice:15(float!null) l_discount:16(float!null) l_shipdate:20(date!null) │ │ │ │ ├── stats: [rows=238668.4, distinct(12)=9920, null(12)=0, distinct(15)=214148, null(15)=0, distinct(16)=11, null(16)=0, distinct(20)=91, null(20)=0, distinct(15,16)=238668, null(15,16)=0] │ │ │ │ │ histogram(20)= 0 0 2820.6 1200 28206 600 27606 3601 25805 3001 25805 3001 27606 2400 26405 3001 25805 4801 24004 3000.6 │ │ │ │ │ <--- '1995-12-31' -------- '1996-01-02' ------- '1996-01-14' ------- '1996-01-25' ------- '1996-02-07' ------- '1996-02-18' ------- '1996-02-28' ------- '1996-03-12' ------- '1996-03-22' ------- '1996-03-31' │ │ │ │ └── scan lineitem@l_sd - │ │ │ │ ├── save-table-name: q15_scan_9 + │ │ │ │ ├── save-table-name: q15_scan_8 │ │ │ │ ├── columns: l_orderkey:10(int!null) l_linenumber:13(int!null) l_shipdate:20(date!null) │ │ │ │ ├── constraint: /20/10/13: [/'1996-01-01' - /'1996-03-31'] │ │ │ │ ├── stats: [rows=238668.4, distinct(10)=225118, null(10)=0, distinct(13)=7, null(13)=0, distinct(20)=91, null(20)=0] @@ -136,58 +122,56 @@ project │ │ └── aggregations │ │ └── sum [as=sum:29, type=float, outer=(28)] │ │ └── column28:28 [type=float] + │ ├── scalar-group-by + │ │ ├── save-table-name: q15_scalar_group_by_9 + │ │ ├── columns: max:50(float) + │ │ ├── cardinality: [1 - 1] + │ │ ├── immutable + │ │ ├── stats: [rows=1, distinct(50)=1, null(50)=0] + │ │ ├── key: () + │ │ ├── fd: ()-->(50) + │ │ ├── group-by (hash) + │ │ │ ├── save-table-name: q15_group_by_10 + │ │ │ ├── columns: l_suppkey:32(int!null) sum:49(float!null) + │ │ │ ├── grouping columns: l_suppkey:32(int!null) + │ │ │ ├── immutable + │ │ │ ├── stats: [rows=9920, distinct(32)=9920, null(32)=0, distinct(49)=9920, null(49)=0] + │ │ │ ├── key: (32) + │ │ │ ├── fd: (32)-->(49) + │ │ │ ├── project + │ │ │ │ ├── save-table-name: q15_project_11 + │ │ │ │ ├── columns: column48:48(float!null) l_suppkey:32(int!null) + │ │ │ │ ├── immutable + │ │ │ │ ├── stats: [rows=238668.4, distinct(32)=9920, null(32)=0, distinct(48)=238668, null(48)=0] + │ │ │ │ ├── index-join lineitem + │ │ │ │ │ ├── save-table-name: q15_index_join_12 + │ │ │ │ │ ├── columns: l_suppkey:32(int!null) l_extendedprice:35(float!null) l_discount:36(float!null) l_shipdate:40(date!null) + │ │ │ │ │ ├── stats: [rows=238668.4, distinct(32)=9920, null(32)=0, distinct(35)=214148, null(35)=0, distinct(36)=11, null(36)=0, distinct(40)=91, null(40)=0, distinct(35,36)=238668, null(35,36)=0] + │ │ │ │ │ │ histogram(40)= 0 0 2820.6 1200 28206 600 27606 3601 25805 3001 25805 3001 27606 2400 26405 3001 25805 4801 24004 3000.6 + │ │ │ │ │ │ <--- '1995-12-31' -------- '1996-01-02' ------- '1996-01-14' ------- '1996-01-25' ------- '1996-02-07' ------- '1996-02-18' ------- '1996-02-28' ------- '1996-03-12' ------- '1996-03-22' ------- '1996-03-31' + │ │ │ │ │ └── scan lineitem@l_sd + │ │ │ │ │ ├── save-table-name: q15_scan_13 + │ │ │ │ │ ├── columns: l_orderkey:30(int!null) l_linenumber:33(int!null) l_shipdate:40(date!null) + │ │ │ │ │ ├── constraint: /40/30/33: [/'1996-01-01' - /'1996-03-31'] + │ │ │ │ │ ├── stats: [rows=238668.4, distinct(30)=225118, null(30)=0, distinct(33)=7, null(33)=0, distinct(40)=91, null(40)=0] + │ │ │ │ │ │ histogram(30)= 0 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1145.6 47.724 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1145.6 47.724 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1145.6 47.724 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1193.3 23.862 1193.3 23.862 1193.3 23.862 1193.3 23.862 1193.3 23.862 1193.3 23.862 1193.3 23.862 1193.3 23.862 1193.3 23.862 1193.3 23.862 1193.3 23.862 1193.3 23.862 1193.3 23.862 1193.3 23.862 1193.3 23.862 1193.3 23.862 1193.3 23.862 1193.3 23.862 1193.3 23.862 1193.3 23.862 1193.3 23.862 1193.3 23.862 1193.3 23.862 1193.3 23.862 1193.3 23.862 1193.3 23.862 1193.3 23.862 1193.3 23.862 1193.3 23.862 1193.3 23.862 1193.3 23.862 1193.3 23.862 1193.3 23.862 1193.3 23.862 1193.3 23.862 1193.3 23.862 1193.3 23.862 1193.3 23.862 1193.3 23.862 1193.3 23.862 1193.3 23.862 1193.3 23.862 1193.3 23.862 1193.3 23.862 1193.3 23.862 1193.3 23.862 1193.3 23.862 1193.3 23.862 1193.3 23.862 + │ │ │ │ │ │ <--- 197 --------- 23686 -------- 53253 -------- 90435 -------- 121730 -------- 153280 -------- 175456 -------- 208548 -------- 242209 -------- 273057 -------- 296640 -------- 330307 -------- 360999 -------- 386307 -------- 420225 -------- 450050 -------- 477795 -------- 504711 -------- 533153 -------- 556672 -------- 582243 -------- 613729 -------- 646117 -------- 675840 -------- 706048 -------- 733063 -------- 769282 -------- 793922 -------- 820357 -------- 849536 -------- 875719 -------- 905028 -------- 940643 -------- 968355 -------- 998721 -------- 1023621 -------- 1059424 -------- 1084932 -------- 1115553 -------- 1139363 -------- 1167361 -------- 1194400 -------- 1225984 -------- 1253861 -------- 1281633 -------- 1304999 -------- 1336355 -------- 1370759 -------- 1400832 -------- 1434085 -------- 1458852 -------- 1491427 -------- 1525120 -------- 1555205 -------- 1591300 -------- 1619426 -------- 1651458 -------- 1682950 -------- 1711399 -------- 1747591 -------- 1787205 -------- 1822240 -------- 1856163 -------- 1886915 -------- 1910949 -------- 1947202 -------- 1974311 -------- 2009286 -------- 2044034 -------- 2079104 -------- 2103488 -------- 2134657 -------- 2164293 -------- 2204514 -------- 2230823 -------- 2265253 -------- 2289826 -------- 2329539 -------- 2364455 -------- 2393507 -------- 2414628 -------- 2440228 -------- 2465255 -------- 2489568 -------- 2520900 -------- 2554919 -------- 2583333 -------- 2612966 -------- 2644833 -------- 2667362 -------- 2702784 -------- 2727394 -------- 2759748 -------- 2794531 -------- 2822214 -------- 2846624 -------- 2883748 -------- 2919586 -------- 2951908 -------- 2980068 -------- 3014726 -------- 3050725 -------- 3081028 -------- 3113351 -------- 3150243 -------- 3185669 -------- 3214311 -------- 3241281 -------- 3275748 -------- 3303232 -------- 3339559 -------- 3370627 -------- 3393664 -------- 3435265 -------- 3464581 -------- 3489026 -------- 3516096 -------- 3548480 -------- 3587015 -------- 3611239 -------- 3638724 -------- 3668641 -------- 3695751 -------- 3729636 -------- 3751523 -------- 3784608 -------- 3815715 -------- 3848608 -------- 3881184 -------- 3908738 -------- 3940002 -------- 3966176 -------- 4001984 -------- 4035687 -------- 4065283 -------- 4092834 -------- 4133062 -------- 4160613 -------- 4196421 -------- 4223713 -------- 4254788 -------- 4291040 -------- 4313664 -------- 4342823 -------- 4369952 -------- 4391684 -------- 4419040 -------- 4449921 -------- 4471781 -------- 4506210 -------- 4538176 -------- 4571297 -------- 4601121 -------- 4630887 -------- 4657476 -------- 4684803 -------- 4714566 -------- 4744070 -------- 4776385 -------- 4807777 -------- 4839491 -------- 4873953 -------- 4902245 -------- 4936263 -------- 4970721 -------- 5003140 -------- 5029729 -------- 5059010 -------- 5087521 -------- 5121093 -------- 5150405 -------- 5178375 -------- 5203683 -------- 5234531 -------- 5268195 -------- 5300004 -------- 5331558 -------- 5362178 -------- 5385762 -------- 5418498 -------- 5445762 -------- 5483109 -------- 5514561 -------- 5542052 -------- 5569572 -------- 5596102 -------- 5622401 -------- 5652194 -------- 5671362 -------- 5699591 -------- 5727136 -------- 5753284 -------- 5780742 -------- 5809189 -------- 5836545 -------- 5864454 -------- 5894917 -------- 5933825 -------- 5968933 -------- 5999590 + │ │ │ │ │ │ histogram(33)= 0 59166 0 53247 0 41862 0 34273 0 25323 0 16516 0 8281.8 + │ │ │ │ │ │ <---- 1 ----- 2 ----- 3 ----- 4 ----- 5 ----- 6 ----- 7 -- + │ │ │ │ │ │ histogram(40)= 0 0 2820.6 1200 28206 600 27606 3601 25805 3001 25805 3001 27606 2400 26405 3001 25805 4801 24004 3000.6 + │ │ │ │ │ │ <--- '1995-12-31' -------- '1996-01-02' ------- '1996-01-14' ------- '1996-01-25' ------- '1996-02-07' ------- '1996-02-18' ------- '1996-02-28' ------- '1996-03-12' ------- '1996-03-22' ------- '1996-03-31' + │ │ │ │ │ ├── key: (30,33) + │ │ │ │ │ └── fd: (30,33)-->(40) + │ │ │ │ └── projections + │ │ │ │ └── l_extendedprice:35 * (1.0 - l_discount:36) [as=column48:48, type=float, outer=(35,36), immutable] + │ │ │ └── aggregations + │ │ │ └── sum [as=sum:49, type=float, outer=(48)] + │ │ │ └── column48:48 [type=float] + │ │ └── aggregations + │ │ └── max [as=max:50, type=float, outer=(49)] + │ │ └── sum:49 [type=float] │ └── filters - │ └── eq [type=bool, outer=(29), immutable, subquery, constraints=(/29: (/NULL - ])] - │ ├── sum:29 [type=float] - │ └── subquery [type=float] - │ └── scalar-group-by - │ ├── save-table-name: q15_scalar_group_by_10 - │ ├── columns: max:50(float) - │ ├── cardinality: [1 - 1] - │ ├── immutable - │ ├── stats: [rows=1, distinct(50)=1, null(50)=0] - │ ├── key: () - │ ├── fd: ()-->(50) - │ ├── group-by (hash) - │ │ ├── save-table-name: q15_group_by_11 - │ │ ├── columns: l_suppkey:32(int!null) sum:49(float!null) - │ │ ├── grouping columns: l_suppkey:32(int!null) - │ │ ├── immutable - │ │ ├── stats: [rows=9920, distinct(32)=9920, null(32)=0, distinct(49)=9920, null(49)=0] - │ │ ├── key: (32) - │ │ ├── fd: (32)-->(49) - │ │ ├── project - │ │ │ ├── save-table-name: q15_project_12 - │ │ │ ├── columns: column48:48(float!null) l_suppkey:32(int!null) - │ │ │ ├── immutable - │ │ │ ├── stats: [rows=238668.4, distinct(32)=9920, null(32)=0, distinct(48)=238668, null(48)=0] - │ │ │ ├── index-join lineitem - │ │ │ │ ├── save-table-name: q15_index_join_13 - │ │ │ │ ├── columns: l_suppkey:32(int!null) l_extendedprice:35(float!null) l_discount:36(float!null) l_shipdate:40(date!null) - │ │ │ │ ├── stats: [rows=238668.4, distinct(32)=9920, null(32)=0, distinct(35)=214148, null(35)=0, distinct(36)=11, null(36)=0, distinct(40)=91, null(40)=0, distinct(35,36)=238668, null(35,36)=0] - │ │ │ │ │ histogram(40)= 0 0 2820.6 1200 28206 600 27606 3601 25805 3001 25805 3001 27606 2400 26405 3001 25805 4801 24004 3000.6 - │ │ │ │ │ <--- '1995-12-31' -------- '1996-01-02' ------- '1996-01-14' ------- '1996-01-25' ------- '1996-02-07' ------- '1996-02-18' ------- '1996-02-28' ------- '1996-03-12' ------- '1996-03-22' ------- '1996-03-31' - │ │ │ │ └── scan lineitem@l_sd - │ │ │ │ ├── save-table-name: q15_scan_14 - │ │ │ │ ├── columns: l_orderkey:30(int!null) l_linenumber:33(int!null) l_shipdate:40(date!null) - │ │ │ │ ├── constraint: /40/30/33: [/'1996-01-01' - /'1996-03-31'] - │ │ │ │ ├── stats: [rows=238668.4, distinct(30)=225118, null(30)=0, distinct(33)=7, null(33)=0, distinct(40)=91, null(40)=0] - │ │ │ │ │ histogram(30)= 0 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1145.6 47.724 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1145.6 47.724 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1145.6 47.724 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1169.5 23.862 1193.3 23.862 1193.3 23.862 1193.3 23.862 1193.3 23.862 1193.3 23.862 1193.3 23.862 1193.3 23.862 1193.3 23.862 1193.3 23.862 1193.3 23.862 1193.3 23.862 1193.3 23.862 1193.3 23.862 1193.3 23.862 1193.3 23.862 1193.3 23.862 1193.3 23.862 1193.3 23.862 1193.3 23.862 1193.3 23.862 1193.3 23.862 1193.3 23.862 1193.3 23.862 1193.3 23.862 1193.3 23.862 1193.3 23.862 1193.3 23.862 1193.3 23.862 1193.3 23.862 1193.3 23.862 1193.3 23.862 1193.3 23.862 1193.3 23.862 1193.3 23.862 1193.3 23.862 1193.3 23.862 1193.3 23.862 1193.3 23.862 1193.3 23.862 1193.3 23.862 1193.3 23.862 1193.3 23.862 1193.3 23.862 1193.3 23.862 1193.3 23.862 1193.3 23.862 1193.3 23.862 1193.3 23.862 1193.3 23.862 - │ │ │ │ │ <--- 197 --------- 23686 -------- 53253 -------- 90435 -------- 121730 -------- 153280 -------- 175456 -------- 208548 -------- 242209 -------- 273057 -------- 296640 -------- 330307 -------- 360999 -------- 386307 -------- 420225 -------- 450050 -------- 477795 -------- 504711 -------- 533153 -------- 556672 -------- 582243 -------- 613729 -------- 646117 -------- 675840 -------- 706048 -------- 733063 -------- 769282 -------- 793922 -------- 820357 -------- 849536 -------- 875719 -------- 905028 -------- 940643 -------- 968355 -------- 998721 -------- 1023621 -------- 1059424 -------- 1084932 -------- 1115553 -------- 1139363 -------- 1167361 -------- 1194400 -------- 1225984 -------- 1253861 -------- 1281633 -------- 1304999 -------- 1336355 -------- 1370759 -------- 1400832 -------- 1434085 -------- 1458852 -------- 1491427 -------- 1525120 -------- 1555205 -------- 1591300 -------- 1619426 -------- 1651458 -------- 1682950 -------- 1711399 -------- 1747591 -------- 1787205 -------- 1822240 -------- 1856163 -------- 1886915 -------- 1910949 -------- 1947202 -------- 1974311 -------- 2009286 -------- 2044034 -------- 2079104 -------- 2103488 -------- 2134657 -------- 2164293 -------- 2204514 -------- 2230823 -------- 2265253 -------- 2289826 -------- 2329539 -------- 2364455 -------- 2393507 -------- 2414628 -------- 2440228 -------- 2465255 -------- 2489568 -------- 2520900 -------- 2554919 -------- 2583333 -------- 2612966 -------- 2644833 -------- 2667362 -------- 2702784 -------- 2727394 -------- 2759748 -------- 2794531 -------- 2822214 -------- 2846624 -------- 2883748 -------- 2919586 -------- 2951908 -------- 2980068 -------- 3014726 -------- 3050725 -------- 3081028 -------- 3113351 -------- 3150243 -------- 3185669 -------- 3214311 -------- 3241281 -------- 3275748 -------- 3303232 -------- 3339559 -------- 3370627 -------- 3393664 -------- 3435265 -------- 3464581 -------- 3489026 -------- 3516096 -------- 3548480 -------- 3587015 -------- 3611239 -------- 3638724 -------- 3668641 -------- 3695751 -------- 3729636 -------- 3751523 -------- 3784608 -------- 3815715 -------- 3848608 -------- 3881184 -------- 3908738 -------- 3940002 -------- 3966176 -------- 4001984 -------- 4035687 -------- 4065283 -------- 4092834 -------- 4133062 -------- 4160613 -------- 4196421 -------- 4223713 -------- 4254788 -------- 4291040 -------- 4313664 -------- 4342823 -------- 4369952 -------- 4391684 -------- 4419040 -------- 4449921 -------- 4471781 -------- 4506210 -------- 4538176 -------- 4571297 -------- 4601121 -------- 4630887 -------- 4657476 -------- 4684803 -------- 4714566 -------- 4744070 -------- 4776385 -------- 4807777 -------- 4839491 -------- 4873953 -------- 4902245 -------- 4936263 -------- 4970721 -------- 5003140 -------- 5029729 -------- 5059010 -------- 5087521 -------- 5121093 -------- 5150405 -------- 5178375 -------- 5203683 -------- 5234531 -------- 5268195 -------- 5300004 -------- 5331558 -------- 5362178 -------- 5385762 -------- 5418498 -------- 5445762 -------- 5483109 -------- 5514561 -------- 5542052 -------- 5569572 -------- 5596102 -------- 5622401 -------- 5652194 -------- 5671362 -------- 5699591 -------- 5727136 -------- 5753284 -------- 5780742 -------- 5809189 -------- 5836545 -------- 5864454 -------- 5894917 -------- 5933825 -------- 5968933 -------- 5999590 - │ │ │ │ │ histogram(33)= 0 59166 0 53247 0 41862 0 34273 0 25323 0 16516 0 8281.8 - │ │ │ │ │ <---- 1 ----- 2 ----- 3 ----- 4 ----- 5 ----- 6 ----- 7 -- - │ │ │ │ │ histogram(40)= 0 0 2820.6 1200 28206 600 27606 3601 25805 3001 25805 3001 27606 2400 26405 3001 25805 4801 24004 3000.6 - │ │ │ │ │ <--- '1995-12-31' -------- '1996-01-02' ------- '1996-01-14' ------- '1996-01-25' ------- '1996-02-07' ------- '1996-02-18' ------- '1996-02-28' ------- '1996-03-12' ------- '1996-03-22' ------- '1996-03-31' - │ │ │ │ ├── key: (30,33) - │ │ │ │ └── fd: (30,33)-->(40) - │ │ │ └── projections - │ │ │ └── l_extendedprice:35 * (1.0 - l_discount:36) [as=column48:48, type=float, outer=(35,36), immutable] - │ │ └── aggregations - │ │ └── sum [as=sum:49, type=float, outer=(48)] - │ │ └── column48:48 [type=float] - │ └── aggregations - │ └── max [as=max:50, type=float, outer=(49)] - │ └── sum:49 [type=float] + │ └── sum:29 = max:50 [type=bool, outer=(29,50), constraints=(/29: (/NULL - ]; /50: (/NULL - ]), fd=(29)==(50), (50)==(29)] └── filters (true) ----Stats for q15_project_1---- @@ -199,15 +183,16 @@ column_names row_count distinct_count null_count {total_revenue} 1 1 0 ~~~~ column_names row_count_est row_count_err distinct_count_est distinct_count_err null_count_est null_count_err -{s_address} 3333.00 3333.00 <== 2835.00 2835.00 <== 0.00 1.00 -{s_name} 3333.00 3333.00 <== 2834.00 2834.00 <== 0.00 1.00 -{s_phone} 3333.00 3333.00 <== 2835.00 2835.00 <== 0.00 1.00 -{s_suppkey} 3333.00 3333.00 <== 3307.00 3307.00 <== 0.00 1.00 -{total_revenue} 3333.00 3333.00 <== 2100.00 2100.00 <== 0.00 1.00 +{s_address} 1.00 1.00 1.00 1.00 0.00 1.00 +{s_name} 1.00 1.00 1.00 1.00 0.00 1.00 +{s_phone} 1.00 1.00 1.00 1.00 0.00 1.00 +{s_suppkey} 1.00 1.00 1.00 1.00 0.00 1.00 +{total_revenue} 1.00 1.00 1.00 1.00 0.00 1.00 -----Stats for q15_merge_join_2---- +----Stats for q15_lookup_join_2---- column_names row_count distinct_count null_count {l_suppkey} 1 1 0 +{max} 1 1 0 {s_address} 1 1 0 {s_name} 1 1 0 {s_phone} 1 1 0 @@ -215,45 +200,37 @@ column_names row_count distinct_count null_count {sum} 1 1 0 ~~~~ column_names row_count_est row_count_err distinct_count_est distinct_count_err null_count_est null_count_err -{l_suppkey} 3333.00 3333.00 <== 3307.00 3307.00 <== 0.00 1.00 -{s_address} 3333.00 3333.00 <== 2835.00 2835.00 <== 0.00 1.00 -{s_name} 3333.00 3333.00 <== 2834.00 2834.00 <== 0.00 1.00 -{s_phone} 3333.00 3333.00 <== 2835.00 2835.00 <== 0.00 1.00 -{s_suppkey} 3333.00 3333.00 <== 3307.00 3307.00 <== 0.00 1.00 -{sum} 3333.00 3333.00 <== 2100.00 2100.00 <== 0.00 1.00 - -----Stats for q15_scan_3---- -column_names row_count distinct_count null_count -{s_address} 9200 9200 0 -{s_name} 9200 9167 0 -{s_phone} 9200 9200 0 -{s_suppkey} 9200 9131 0 -~~~~ -column_names row_count_est row_count_err distinct_count_est distinct_count_err null_count_est null_count_err -{s_address} 10000.00 1.09 10000.00 1.09 0.00 1.00 -{s_name} 10000.00 1.09 9990.00 1.09 0.00 1.00 -{s_phone} 10000.00 1.09 10000.00 1.09 0.00 1.00 -{s_suppkey} 10000.00 1.09 9920.00 1.09 0.00 1.00 +{l_suppkey} 1.00 1.00 1.00 1.00 0.00 1.00 +{max} 1.00 1.00 1.00 1.00 0.00 1.00 +{s_address} 1.00 1.00 1.00 1.00 0.00 1.00 +{s_name} 1.00 1.00 1.00 1.00 0.00 1.00 +{s_phone} 1.00 1.00 1.00 1.00 0.00 1.00 +{s_suppkey} 1.00 1.00 1.00 1.00 0.00 1.00 +{sum} 1.00 1.00 1.00 1.00 0.00 1.00 -----Stats for q15_sort_4---- +----Stats for q15_sort_3---- column_names row_count distinct_count null_count {l_suppkey} 1 1 0 +{max} 1 1 0 {sum} 1 1 0 ~~~~ column_names row_count_est row_count_err distinct_count_est distinct_count_err null_count_est null_count_err -{l_suppkey} 3307.00 3307.00 <== 3307.00 3307.00 <== 0.00 1.00 -{sum} 3307.00 3307.00 <== 3307.00 3307.00 <== 0.00 1.00 +{l_suppkey} 1.00 1.00 1.00 1.00 0.00 1.00 +{max} 1.00 1.00 1.00 1.00 0.00 1.00 +{sum} 1.00 1.00 1.00 1.00 0.00 1.00 -----Stats for q15_select_5---- +----Stats for q15_inner_join_4---- column_names row_count distinct_count null_count {l_suppkey} 1 1 0 +{max} 1 1 0 {sum} 1 1 0 ~~~~ column_names row_count_est row_count_err distinct_count_est distinct_count_err null_count_est null_count_err -{l_suppkey} 3307.00 3307.00 <== 3307.00 3307.00 <== 0.00 1.00 -{sum} 3307.00 3307.00 <== 3307.00 3307.00 <== 0.00 1.00 +{l_suppkey} 1.00 1.00 1.00 1.00 0.00 1.00 +{max} 1.00 1.00 1.00 1.00 0.00 1.00 +{sum} 1.00 1.00 1.00 1.00 0.00 1.00 -----Stats for q15_group_by_6---- +----Stats for q15_group_by_5---- column_names row_count distinct_count null_count {l_suppkey} 10000 9920 0 {sum} 10000 10000 0 @@ -262,7 +239,7 @@ column_names row_count_est row_count_err distinct_count_est distinct_count_e {l_suppkey} 9920.00 1.01 9920.00 1.00 0.00 1.00 {sum} 9920.00 1.01 9920.00 1.01 0.00 1.00 -----Stats for q15_project_7---- +----Stats for q15_project_6---- column_names row_count distinct_count null_count {column28} 225954 220864 0 {l_suppkey} 225954 9920 0 @@ -271,7 +248,7 @@ column_names row_count_est row_count_err distinct_count_est distinct_count_e {column28} 238668.00 1.06 238668.00 1.08 0.00 1.00 {l_suppkey} 238668.00 1.06 9920.00 1.00 0.00 1.00 -----Stats for q15_index_join_8---- +----Stats for q15_index_join_7---- column_names row_count distinct_count null_count {l_discount} 225954 11 0 {l_extendedprice} 225954 196692 0 @@ -284,7 +261,7 @@ column_names row_count_est row_count_err distinct_count_est distinct_co {l_shipdate} 238668.00 1.06 91.00 1.00 0.00 1.00 {l_suppkey} 238668.00 1.06 9920.00 1.00 0.00 1.00 -----Stats for q15_scan_9---- +----Stats for q15_scan_8---- column_names row_count distinct_count null_count {l_linenumber} 225954 7 0 {l_orderkey} 225954 95273 0 @@ -295,14 +272,14 @@ column_names row_count_est row_count_err distinct_count_est distinct_count {l_orderkey} 238668.00 1.06 225118.00 2.36 <== 0.00 1.00 {l_shipdate} 238668.00 1.06 91.00 1.00 0.00 1.00 -----Stats for q15_scalar_group_by_10---- +----Stats for q15_scalar_group_by_9---- column_names row_count distinct_count null_count {max} 1 1 0 ~~~~ column_names row_count_est row_count_err distinct_count_est distinct_count_err null_count_est null_count_err {max} 1.00 1.00 1.00 1.00 0.00 1.00 -----Stats for q15_group_by_11---- +----Stats for q15_group_by_10---- column_names row_count distinct_count null_count {l_suppkey} 10000 9920 0 {sum} 10000 10000 0 @@ -311,7 +288,7 @@ column_names row_count_est row_count_err distinct_count_est distinct_count_e {l_suppkey} 9920.00 1.01 9920.00 1.00 0.00 1.00 {sum} 9920.00 1.01 9920.00 1.01 0.00 1.00 -----Stats for q15_project_12---- +----Stats for q15_project_11---- column_names row_count distinct_count null_count {column48} 225954 220864 0 {l_suppkey} 225954 9920 0 @@ -320,7 +297,7 @@ column_names row_count_est row_count_err distinct_count_est distinct_count_e {column48} 238668.00 1.06 238668.00 1.08 0.00 1.00 {l_suppkey} 238668.00 1.06 9920.00 1.00 0.00 1.00 -----Stats for q15_index_join_13---- +----Stats for q15_index_join_12---- column_names row_count distinct_count null_count {l_discount} 225954 11 0 {l_extendedprice} 225954 196692 0 @@ -333,7 +310,7 @@ column_names row_count_est row_count_err distinct_count_est distinct_co {l_shipdate} 238668.00 1.06 91.00 1.00 0.00 1.00 {l_suppkey} 238668.00 1.06 9920.00 1.00 0.00 1.00 -----Stats for q15_scan_14---- +----Stats for q15_scan_13---- column_names row_count distinct_count null_count {l_linenumber} 225954 7 0 {l_orderkey} 225954 95273 0 diff --git a/pkg/sql/opt/norm/decorrelate_funcs.go b/pkg/sql/opt/norm/decorrelate_funcs.go index 62547760a599..5181dab98bcb 100644 --- a/pkg/sql/opt/norm/decorrelate_funcs.go +++ b/pkg/sql/opt/norm/decorrelate_funcs.go @@ -66,6 +66,20 @@ func (c *CustomFuncs) deriveHasHoistableSubquery(scalar opt.ScalarExpr) bool { case *memo.UDFExpr: // Do not attempt to hoist UDFs. return false + + case *memo.EqExpr: + // Hoist subqueries in expressions like (Eq (Variable) (Subquery)) if + // the corresponding session setting is enabled. + // TODO(mgartner): We could hoist if we have an IS NOT DISTINCT FROM + // expression. But it won't currently lead to a lookup join due to + // #100855 and the plan could be worse, so we avoid it for now. + if c.f.evalCtx.SessionData().OptimizerHoistUncorrelatedEqualitySubqueries { + _, isLeftVar := scalar.Child(0).(*memo.VariableExpr) + _, isRightSubquery := scalar.Child(1).(*memo.SubqueryExpr) + if isLeftVar && isRightSubquery { + return true + } + } } // If HasHoistableSubquery is true for any child, then it's true for this @@ -807,7 +821,14 @@ func (r *subqueryHoister) hoistAll(scalar opt.ScalarExpr) opt.ScalarExpr { switch scalar.Op() { case opt.SubqueryOp, opt.ExistsOp, opt.AnyOp, opt.ArrayFlattenOp: subquery := scalar.Child(0).(memo.RelExpr) - if subquery.Relational().OuterCols.Empty() { + // According to the implementation of deriveHasHoistableSubquery, + // Exists, Any, and ArrayFlatten expressions are only hoistable if they + // are correlated. Uncorrelated subquery expressions are hoistable if + // the corresponding session setting is enabled and they are part of an + // equality expression with a variable. + uncorrelatedHoistAllowed := scalar.Op() == opt.SubqueryOp && + r.f.evalCtx.SessionData().OptimizerHoistUncorrelatedEqualitySubqueries + if subquery.Relational().OuterCols.Empty() && !uncorrelatedHoistAllowed { break } diff --git a/pkg/sql/opt/norm/testdata/rules/decorrelate b/pkg/sql/opt/norm/testdata/rules/decorrelate index 55cc60523511..898e41b88a8d 100644 --- a/pkg/sql/opt/norm/testdata/rules/decorrelate +++ b/pkg/sql/opt/norm/testdata/rules/decorrelate @@ -4656,23 +4656,42 @@ project ├── key: (1) ├── fd: (1)-->(2-5) └── select - ├── columns: k:1!null i:2 f:3 s:4 j:5 true_agg:18 + ├── columns: k:1!null i:2 f:3 s:4 j:5 column16:16 true_agg:18 ├── key: (1) - ├── fd: (1)-->(2-5,18) + ├── fd: (1)-->(2-5,16,18) ├── group-by (hash) - │ ├── columns: k:1!null i:2 f:3 s:4 j:5 true_agg:18 + │ ├── columns: k:1!null i:2 f:3 s:4 j:5 column16:16 true_agg:18 │ ├── grouping columns: k:1!null │ ├── key: (1) - │ ├── fd: (1)-->(2-5,18) + │ ├── fd: (1)-->(2-5,16,18) │ ├── left-join (hash) - │ │ ├── columns: k:1!null i:2 f:3 s:4 j:5 x:12 true:17 + │ │ ├── columns: k:1!null i:2 f:3 s:4 j:5 x:12 column16:16 true:17 │ │ ├── multiplicity: left-rows(exactly-one), right-rows(zero-or-one) │ │ ├── key: (1) - │ │ ├── fd: (1)-->(2-5,12,17) - │ │ ├── scan a - │ │ │ ├── columns: k:1!null i:2 f:3 s:4 j:5 + │ │ ├── fd: (1)-->(2-5,12,16,17) + │ │ ├── left-join (cross) + │ │ │ ├── columns: k:1!null i:2 f:3 s:4 j:5 column16:16 + │ │ │ ├── multiplicity: left-rows(exactly-one), right-rows(zero-or-more) │ │ │ ├── key: (1) - │ │ │ └── fd: (1)-->(2-5) + │ │ │ ├── fd: (1)-->(2-5,16) + │ │ │ ├── scan a + │ │ │ │ ├── columns: k:1!null i:2 f:3 s:4 j:5 + │ │ │ │ ├── key: (1) + │ │ │ │ └── fd: (1)-->(2-5) + │ │ │ ├── project + │ │ │ │ ├── columns: column16:16!null + │ │ │ │ ├── cardinality: [0 - 1] + │ │ │ │ ├── key: () + │ │ │ │ ├── fd: ()-->(16) + │ │ │ │ ├── limit + │ │ │ │ │ ├── cardinality: [0 - 1] + │ │ │ │ │ ├── key: () + │ │ │ │ │ ├── scan xy + │ │ │ │ │ │ └── limit hint: 1.00 + │ │ │ │ │ └── 1 + │ │ │ │ └── projections + │ │ │ │ └── true [as=column16:16] + │ │ │ └── filters (true) │ │ ├── project │ │ │ ├── columns: true:17!null x:12!null │ │ │ ├── key: (12) @@ -4693,27 +4712,135 @@ project │ │ └── f:3 │ ├── const-agg [as=s:4, outer=(4)] │ │ └── s:4 - │ └── const-agg [as=j:5, outer=(5)] - │ └── j:5 + │ ├── const-agg [as=j:5, outer=(5)] + │ │ └── j:5 + │ └── const-agg [as=column16:16, outer=(16)] + │ └── column16:16 + └── filters + └── COALESCE(column16:16, false) OR (true_agg:18 IS NOT NULL) [outer=(16,18)] + +# Hoist an uncorrelated equality subquery. +norm expect=HoistSelectSubquery +SELECT * FROM a WHERE k = (SELECT max(x) FROM xy) +---- +project + ├── columns: k:1!null i:2 f:3 s:4 j:5 + ├── cardinality: [0 - 1] + ├── key: () + ├── fd: ()-->(1-5) + └── inner-join (hash) + ├── columns: k:1!null i:2 f:3 s:4 j:5 max:12!null + ├── cardinality: [0 - 1] + ├── multiplicity: left-rows(zero-or-one), right-rows(zero-or-one) + ├── key: () + ├── fd: ()-->(1-5,12), (12)==(1), (1)==(12) + ├── scan a + │ ├── columns: k:1!null i:2 f:3 s:4 j:5 + │ ├── key: (1) + │ └── fd: (1)-->(2-5) + ├── scalar-group-by + │ ├── columns: max:12 + │ ├── cardinality: [1 - 1] + │ ├── key: () + │ ├── fd: ()-->(12) + │ ├── scan xy + │ │ ├── columns: x:8!null + │ │ └── key: (8) + │ └── aggregations + │ └── max [as=max:12, outer=(8)] + │ └── x:8 └── filters - └── or [outer=(18), subquery] - ├── coalesce - │ ├── subquery - │ │ └── project - │ │ ├── columns: column16:16!null - │ │ ├── cardinality: [0 - 1] - │ │ ├── key: () - │ │ ├── fd: ()-->(16) - │ │ ├── limit - │ │ │ ├── cardinality: [0 - 1] - │ │ │ ├── key: () - │ │ │ ├── scan xy - │ │ │ │ └── limit hint: 1.00 - │ │ │ └── 1 - │ │ └── projections - │ │ └── true [as=column16:16] - │ └── false - └── true_agg:18 IS NOT NULL + └── k:1 = max:12 [outer=(1,12), constraints=(/1: (/NULL - ]; /12: (/NULL - ]), fd=(1)==(12), (12)==(1)] + +# Hoist an uncorrelated equality subquery that could return multiple rows. +norm expect=HoistSelectSubquery +SELECT * FROM a WHERE k = (SELECT x FROM xy) +---- +project + ├── columns: k:1!null i:2 f:3 s:4 j:5 + ├── cardinality: [0 - 1] + ├── key: () + ├── fd: ()-->(1-5) + └── inner-join (hash) + ├── columns: k:1!null i:2 f:3 s:4 j:5 x:8!null + ├── cardinality: [0 - 1] + ├── multiplicity: left-rows(zero-or-one), right-rows(zero-or-one) + ├── key: () + ├── fd: ()-->(1-5,8), (8)==(1), (1)==(8) + ├── scan a + │ ├── columns: k:1!null i:2 f:3 s:4 j:5 + │ ├── key: (1) + │ └── fd: (1)-->(2-5) + ├── max1-row + │ ├── columns: x:8!null + │ ├── error: "more than one row returned by a subquery used as an expression" + │ ├── cardinality: [0 - 1] + │ ├── key: () + │ ├── fd: ()-->(8) + │ └── scan xy + │ ├── columns: x:8!null + │ └── key: (8) + └── filters + └── k:1 = x:8 [outer=(1,8), constraints=(/1: (/NULL - ]; /8: (/NULL - ]), fd=(1)==(8), (8)==(1)] + +# Do not hoist an uncorrelated equality subquery if the corresponding session +# setting is disabled. +norm set=optimizer_hoist_uncorrelated_equality_subqueries=off expect-not=HoistSelectSubquery +SELECT * FROM a WHERE k = (SELECT max(x) FROM xy) +---- +select + ├── columns: k:1!null i:2 f:3 s:4 j:5 + ├── key: (1) + ├── fd: (1)-->(2-5) + ├── scan a + │ ├── columns: k:1!null i:2 f:3 s:4 j:5 + │ ├── key: (1) + │ └── fd: (1)-->(2-5) + └── filters + └── eq [outer=(1), subquery, constraints=(/1: (/NULL - ])] + ├── k:1 + └── subquery + └── scalar-group-by + ├── columns: max:12 + ├── cardinality: [1 - 1] + ├── key: () + ├── fd: ()-->(12) + ├── scan xy + │ ├── columns: x:8!null + │ └── key: (8) + └── aggregations + └── max [as=max:12, outer=(8)] + └── x:8 + +# Do not hoist an uncorrelated inequality subquery. We have not yet proven that +# it will lead to a better plan. +norm expect-not=HoistSelectSubquery +SELECT * FROM a WHERE k < (SELECT max(x) FROM xy) +---- +select + ├── columns: k:1!null i:2 f:3 s:4 j:5 + ├── key: (1) + ├── fd: (1)-->(2-5) + ├── scan a + │ ├── columns: k:1!null i:2 f:3 s:4 j:5 + │ ├── key: (1) + │ └── fd: (1)-->(2-5) + └── filters + └── lt [outer=(1), subquery, constraints=(/1: (/NULL - ])] + ├── k:1 + └── subquery + └── scalar-group-by + ├── columns: max:12 + ├── cardinality: [1 - 1] + ├── key: () + ├── fd: ()-->(12) + ├── scan xy + │ ├── columns: x:8!null + │ └── key: (8) + └── aggregations + └── max [as=max:12, outer=(8)] + └── x:8 + # -------------------------------------------------- # HoistProjectSubquery @@ -5119,19 +5246,114 @@ values │ └── true [as=column16:16] └── false -# Don't hoist uncorrelated subquery. -norm -SELECT i < ANY(SELECT y FROM xy) AS r FROM a +# Hoist an uncorrelated equality subquery. +norm expect=HoistProjectSubquery +SELECT k = (SELECT max(x) FROM xy) FROM a ---- project - ├── columns: r:12 + ├── columns: "?column?":13 + ├── inner-join (cross) + │ ├── columns: k:1!null max:12 + │ ├── multiplicity: left-rows(exactly-one), right-rows(zero-or-more) + │ ├── key: (1) + │ ├── fd: ()-->(12) + │ ├── scan a + │ │ ├── columns: k:1!null + │ │ └── key: (1) + │ ├── scalar-group-by + │ │ ├── columns: max:12 + │ │ ├── cardinality: [1 - 1] + │ │ ├── key: () + │ │ ├── fd: ()-->(12) + │ │ ├── scan xy + │ │ │ ├── columns: x:8!null + │ │ │ └── key: (8) + │ │ └── aggregations + │ │ └── max [as=max:12, outer=(8)] + │ │ └── x:8 + │ └── filters (true) + └── projections + └── k:1 = max:12 [as="?column?":13, outer=(1,12)] + +# Hoist an uncorrelated equality subquery that could return multiple rows. +norm expect=HoistProjectSubquery +SELECT k = (SELECT x FROM xy) FROM a +---- +project + ├── columns: "?column?":12 + ├── left-join (cross) + │ ├── columns: k:1!null x:8 + │ ├── multiplicity: left-rows(exactly-one), right-rows(zero-or-more) + │ ├── key: (1) + │ ├── fd: (1)-->(8) + │ ├── scan a + │ │ ├── columns: k:1!null + │ │ └── key: (1) + │ ├── max1-row + │ │ ├── columns: x:8!null + │ │ ├── error: "more than one row returned by a subquery used as an expression" + │ │ ├── cardinality: [0 - 1] + │ │ ├── key: () + │ │ ├── fd: ()-->(8) + │ │ └── scan xy + │ │ ├── columns: x:8!null + │ │ └── key: (8) + │ └── filters (true) + └── projections + └── k:1 = x:8 [as="?column?":12, outer=(1,8)] + +# Do not hoist an uncorrelated equality subquery if the corresponding session +# setting is disabled. +norm set=optimizer_hoist_uncorrelated_equality_subqueries=off expect-not=HoistProjectSubquery +SELECT k = (SELECT max(x) FROM xy) FROM a +---- +project + ├── columns: "?column?":13 ├── scan a - │ └── columns: i:2 + │ ├── columns: k:1!null + │ └── key: (1) └── projections - └── any: lt [as=r:12, outer=(2), correlated-subquery] - ├── scan xy - │ └── columns: y:9 - └── i:2 + └── eq [as="?column?":13, outer=(1), subquery] + ├── k:1 + └── subquery + └── scalar-group-by + ├── columns: max:12 + ├── cardinality: [1 - 1] + ├── key: () + ├── fd: ()-->(12) + ├── scan xy + │ ├── columns: x:8!null + │ └── key: (8) + └── aggregations + └── max [as=max:12, outer=(8)] + └── x:8 + +# Do not hoist an uncorrelated inequality subquery. We have not yet proven that +# it will lead to a better plan. +norm expect-not=HoistProjectSubquery +SELECT k < (SELECT max(x) FROM xy) FROM a +---- +project + ├── columns: "?column?":13 + ├── scan a + │ ├── columns: k:1!null + │ └── key: (1) + └── projections + └── lt [as="?column?":13, outer=(1), subquery] + ├── k:1 + └── subquery + └── scalar-group-by + ├── columns: max:12 + ├── cardinality: [1 - 1] + ├── key: () + ├── fd: ()-->(12) + ├── scan xy + │ ├── columns: x:8!null + │ └── key: (8) + └── aggregations + └── max [as=max:12, outer=(8)] + └── x:8 + # -------------------------------------------------- # HoistJoinSubquery diff --git a/pkg/sql/opt/norm/testdata/rules/inline b/pkg/sql/opt/norm/testdata/rules/inline index 3b3ae1512b70..b5fa49d91ff1 100644 --- a/pkg/sql/opt/norm/testdata/rules/inline +++ b/pkg/sql/opt/norm/testdata/rules/inline @@ -1262,30 +1262,32 @@ SELECT k, min_x() FROM a WHERE k = min_x() ---- project ├── columns: k:1!null min_x:16 - ├── key: (1) - ├── fd: (1)-->(16) - ├── select - │ ├── columns: k:1!null - │ ├── key: (1) + ├── cardinality: [0 - 1] + ├── key: () + ├── fd: ()-->(1,16) + ├── inner-join (hash) + │ ├── columns: k:1!null x:8!null + │ ├── cardinality: [0 - 1] + │ ├── multiplicity: left-rows(zero-or-one), right-rows(zero-or-one) + │ ├── key: () + │ ├── fd: ()-->(1,8), (8)==(1), (1)==(8) │ ├── scan a │ │ ├── columns: k:1!null │ │ └── key: (1) + │ ├── limit + │ │ ├── columns: x:8!null + │ │ ├── internal-ordering: +8 + │ │ ├── cardinality: [0 - 1] + │ │ ├── key: () + │ │ ├── fd: ()-->(8) + │ │ ├── scan xy + │ │ │ ├── columns: x:8!null + │ │ │ ├── key: (8) + │ │ │ ├── ordering: +8 + │ │ │ └── limit hint: 1.00 + │ │ └── 1 │ └── filters - │ └── eq [outer=(1), subquery, constraints=(/1: (/NULL - ])] - │ ├── k:1 - │ └── subquery - │ └── limit - │ ├── columns: x:8!null - │ ├── internal-ordering: +8 - │ ├── cardinality: [0 - 1] - │ ├── key: () - │ ├── fd: ()-->(8) - │ ├── scan xy - │ │ ├── columns: x:8!null - │ │ ├── key: (8) - │ │ ├── ordering: +8 - │ │ └── limit hint: 1.00 - │ └── 1 + │ └── k:1 = x:8 [outer=(1,8), constraints=(/1: (/NULL - ]; /8: (/NULL - ]), fd=(1)==(8), (8)==(1)] └── projections └── subquery [as=min_x:16, subquery] └── limit diff --git a/pkg/sql/opt/norm/testdata/rules/join b/pkg/sql/opt/norm/testdata/rules/join index 1c7b6c590588..28f72b47c360 100644 --- a/pkg/sql/opt/norm/testdata/rules/join +++ b/pkg/sql/opt/norm/testdata/rules/join @@ -1438,59 +1438,61 @@ SELECT (SELECT i_name FROM item LIMIT 1) project ├── columns: i_name:57 ├── inner-join (hash) - │ ├── columns: h_data:9!null ol_o_id:12!null ol_d_id:13!null ol_w_id:14!null ol_number:15!null ol_dist_info:21!null true_agg:48 - │ ├── fd: (12-15)-->(21,48), (9)==(21), (21)==(9) + │ ├── columns: h_data:9!null ol_dist_info:21!null ol_i_id:39 exists:49!null + │ ├── fd: (9)==(21), (21)==(9) │ ├── scan history │ │ └── columns: h_data:9 │ ├── select - │ │ ├── columns: ol_o_id:12!null ol_d_id:13!null ol_w_id:14!null ol_number:15!null ol_dist_info:21 true_agg:48 - │ │ ├── key: (12-15) - │ │ ├── fd: (12-15)-->(21,48) - │ │ ├── group-by (hash) - │ │ │ ├── columns: ol_o_id:12!null ol_d_id:13!null ol_w_id:14!null ol_number:15!null ol_dist_info:21 true_agg:48 - │ │ │ ├── grouping columns: ol_o_id:12!null ol_d_id:13!null ol_w_id:14!null ol_number:15!null - │ │ │ ├── key: (12-15) - │ │ │ ├── fd: (12-15)-->(21,48) - │ │ │ ├── left-join (cross) - │ │ │ │ ├── columns: ol_o_id:12!null ol_d_id:13!null ol_w_id:14!null ol_number:15!null ol_dist_info:21 true:47 - │ │ │ │ ├── fd: (12-15)-->(21) - │ │ │ │ ├── scan order_line - │ │ │ │ │ ├── columns: ol_o_id:12!null ol_d_id:13!null ol_w_id:14!null ol_number:15!null ol_dist_info:21 + │ │ ├── columns: ol_dist_info:21 ol_i_id:39 exists:49!null + │ │ ├── left-join (cross) + │ │ │ ├── columns: ol_dist_info:21 ol_i_id:39 exists:49!null + │ │ │ ├── multiplicity: left-rows(exactly-one), right-rows(zero-or-more) + │ │ │ ├── project + │ │ │ │ ├── columns: exists:49!null ol_dist_info:21 + │ │ │ │ ├── group-by (hash) + │ │ │ │ │ ├── columns: ol_o_id:12!null ol_d_id:13!null ol_w_id:14!null ol_number:15!null ol_dist_info:21 true_agg:48 + │ │ │ │ │ ├── grouping columns: ol_o_id:12!null ol_d_id:13!null ol_w_id:14!null ol_number:15!null │ │ │ │ │ ├── key: (12-15) - │ │ │ │ │ └── fd: (12-15)-->(21) - │ │ │ │ ├── project - │ │ │ │ │ ├── columns: true:47!null - │ │ │ │ │ ├── fd: ()-->(47) - │ │ │ │ │ ├── select - │ │ │ │ │ │ ├── columns: h_data:32!null - │ │ │ │ │ │ ├── scan history - │ │ │ │ │ │ │ └── columns: h_data:32 + │ │ │ │ │ ├── fd: (12-15)-->(21,48) + │ │ │ │ │ ├── left-join (cross) + │ │ │ │ │ │ ├── columns: ol_o_id:12!null ol_d_id:13!null ol_w_id:14!null ol_number:15!null ol_dist_info:21 true:47 + │ │ │ │ │ │ ├── fd: (12-15)-->(21) + │ │ │ │ │ │ ├── scan order_line + │ │ │ │ │ │ │ ├── columns: ol_o_id:12!null ol_d_id:13!null ol_w_id:14!null ol_number:15!null ol_dist_info:21 + │ │ │ │ │ │ │ ├── key: (12-15) + │ │ │ │ │ │ │ └── fd: (12-15)-->(21) + │ │ │ │ │ │ ├── project + │ │ │ │ │ │ │ ├── columns: true:47!null + │ │ │ │ │ │ │ ├── fd: ()-->(47) + │ │ │ │ │ │ │ ├── select + │ │ │ │ │ │ │ │ ├── columns: h_data:32!null + │ │ │ │ │ │ │ │ ├── scan history + │ │ │ │ │ │ │ │ │ └── columns: h_data:32 + │ │ │ │ │ │ │ │ └── filters + │ │ │ │ │ │ │ │ └── h_data:32 IS NOT NULL [outer=(32), constraints=(/32: (/NULL - ]; tight)] + │ │ │ │ │ │ │ └── projections + │ │ │ │ │ │ │ └── true [as=true:47] │ │ │ │ │ │ └── filters - │ │ │ │ │ │ └── h_data:32 IS NOT NULL [outer=(32), constraints=(/32: (/NULL - ]; tight)] - │ │ │ │ │ └── projections - │ │ │ │ │ └── true [as=true:47] - │ │ │ │ └── filters - │ │ │ │ └── ol_dist_info:21 IS NOT NULL [outer=(21), constraints=(/21: (/NULL - ]; tight)] - │ │ │ └── aggregations - │ │ │ ├── const-not-null-agg [as=true_agg:48, outer=(47)] - │ │ │ │ └── true:47 - │ │ │ └── const-agg [as=ol_dist_info:21, outer=(21)] - │ │ │ └── ol_dist_info:21 + │ │ │ │ │ │ └── ol_dist_info:21 IS NOT NULL [outer=(21), constraints=(/21: (/NULL - ]; tight)] + │ │ │ │ │ └── aggregations + │ │ │ │ │ ├── const-not-null-agg [as=true_agg:48, outer=(47)] + │ │ │ │ │ │ └── true:47 + │ │ │ │ │ └── const-agg [as=ol_dist_info:21, outer=(21)] + │ │ │ │ │ └── ol_dist_info:21 + │ │ │ │ └── projections + │ │ │ │ └── true_agg:48 IS NOT NULL [as=exists:49, outer=(48)] + │ │ │ ├── limit + │ │ │ │ ├── columns: ol_i_id:39!null + │ │ │ │ ├── cardinality: [0 - 1] + │ │ │ │ ├── key: () + │ │ │ │ ├── fd: ()-->(39) + │ │ │ │ ├── scan order_line + │ │ │ │ │ ├── columns: ol_i_id:39!null + │ │ │ │ │ └── limit hint: 1.00 + │ │ │ │ └── 1 + │ │ │ └── filters (true) │ │ └── filters - │ │ └── or [outer=(48), subquery] - │ │ ├── true_agg:48 IS NOT NULL - │ │ └── is-not - │ │ ├── subquery - │ │ │ └── limit - │ │ │ ├── columns: ol_i_id:39!null - │ │ │ ├── cardinality: [0 - 1] - │ │ │ ├── key: () - │ │ │ ├── fd: ()-->(39) - │ │ │ ├── scan order_line - │ │ │ │ ├── columns: ol_i_id:39!null - │ │ │ │ └── limit hint: 1.00 - │ │ │ └── 1 - │ │ └── NULL + │ │ └── exists:49 OR (ol_i_id:39 IS NOT NULL) [outer=(39,49)] │ └── filters │ └── h_data:9 = ol_dist_info:21 [outer=(9,21), constraints=(/9: (/NULL - ]; /21: (/NULL - ]), fd=(9)==(21), (21)==(9)] └── projections diff --git a/pkg/sql/opt/testutils/opttester/opt_tester.go b/pkg/sql/opt/testutils/opttester/opt_tester.go index 9a56524a96d1..6595fda80912 100644 --- a/pkg/sql/opt/testutils/opttester/opt_tester.go +++ b/pkg/sql/opt/testutils/opttester/opt_tester.go @@ -299,6 +299,7 @@ func New(catalog cat.Catalog, sql string) *OptTester { ot.evalCtx.SessionData().OptimizerUseLimitOrderingForStreamingGroupBy = true ot.evalCtx.SessionData().OptimizerUseImprovedSplitDisjunctionForJoins = true ot.evalCtx.SessionData().OptimizerAlwaysUseHistograms = true + ot.evalCtx.SessionData().OptimizerHoistUncorrelatedEqualitySubqueries = true return ot } diff --git a/pkg/sql/opt/xform/testdata/external/tpch b/pkg/sql/opt/xform/testdata/external/tpch index 8d43f1f7600e..c7025239c3df 100644 --- a/pkg/sql/opt/xform/testdata/external/tpch +++ b/pkg/sql/opt/xform/testdata/external/tpch @@ -1580,32 +1580,28 @@ project ├── columns: s_suppkey:1!null s_name:2!null s_address:3!null s_phone:5!null total_revenue:29!null ├── immutable ├── key: (1) - ├── fd: (1)-->(2,3,5,29) - ├── ordering: +1 - └── inner-join (merge) - ├── columns: s_suppkey:1!null s_name:2!null s_address:3!null s_phone:5!null l_suppkey:12!null sum:29!null - ├── left ordering: +1 - ├── right ordering: +12 + ├── fd: ()-->(29), (1)-->(2,3,5) + ├── ordering: +1 opt(29) [actual: +1] + └── inner-join (lookup supplier) + ├── columns: s_suppkey:1!null s_name:2!null s_address:3!null s_phone:5!null l_suppkey:12!null sum:29!null max:50!null + ├── key columns: [12] = [1] + ├── lookup columns are key ├── immutable ├── key: (12) - ├── fd: (1)-->(2,3,5), (12)-->(29), (1)==(12), (12)==(1) - ├── ordering: +(1|12) [actual: +1] - ├── scan supplier - │ ├── columns: s_suppkey:1!null s_name:2!null s_address:3!null s_phone:5!null - │ ├── key: (1) - │ ├── fd: (1)-->(2,3,5) - │ └── ordering: +1 + ├── fd: ()-->(29,50), (1)-->(2,3,5), (29)==(50), (50)==(29), (1)==(12), (12)==(1) + ├── ordering: +(1|12) opt(29,50) [actual: +12] ├── sort - │ ├── columns: l_suppkey:12!null sum:29!null + │ ├── columns: l_suppkey:12!null sum:29!null max:50!null │ ├── immutable │ ├── key: (12) - │ ├── fd: (12)-->(29) - │ ├── ordering: +12 - │ └── select - │ ├── columns: l_suppkey:12!null sum:29!null + │ ├── fd: ()-->(29,50), (29)==(50), (50)==(29) + │ ├── ordering: +12 opt(29,50) [actual: +12] + │ └── inner-join (hash) + │ ├── columns: l_suppkey:12!null sum:29!null max:50!null + │ ├── multiplicity: left-rows(zero-or-one), right-rows(zero-or-more) │ ├── immutable │ ├── key: (12) - │ ├── fd: (12)-->(29) + │ ├── fd: ()-->(29,50), (29)==(50), (50)==(29) │ ├── group-by (hash) │ │ ├── columns: l_suppkey:12!null sum:29!null │ │ ├── grouping columns: l_suppkey:12!null @@ -1627,40 +1623,38 @@ project │ │ └── aggregations │ │ └── sum [as=sum:29, outer=(28)] │ │ └── column28:28 + │ ├── scalar-group-by + │ │ ├── columns: max:50 + │ │ ├── cardinality: [1 - 1] + │ │ ├── immutable + │ │ ├── key: () + │ │ ├── fd: ()-->(50) + │ │ ├── group-by (hash) + │ │ │ ├── columns: l_suppkey:32!null sum:49!null + │ │ │ ├── grouping columns: l_suppkey:32!null + │ │ │ ├── immutable + │ │ │ ├── key: (32) + │ │ │ ├── fd: (32)-->(49) + │ │ │ ├── project + │ │ │ │ ├── columns: column48:48!null l_suppkey:32!null + │ │ │ │ ├── immutable + │ │ │ │ ├── index-join lineitem + │ │ │ │ │ ├── columns: l_suppkey:32!null l_extendedprice:35!null l_discount:36!null l_shipdate:40!null + │ │ │ │ │ └── scan lineitem@l_sd + │ │ │ │ │ ├── columns: l_orderkey:30!null l_linenumber:33!null l_shipdate:40!null + │ │ │ │ │ ├── constraint: /40/30/33: [/'1996-01-01' - /'1996-03-31'] + │ │ │ │ │ ├── key: (30,33) + │ │ │ │ │ └── fd: (30,33)-->(40) + │ │ │ │ └── projections + │ │ │ │ └── l_extendedprice:35 * (1.0 - l_discount:36) [as=column48:48, outer=(35,36), immutable] + │ │ │ └── aggregations + │ │ │ └── sum [as=sum:49, outer=(48)] + │ │ │ └── column48:48 + │ │ └── aggregations + │ │ └── max [as=max:50, outer=(49)] + │ │ └── sum:49 │ └── filters - │ └── eq [outer=(29), immutable, subquery, constraints=(/29: (/NULL - ])] - │ ├── sum:29 - │ └── subquery - │ └── scalar-group-by - │ ├── columns: max:50 - │ ├── cardinality: [1 - 1] - │ ├── immutable - │ ├── key: () - │ ├── fd: ()-->(50) - │ ├── group-by (hash) - │ │ ├── columns: l_suppkey:32!null sum:49!null - │ │ ├── grouping columns: l_suppkey:32!null - │ │ ├── immutable - │ │ ├── key: (32) - │ │ ├── fd: (32)-->(49) - │ │ ├── project - │ │ │ ├── columns: column48:48!null l_suppkey:32!null - │ │ │ ├── immutable - │ │ │ ├── index-join lineitem - │ │ │ │ ├── columns: l_suppkey:32!null l_extendedprice:35!null l_discount:36!null l_shipdate:40!null - │ │ │ │ └── scan lineitem@l_sd - │ │ │ │ ├── columns: l_orderkey:30!null l_linenumber:33!null l_shipdate:40!null - │ │ │ │ ├── constraint: /40/30/33: [/'1996-01-01' - /'1996-03-31'] - │ │ │ │ ├── key: (30,33) - │ │ │ │ └── fd: (30,33)-->(40) - │ │ │ └── projections - │ │ │ └── l_extendedprice:35 * (1.0 - l_discount:36) [as=column48:48, outer=(35,36), immutable] - │ │ └── aggregations - │ │ └── sum [as=sum:49, outer=(48)] - │ │ └── column48:48 - │ └── aggregations - │ └── max [as=max:50, outer=(49)] - │ └── sum:49 + │ └── sum:29 = max:50 [outer=(29,50), constraints=(/29: (/NULL - ]; /50: (/NULL - ]), fd=(29)==(50), (50)==(29)] └── filters (true) # -------------------------------------------------- diff --git a/pkg/sql/opt/xform/testdata/external/tpch-no-stats b/pkg/sql/opt/xform/testdata/external/tpch-no-stats index d591e9c16817..78e42c1dc07b 100644 --- a/pkg/sql/opt/xform/testdata/external/tpch-no-stats +++ b/pkg/sql/opt/xform/testdata/external/tpch-no-stats @@ -1556,27 +1556,28 @@ project ├── columns: s_suppkey:1!null s_name:2!null s_address:3!null s_phone:5!null total_revenue:29!null ├── immutable ├── key: (1) - ├── fd: (1)-->(2,3,5,29) - ├── ordering: +1 + ├── fd: ()-->(29), (1)-->(2,3,5) + ├── ordering: +1 opt(29) [actual: +1] └── inner-join (lookup supplier) - ├── columns: s_suppkey:1!null s_name:2!null s_address:3!null s_phone:5!null l_suppkey:12!null sum:29!null + ├── columns: s_suppkey:1!null s_name:2!null s_address:3!null s_phone:5!null l_suppkey:12!null sum:29!null max:50!null ├── key columns: [12] = [1] ├── lookup columns are key ├── immutable ├── key: (12) - ├── fd: (1)-->(2,3,5), (12)-->(29), (1)==(12), (12)==(1) - ├── ordering: +(1|12) [actual: +12] + ├── fd: ()-->(29,50), (1)-->(2,3,5), (29)==(50), (50)==(29), (1)==(12), (12)==(1) + ├── ordering: +(1|12) opt(29,50) [actual: +12] ├── sort - │ ├── columns: l_suppkey:12!null sum:29!null + │ ├── columns: l_suppkey:12!null sum:29!null max:50!null │ ├── immutable │ ├── key: (12) - │ ├── fd: (12)-->(29) - │ ├── ordering: +12 - │ └── select - │ ├── columns: l_suppkey:12!null sum:29!null + │ ├── fd: ()-->(29,50), (29)==(50), (50)==(29) + │ ├── ordering: +12 opt(29,50) [actual: +12] + │ └── inner-join (hash) + │ ├── columns: l_suppkey:12!null sum:29!null max:50!null + │ ├── multiplicity: left-rows(zero-or-one), right-rows(zero-or-more) │ ├── immutable │ ├── key: (12) - │ ├── fd: (12)-->(29) + │ ├── fd: ()-->(29,50), (29)==(50), (50)==(29) │ ├── group-by (hash) │ │ ├── columns: l_suppkey:12!null sum:29!null │ │ ├── grouping columns: l_suppkey:12!null @@ -1597,39 +1598,37 @@ project │ │ └── aggregations │ │ └── sum [as=sum:29, outer=(28)] │ │ └── column28:28 + │ ├── scalar-group-by + │ │ ├── columns: max:50 + │ │ ├── cardinality: [1 - 1] + │ │ ├── immutable + │ │ ├── key: () + │ │ ├── fd: ()-->(50) + │ │ ├── group-by (hash) + │ │ │ ├── columns: l_suppkey:32!null sum:49!null + │ │ │ ├── grouping columns: l_suppkey:32!null + │ │ │ ├── immutable + │ │ │ ├── key: (32) + │ │ │ ├── fd: (32)-->(49) + │ │ │ ├── project + │ │ │ │ ├── columns: column48:48!null l_suppkey:32!null + │ │ │ │ ├── immutable + │ │ │ │ ├── select + │ │ │ │ │ ├── columns: l_suppkey:32!null l_extendedprice:35!null l_discount:36!null l_shipdate:40!null + │ │ │ │ │ ├── scan lineitem + │ │ │ │ │ │ └── columns: l_suppkey:32!null l_extendedprice:35!null l_discount:36!null l_shipdate:40!null + │ │ │ │ │ └── filters + │ │ │ │ │ └── (l_shipdate:40 >= '1996-01-01') AND (l_shipdate:40 < '1996-04-01') [outer=(40), constraints=(/40: [/'1996-01-01' - /'1996-03-31']; tight)] + │ │ │ │ └── projections + │ │ │ │ └── l_extendedprice:35 * (1.0 - l_discount:36) [as=column48:48, outer=(35,36), immutable] + │ │ │ └── aggregations + │ │ │ └── sum [as=sum:49, outer=(48)] + │ │ │ └── column48:48 + │ │ └── aggregations + │ │ └── max [as=max:50, outer=(49)] + │ │ └── sum:49 │ └── filters - │ └── eq [outer=(29), immutable, subquery, constraints=(/29: (/NULL - ])] - │ ├── sum:29 - │ └── subquery - │ └── scalar-group-by - │ ├── columns: max:50 - │ ├── cardinality: [1 - 1] - │ ├── immutable - │ ├── key: () - │ ├── fd: ()-->(50) - │ ├── group-by (hash) - │ │ ├── columns: l_suppkey:32!null sum:49!null - │ │ ├── grouping columns: l_suppkey:32!null - │ │ ├── immutable - │ │ ├── key: (32) - │ │ ├── fd: (32)-->(49) - │ │ ├── project - │ │ │ ├── columns: column48:48!null l_suppkey:32!null - │ │ │ ├── immutable - │ │ │ ├── select - │ │ │ │ ├── columns: l_suppkey:32!null l_extendedprice:35!null l_discount:36!null l_shipdate:40!null - │ │ │ │ ├── scan lineitem - │ │ │ │ │ └── columns: l_suppkey:32!null l_extendedprice:35!null l_discount:36!null l_shipdate:40!null - │ │ │ │ └── filters - │ │ │ │ └── (l_shipdate:40 >= '1996-01-01') AND (l_shipdate:40 < '1996-04-01') [outer=(40), constraints=(/40: [/'1996-01-01' - /'1996-03-31']; tight)] - │ │ │ └── projections - │ │ │ └── l_extendedprice:35 * (1.0 - l_discount:36) [as=column48:48, outer=(35,36), immutable] - │ │ └── aggregations - │ │ └── sum [as=sum:49, outer=(48)] - │ │ └── column48:48 - │ └── aggregations - │ └── max [as=max:50, outer=(49)] - │ └── sum:49 + │ └── sum:29 = max:50 [outer=(29,50), constraints=(/29: (/NULL - ]; /50: (/NULL - ]), fd=(29)==(50), (50)==(29)] └── filters (true) # -------------------------------------------------- diff --git a/pkg/sql/sessiondatapb/local_only_session_data.proto b/pkg/sql/sessiondatapb/local_only_session_data.proto index d0d34a4cfcd5..01fc265e7836 100644 --- a/pkg/sql/sessiondatapb/local_only_session_data.proto +++ b/pkg/sql/sessiondatapb/local_only_session_data.proto @@ -379,6 +379,11 @@ message LocalOnlySessionData { // parallelization will still be disabled for queries with LIMITs, and it can // lead to increased likelihood of OOMs. bool unbounded_parallel_scans = 101; + // OptimizerHoistUncorrelatedEqualitySubqueries, when true, causes the + // optimizer to hoist uncorrelated subqueries that are part of an equality + // expression with a column reference, which can produce more efficient query + // plans. + bool optimizer_hoist_uncorrelated_equality_subqueries = 102; /////////////////////////////////////////////////////////////////////////// // WARNING: consider whether a session parameter you're adding needs to // diff --git a/pkg/sql/vars.go b/pkg/sql/vars.go index 6e34650d1030..beecd0866786 100644 --- a/pkg/sql/vars.go +++ b/pkg/sql/vars.go @@ -2568,6 +2568,23 @@ var varGen = map[string]sessionVar{ GlobalDefault: globalTrue, }, + // CockroachDB extension. + `optimizer_hoist_uncorrelated_equality_subqueries`: { + GetStringVal: makePostgresBoolGetStringValFn(`optimizer_hoist_uncorrelated_equality_subqueries`), + Set: func(_ context.Context, m sessionDataMutator, s string) error { + b, err := paramparse.ParseBoolVar("optimizer_hoist_uncorrelated_equality_subqueries", s) + if err != nil { + return err + } + m.SetOptimizerHoistUncorrelatedEqualitySubqueries(b) + return nil + }, + Get: func(evalCtx *extendedEvalContext, _ *kv.Txn) (string, error) { + return formatBoolAsPostgresSetting(evalCtx.SessionData().OptimizerHoistUncorrelatedEqualitySubqueries), nil + }, + GlobalDefault: globalTrue, + }, + // CockroachDB extension. `enable_create_stats_using_extremes`: { GetStringVal: makePostgresBoolGetStringValFn(`enable_create_stats_using_extremes`),