diff --git a/cmd/explaintest/r/agg_predicate_pushdown.result b/cmd/explaintest/r/agg_predicate_pushdown.result new file mode 100644 index 0000000000000..9caca7aa5bb22 --- /dev/null +++ b/cmd/explaintest/r/agg_predicate_pushdown.result @@ -0,0 +1,54 @@ +drop database if exists agg_predicate_pushdown; +create database agg_predicate_pushdown; +create table t(a int, b int, c int); +desc format='brief' select a, b, avg(c) from t group by a, b, c having +(a > 1) and (a > 2) and 1 and (b > 2) and (avg(c) > 3); +id estRows task access object operator info +Projection 711.11 root test.t.a, test.t.b, Column#5 +└─Selection 711.11 root gt(Column#5, 3) + └─HashAgg 888.89 root group by:Column#16, Column#17, Column#18, funcs:avg(Column#13)->Column#5, funcs:firstrow(Column#14)->test.t.a, funcs:firstrow(Column#15)->test.t.b + └─Projection 1111.11 root cast(test.t.c, decimal(15,4) BINARY)->Column#13, test.t.a, test.t.b, test.t.a, test.t.b, test.t.c + └─TableReader 1111.11 root data:Selection + └─Selection 1111.11 cop[tikv] gt(test.t.a, 1), gt(test.t.a, 2), gt(test.t.b, 2) + └─TableFullScan 10000.00 cop[tikv] table:t keep order:false, stats:pseudo +desc format='brief' select a, b, avg(c) from t group by a, b, c having +(a > 1 or b > 2) and (a > 2 or b < 1) and 1 and (b > 2) and (avg(c) > 3); +id estRows task access object operator info +Projection 657.65 root test.t.a, test.t.b, Column#5 +└─Selection 657.65 root gt(Column#5, 3) + └─HashAgg 822.06 root group by:Column#16, Column#17, Column#18, funcs:avg(Column#13)->Column#5, funcs:firstrow(Column#14)->test.t.a, funcs:firstrow(Column#15)->test.t.b + └─Projection 1027.57 root cast(test.t.c, decimal(15,4) BINARY)->Column#13, test.t.a, test.t.b, test.t.a, test.t.b, test.t.c + └─TableReader 1027.57 root data:Selection + └─Selection 1027.57 cop[tikv] gt(test.t.b, 2), or(gt(test.t.a, 1), gt(test.t.b, 2)), or(gt(test.t.a, 2), lt(test.t.b, 1)) + └─TableFullScan 10000.00 cop[tikv] table:t keep order:false, stats:pseudo +desc format='brief' select a, b, avg(c) from t group by a, b, c having +(a > 1 and b > 2) or (a > 2 and b < 1) or (b > 2 and avg(c) > 3); +id estRows task access object operator info +Projection 3027.54 root test.t.a, test.t.b, Column#5 +└─Selection 3027.54 root or(and(gt(test.t.a, 1), gt(test.t.b, 2)), or(and(gt(test.t.a, 2), lt(test.t.b, 1)), and(gt(test.t.b, 2), gt(Column#5, 3)))) + └─HashAgg 3784.43 root group by:Column#16, Column#17, Column#18, funcs:avg(Column#13)->Column#5, funcs:firstrow(Column#14)->test.t.a, funcs:firstrow(Column#15)->test.t.b + └─Projection 4730.53 root cast(test.t.c, decimal(15,4) BINARY)->Column#13, test.t.a, test.t.b, test.t.a, test.t.b, test.t.c + └─TableReader 4730.53 root data:Selection + └─Selection 4730.53 cop[tikv] or(and(gt(test.t.a, 1), gt(test.t.b, 2)), or(and(gt(test.t.a, 2), lt(test.t.b, 1)), gt(test.t.b, 2))) + └─TableFullScan 10000.00 cop[tikv] table:t keep order:false, stats:pseudo +desc format='brief' select a, b, avg(c) from t group by a, b, c having +(a > 1 or avg(c) > 1) and (a < 3); +id estRows task access object operator info +Projection 2126.93 root test.t.a, test.t.b, Column#5 +└─Selection 2126.93 root or(gt(test.t.a, 1), gt(Column#5, 1)) + └─HashAgg 2658.67 root group by:Column#16, Column#17, Column#18, funcs:avg(Column#13)->Column#5, funcs:firstrow(Column#14)->test.t.a, funcs:firstrow(Column#15)->test.t.b + └─Projection 3323.33 root cast(test.t.c, decimal(15,4) BINARY)->Column#13, test.t.a, test.t.b, test.t.a, test.t.b, test.t.c + └─TableReader 3323.33 root data:Selection + └─Selection 3323.33 cop[tikv] lt(test.t.a, 3) + └─TableFullScan 10000.00 cop[tikv] table:t keep order:false, stats:pseudo +desc format='brief' select a, b, avg(c) from t group by a, b, c having +(a > 1 and avg(c) > 1) or (a < 3); +id estRows task access object operator info +Projection 6393.60 root test.t.a, test.t.b, Column#5 +└─Selection 6393.60 root or(and(gt(test.t.a, 1), gt(Column#5, 1)), lt(test.t.a, 3)) + └─HashAgg 7992.00 root group by:Column#16, Column#17, Column#18, funcs:avg(Column#13)->Column#5, funcs:firstrow(Column#14)->test.t.a, funcs:firstrow(Column#15)->test.t.b + └─Projection 9990.00 root cast(test.t.c, decimal(15,4) BINARY)->Column#13, test.t.a, test.t.b, test.t.a, test.t.b, test.t.c + └─TableReader 9990.00 root data:Selection + └─Selection 9990.00 cop[tikv] or(gt(test.t.a, 1), lt(test.t.a, 3)) + └─TableFullScan 10000.00 cop[tikv] table:t keep order:false, stats:pseudo +use test; diff --git a/cmd/explaintest/r/cte.result b/cmd/explaintest/r/cte.result index 077e62cf33cd4..6c1da3d121e77 100644 --- a/cmd/explaintest/r/cte.result +++ b/cmd/explaintest/r/cte.result @@ -387,17 +387,18 @@ insert into tpk values(1), (2), (3); // Expect a Sort operator on CTE. explain with cte1 as (select c1 from t1) select /*+ MERGE_JOIN(dt1, dt2) */ * from t1 dt1 inner join cte1 dt2 on dt2.c1 = dt1.c1 order by 1, 2; id estRows task access object operator info -MergeJoin_26 10000.00 root inner join, left key:test.t1.c1, right key:test.t1.c1 -├─Sort_24(Build) 8000.00 root test.t1.c1 -│ └─Selection_22 8000.00 root not(isnull(test.t1.c1)) -│ └─CTEFullScan_23 10000.00 root CTE:dt2 data:CTE_0 -└─Sort_20(Probe) 9990.00 root test.t1.c1 - └─TableReader_19 9990.00 root data:Selection_18 - └─Selection_18 9990.00 cop[tikv] not(isnull(test.t1.c1)) - └─TableFullScan_17 10000.00 cop[tikv] table:dt1 keep order:false, stats:pseudo -CTE_0 10000.00 root Non-Recursive CTE -└─TableReader_12(Seed Part) 10000.00 root data:TableFullScan_11 - └─TableFullScan_11 10000.00 cop[tikv] table:t1 keep order:false, stats:pseudo +MergeJoin_28 8000.00 root inner join, left key:test.t1.c1, right key:test.t1.c1 +├─Sort_26(Build) 6400.00 root test.t1.c1 +│ └─Selection_24 6400.00 root not(isnull(test.t1.c1)) +│ └─CTEFullScan_25 8000.00 root CTE:dt2 data:CTE_0 +└─Sort_22(Probe) 9990.00 root test.t1.c1 + └─TableReader_21 9990.00 root data:Selection_20 + └─Selection_20 9990.00 cop[tikv] not(isnull(test.t1.c1)) + └─TableFullScan_19 10000.00 cop[tikv] table:dt1 keep order:false, stats:pseudo +CTE_0 8000.00 root Non-Recursive CTE +└─Selection_11(Seed Part) 8000.00 root not(isnull(test.t1.c1)) + └─TableReader_14 10000.00 root data:TableFullScan_13 + └─TableFullScan_13 10000.00 cop[tikv] table:t1 keep order:false, stats:pseudo with cte1 as (select c1 from t1) select /*+ MERGE_JOIN(dt1, dt2) */ * from t1 dt1 inner join cte1 dt2 on dt2.c1 = dt1.c1 order by 1, 2; c1 c1 1 1 @@ -411,15 +412,16 @@ c1 c1 // Sort should not exist, because tpk.c1 is pk. Not the best plan for now(#25674). explain with cte1 as (select c1 from tpk) select /*+ MERGE_JOIN(dt1, dt2) */ * from tpk dt1 inner join cte1 dt2 on dt2.c1 = dt1.c1 order by 1, 2; id estRows task access object operator info -MergeJoin_24 10000.00 root inner join, left key:test.tpk.c1, right key:test.tpk.c1 -├─Sort_22(Build) 8000.00 root test.tpk.c1 -│ └─Selection_20 8000.00 root not(isnull(test.tpk.c1)) -│ └─CTEFullScan_21 10000.00 root CTE:dt2 data:CTE_0 -└─TableReader_18(Probe) 10000.00 root data:TableFullScan_17 - └─TableFullScan_17 10000.00 cop[tikv] table:dt1 keep order:true, stats:pseudo -CTE_0 10000.00 root Non-Recursive CTE -└─TableReader_12(Seed Part) 10000.00 root data:TableFullScan_11 - └─TableFullScan_11 10000.00 cop[tikv] table:tpk keep order:false, stats:pseudo +MergeJoin_26 8000.00 root inner join, left key:test.tpk.c1, right key:test.tpk.c1 +├─Sort_24(Build) 6400.00 root test.tpk.c1 +│ └─Selection_22 6400.00 root not(isnull(test.tpk.c1)) +│ └─CTEFullScan_23 8000.00 root CTE:dt2 data:CTE_0 +└─TableReader_20(Probe) 10000.00 root data:TableFullScan_19 + └─TableFullScan_19 10000.00 cop[tikv] table:dt1 keep order:true, stats:pseudo +CTE_0 8000.00 root Non-Recursive CTE +└─Selection_11(Seed Part) 8000.00 root not(isnull(test.tpk.c1)) + └─TableReader_14 10000.00 root data:TableFullScan_13 + └─TableFullScan_13 10000.00 cop[tikv] table:tpk keep order:false, stats:pseudo with cte1 as (select c1 from tpk) select /*+ MERGE_JOIN(dt1, dt2) */ * from tpk dt1 inner join cte1 dt2 on dt2.c1 = dt1.c1 order by 1, 2; c1 c1 1 1 @@ -428,18 +430,19 @@ c1 c1 // Sort should not exist, because we have order by in CTE definition. Not the best plan for now(#25674). explain with cte1 as (select c1 from t1 order by c1) select /*+ MERGE_JOIN(dt1, dt2) */ * from t1 dt1 inner join cte1 dt2 on dt2.c1 = dt1.c1 order by 1, 2; id estRows task access object operator info -MergeJoin_30 10000.00 root inner join, left key:test.t1.c1, right key:test.t1.c1 -├─Sort_28(Build) 8000.00 root test.t1.c1 -│ └─Selection_26 8000.00 root not(isnull(test.t1.c1)) -│ └─CTEFullScan_27 10000.00 root CTE:dt2 data:CTE_0 -└─Sort_24(Probe) 9990.00 root test.t1.c1 - └─TableReader_23 9990.00 root data:Selection_22 - └─Selection_22 9990.00 cop[tikv] not(isnull(test.t1.c1)) - └─TableFullScan_21 10000.00 cop[tikv] table:dt1 keep order:false, stats:pseudo -CTE_0 10000.00 root Non-Recursive CTE -└─Sort_11(Seed Part) 10000.00 root test.t1.c1 - └─TableReader_15 10000.00 root data:TableFullScan_14 - └─TableFullScan_14 10000.00 cop[tikv] table:t1 keep order:false, stats:pseudo +MergeJoin_32 8000.00 root inner join, left key:test.t1.c1, right key:test.t1.c1 +├─Sort_30(Build) 6400.00 root test.t1.c1 +│ └─Selection_28 6400.00 root not(isnull(test.t1.c1)) +│ └─CTEFullScan_29 8000.00 root CTE:dt2 data:CTE_0 +└─Sort_26(Probe) 9990.00 root test.t1.c1 + └─TableReader_25 9990.00 root data:Selection_24 + └─Selection_24 9990.00 cop[tikv] not(isnull(test.t1.c1)) + └─TableFullScan_23 10000.00 cop[tikv] table:dt1 keep order:false, stats:pseudo +CTE_0 8000.00 root Non-Recursive CTE +└─Selection_12(Seed Part) 8000.00 root not(isnull(test.t1.c1)) + └─Sort_13 10000.00 root test.t1.c1 + └─TableReader_17 10000.00 root data:TableFullScan_16 + └─TableFullScan_16 10000.00 cop[tikv] table:t1 keep order:false, stats:pseudo with cte1 as (select c1 from t1 order by c1) select /*+ MERGE_JOIN(dt1, dt2) */ * from t1 dt1 inner join cte1 dt2 on dt2.c1 = dt1.c1 order by 1, 2; c1 c1 1 1 @@ -500,18 +503,19 @@ c1 c1 // Expect Sort operator in CTE definition. explain with cte1 as (select c1 from t1 order by c1) select /*+ MERGE_JOIN(dt1, dt2) */ * from t1 dt1 inner join cte1 dt2 on dt2.c1 = dt1.c1 order by 1, 2; id estRows task access object operator info -MergeJoin_30 10000.00 root inner join, left key:test.t1.c1, right key:test.t1.c1 -├─Sort_28(Build) 8000.00 root test.t1.c1 -│ └─Selection_26 8000.00 root not(isnull(test.t1.c1)) -│ └─CTEFullScan_27 10000.00 root CTE:dt2 data:CTE_0 -└─Sort_24(Probe) 9990.00 root test.t1.c1 - └─TableReader_23 9990.00 root data:Selection_22 - └─Selection_22 9990.00 cop[tikv] not(isnull(test.t1.c1)) - └─TableFullScan_21 10000.00 cop[tikv] table:dt1 keep order:false, stats:pseudo -CTE_0 10000.00 root Non-Recursive CTE -└─Sort_11(Seed Part) 10000.00 root test.t1.c1 - └─TableReader_15 10000.00 root data:TableFullScan_14 - └─TableFullScan_14 10000.00 cop[tikv] table:t1 keep order:false, stats:pseudo +MergeJoin_32 8000.00 root inner join, left key:test.t1.c1, right key:test.t1.c1 +├─Sort_30(Build) 6400.00 root test.t1.c1 +│ └─Selection_28 6400.00 root not(isnull(test.t1.c1)) +│ └─CTEFullScan_29 8000.00 root CTE:dt2 data:CTE_0 +└─Sort_26(Probe) 9990.00 root test.t1.c1 + └─TableReader_25 9990.00 root data:Selection_24 + └─Selection_24 9990.00 cop[tikv] not(isnull(test.t1.c1)) + └─TableFullScan_23 10000.00 cop[tikv] table:dt1 keep order:false, stats:pseudo +CTE_0 8000.00 root Non-Recursive CTE +└─Selection_12(Seed Part) 8000.00 root not(isnull(test.t1.c1)) + └─Sort_13 10000.00 root test.t1.c1 + └─TableReader_17 10000.00 root data:TableFullScan_16 + └─TableFullScan_16 10000.00 cop[tikv] table:t1 keep order:false, stats:pseudo with cte1 as (select c1 from t1 order by c1) select /*+ MERGE_JOIN(dt1, dt2) */ * from t1 dt1 inner join cte1 dt2 on dt2.c1 = dt1.c1 order by 1, 2; c1 c1 1 1 @@ -525,17 +529,18 @@ c1 c1 // Sort should not exist, because tpk is ordered. Not the best plan for now(#25674). explain with cte1 as (select c1 from tpk order by c1) select /*+ MERGE_JOIN(dt1, dt2) */ * from t1 dt1 inner join cte1 dt2 on dt2.c1 = dt1.c1 order by 1, 2; id estRows task access object operator info -MergeJoin_32 10000.00 root inner join, left key:test.t1.c1, right key:test.tpk.c1 -├─Sort_30(Build) 8000.00 root test.tpk.c1 -│ └─Selection_28 8000.00 root not(isnull(test.tpk.c1)) -│ └─CTEFullScan_29 10000.00 root CTE:dt2 data:CTE_0 -└─Sort_26(Probe) 9990.00 root test.t1.c1 - └─TableReader_25 9990.00 root data:Selection_24 - └─Selection_24 9990.00 cop[tikv] not(isnull(test.t1.c1)) - └─TableFullScan_23 10000.00 cop[tikv] table:dt1 keep order:false, stats:pseudo -CTE_0 10000.00 root Non-Recursive CTE -└─TableReader_18(Seed Part) 10000.00 root data:TableFullScan_17 - └─TableFullScan_17 10000.00 cop[tikv] table:tpk keep order:true, stats:pseudo +MergeJoin_34 8000.00 root inner join, left key:test.t1.c1, right key:test.tpk.c1 +├─Sort_32(Build) 6400.00 root test.tpk.c1 +│ └─Selection_30 6400.00 root not(isnull(test.tpk.c1)) +│ └─CTEFullScan_31 8000.00 root CTE:dt2 data:CTE_0 +└─Sort_28(Probe) 9990.00 root test.t1.c1 + └─TableReader_27 9990.00 root data:Selection_26 + └─Selection_26 9990.00 cop[tikv] not(isnull(test.t1.c1)) + └─TableFullScan_25 10000.00 cop[tikv] table:dt1 keep order:false, stats:pseudo +CTE_0 8000.00 root Non-Recursive CTE +└─Selection_12(Seed Part) 8000.00 root not(isnull(test.tpk.c1)) + └─TableReader_20 10000.00 root data:TableFullScan_19 + └─TableFullScan_19 10000.00 cop[tikv] table:tpk keep order:true, stats:pseudo with cte1 as (select c1 from tpk order by c1) select /*+ MERGE_JOIN(dt1, dt2) */ * from t1 dt1 inner join cte1 dt2 on dt2.c1 = dt1.c1 order by 1, 2; c1 c1 1 1 @@ -545,15 +550,16 @@ c1 c1 // HashJoin. No need to sort explain with cte1 as (select c1 from t1) select /*+ HASH_JOIN(dt1, dt2) */ * from t1 dt1 inner join cte1 dt2 on dt2.c1 = 1 order by 1, 2; id estRows task access object operator info -Sort_13 80000000.00 root test.t1.c1, test.t1.c1 -└─HashJoin_16 80000000.00 root CARTESIAN inner join - ├─Selection_20(Build) 8000.00 root eq(test.t1.c1, 1) - │ └─CTEFullScan_21 10000.00 root CTE:dt2 data:CTE_0 - └─TableReader_19(Probe) 10000.00 root data:TableFullScan_18 - └─TableFullScan_18 10000.00 cop[tikv] table:dt1 keep order:false, stats:pseudo -CTE_0 10000.00 root Non-Recursive CTE -└─TableReader_12(Seed Part) 10000.00 root data:TableFullScan_11 - └─TableFullScan_11 10000.00 cop[tikv] table:t1 keep order:false, stats:pseudo +Sort_15 64000000.00 root test.t1.c1, test.t1.c1 +└─HashJoin_18 64000000.00 root CARTESIAN inner join + ├─Selection_22(Build) 6400.00 root eq(test.t1.c1, 1) + │ └─CTEFullScan_23 8000.00 root CTE:dt2 data:CTE_0 + └─TableReader_21(Probe) 10000.00 root data:TableFullScan_20 + └─TableFullScan_20 10000.00 cop[tikv] table:dt1 keep order:false, stats:pseudo +CTE_0 8000.00 root Non-Recursive CTE +└─Selection_11(Seed Part) 8000.00 root eq(test.t1.c1, 1) + └─TableReader_14 10000.00 root data:TableFullScan_13 + └─TableFullScan_13 10000.00 cop[tikv] table:t1 keep order:false, stats:pseudo with cte1 as (select c1 from t1) select /*+ HASH_JOIN(dt1, dt2) */ * from t1 dt1 inner join cte1 dt2 on dt2.c1 = 1 order by 1, 2; c1 c1 1 1 @@ -566,15 +572,16 @@ c1 c1 2 1 explain with cte1 as (select c1 from tpk) select /*+ HASH_JOIN(dt1, dt2) */ * from t1 dt1 inner join cte1 dt2 on dt2.c1 = 1 order by 1, 2; id estRows task access object operator info -Sort_13 80000000.00 root test.t1.c1, test.tpk.c1 -└─HashJoin_16 80000000.00 root CARTESIAN inner join - ├─Selection_20(Build) 8000.00 root eq(test.tpk.c1, 1) - │ └─CTEFullScan_21 10000.00 root CTE:dt2 data:CTE_0 - └─TableReader_19(Probe) 10000.00 root data:TableFullScan_18 - └─TableFullScan_18 10000.00 cop[tikv] table:dt1 keep order:false, stats:pseudo -CTE_0 10000.00 root Non-Recursive CTE -└─TableReader_12(Seed Part) 10000.00 root data:TableFullScan_11 - └─TableFullScan_11 10000.00 cop[tikv] table:tpk keep order:false, stats:pseudo +Sort_15 64000000.00 root test.t1.c1, test.tpk.c1 +└─HashJoin_18 64000000.00 root CARTESIAN inner join + ├─Selection_22(Build) 6400.00 root eq(test.tpk.c1, 1) + │ └─CTEFullScan_23 8000.00 root CTE:dt2 data:CTE_0 + └─TableReader_21(Probe) 10000.00 root data:TableFullScan_20 + └─TableFullScan_20 10000.00 cop[tikv] table:dt1 keep order:false, stats:pseudo +CTE_0 8000.00 root Non-Recursive CTE +└─Selection_11(Seed Part) 8000.00 root eq(test.tpk.c1, 1) + └─TableReader_14 10000.00 root data:TableFullScan_13 + └─TableFullScan_13 10000.00 cop[tikv] table:tpk keep order:false, stats:pseudo with cte1 as (select c1 from tpk) select /*+ HASH_JOIN(dt1, dt2) */ * from t1 dt1 inner join cte1 dt2 on dt2.c1 = 1 order by 1, 2; c1 c1 1 1 @@ -589,19 +596,20 @@ create table tpk1(c1 int primary key); insert into tpk1 values(1), (2), (3); explain with cte1 as (select c1 from tpk) select /*+ merge_join(dt1, dt2) */ * from tpk1 dt1 inner join cte1 dt2 inner join cte1 dt3 on dt1.c1 = dt2.c1 and dt2.c1 = dt3.c1; id estRows task access object operator info -Projection_18 12500.00 root test.tpk1.c1, test.tpk.c1, test.tpk.c1 -└─HashJoin_20 12500.00 root inner join, equal:[eq(test.tpk.c1, test.tpk.c1)] - ├─Selection_21(Build) 8000.00 root not(isnull(test.tpk.c1)) - │ └─CTEFullScan_22 10000.00 root CTE:dt3 data:CTE_0 - └─MergeJoin_23(Probe) 10000.00 root inner join, left key:test.tpk1.c1, right key:test.tpk.c1 - ├─Sort_29(Build) 8000.00 root test.tpk.c1 - │ └─Selection_27 8000.00 root not(isnull(test.tpk.c1)) - │ └─CTEFullScan_28 10000.00 root CTE:dt2 data:CTE_0 - └─TableReader_25(Probe) 10000.00 root data:TableFullScan_24 - └─TableFullScan_24 10000.00 cop[tikv] table:dt1 keep order:true, stats:pseudo -CTE_0 10000.00 root Non-Recursive CTE -└─TableReader_14(Seed Part) 10000.00 root data:TableFullScan_13 - └─TableFullScan_13 10000.00 cop[tikv] table:tpk keep order:false, stats:pseudo +Projection_20 10000.00 root test.tpk1.c1, test.tpk.c1, test.tpk.c1 +└─HashJoin_22 10000.00 root inner join, equal:[eq(test.tpk.c1, test.tpk.c1)] + ├─Selection_23(Build) 6400.00 root not(isnull(test.tpk.c1)) + │ └─CTEFullScan_24 8000.00 root CTE:dt3 data:CTE_0 + └─MergeJoin_25(Probe) 8000.00 root inner join, left key:test.tpk1.c1, right key:test.tpk.c1 + ├─Sort_31(Build) 6400.00 root test.tpk.c1 + │ └─Selection_29 6400.00 root not(isnull(test.tpk.c1)) + │ └─CTEFullScan_30 8000.00 root CTE:dt2 data:CTE_0 + └─TableReader_27(Probe) 10000.00 root data:TableFullScan_26 + └─TableFullScan_26 10000.00 cop[tikv] table:dt1 keep order:true, stats:pseudo +CTE_0 8000.00 root Non-Recursive CTE +└─Selection_13(Seed Part) 8000.00 root or(not(isnull(test.tpk.c1)), not(isnull(test.tpk.c1))) + └─TableReader_16 10000.00 root data:TableFullScan_15 + └─TableFullScan_15 10000.00 cop[tikv] table:tpk keep order:false, stats:pseudo with cte1 as (select c1 from tpk) select /*+ merge_join(dt1, dt2) */ * from tpk1 dt1 inner join cte1 dt2 inner join cte1 dt3 on dt1.c1 = dt2.c1 and dt2.c1 = dt3.c1; c1 c1 c1 1 1 1 @@ -617,18 +625,18 @@ insert into t2 values(1, 1); insert into t2 values(3, 2); explain select * from t1 where c1 > all(with cte1 as (select c1 from t2 where t2.c2 = t1.c2) select c1 from cte1); id estRows task access object operator info -Projection_17 10000.00 root test.t1.c1, test.t1.c2 -└─Apply_19 10000.00 root CARTESIAN inner join, other cond:or(and(gt(test.t1.c1, Column#8), if(ne(Column#9, 0), NULL, 1)), or(eq(Column#10, 0), if(isnull(test.t1.c1), NULL, 0))) - ├─TableReader_21(Build) 10000.00 root data:TableFullScan_20 - │ └─TableFullScan_20 10000.00 cop[tikv] table:t1 keep order:false, stats:pseudo - └─HashAgg_22(Probe) 1.00 root funcs:max(Column#13)->Column#8, funcs:sum(Column#14)->Column#9, funcs:count(1)->Column#10 - └─Projection_26 10.00 root test.t2.c1, cast(isnull(test.t2.c1), decimal(20,0) BINARY)->Column#14 - └─CTEFullScan_24 10.00 root CTE:cte1 data:CTE_0 +Projection_18 10000.00 root test.t1.c1, test.t1.c2 +└─Apply_20 10000.00 root CARTESIAN inner join, other cond:or(and(gt(test.t1.c1, Column#8), if(ne(Column#9, 0), NULL, 1)), or(eq(Column#10, 0), if(isnull(test.t1.c1), NULL, 0))) + ├─TableReader_22(Build) 10000.00 root data:TableFullScan_21 + │ └─TableFullScan_21 10000.00 cop[tikv] table:t1 keep order:false, stats:pseudo + └─HashAgg_23(Probe) 1.00 root funcs:max(Column#13)->Column#8, funcs:sum(Column#14)->Column#9, funcs:count(1)->Column#10 + └─Projection_27 10.00 root test.t2.c1, cast(isnull(test.t2.c1), decimal(20,0) BINARY)->Column#14 + └─CTEFullScan_25 10.00 root CTE:cte1 data:CTE_0 CTE_0 10.00 root Non-Recursive CTE -└─Projection_12(Seed Part) 10.00 root test.t2.c1 - └─TableReader_15 10.00 root data:Selection_14 - └─Selection_14 10.00 cop[tikv] eq(test.t2.c2, test.t1.c2) - └─TableFullScan_13 10000.00 cop[tikv] table:t2 keep order:false, stats:pseudo +└─Projection_13(Seed Part) 10.00 root test.t2.c1 + └─TableReader_16 10.00 root data:Selection_15 + └─Selection_15 10.00 cop[tikv] eq(test.t2.c2, test.t1.c2) + └─TableFullScan_14 10000.00 cop[tikv] table:t2 keep order:false, stats:pseudo select * from t1 where c1 > all(with cte1 as (select c1 from t2 where t2.c2 = t1.c2) select c1 from cte1); c1 c2 2 1 @@ -636,15 +644,15 @@ c1 c2 insert into t1 values(2, 3); explain select * from t1 where exists(with cte1 as (select c1 from t2 where t2.c2 = t1.c2) select c1 from cte1); id estRows task access object operator info -Apply_16 10000.00 root CARTESIAN semi join -├─TableReader_18(Build) 10000.00 root data:TableFullScan_17 -│ └─TableFullScan_17 10000.00 cop[tikv] table:t1 keep order:false, stats:pseudo -└─CTEFullScan_19(Probe) 10.00 root CTE:cte1 data:CTE_0 +Apply_17 10000.00 root CARTESIAN semi join +├─TableReader_19(Build) 10000.00 root data:TableFullScan_18 +│ └─TableFullScan_18 10000.00 cop[tikv] table:t1 keep order:false, stats:pseudo +└─CTEFullScan_20(Probe) 10.00 root CTE:cte1 data:CTE_0 CTE_0 10.00 root Non-Recursive CTE -└─Projection_10(Seed Part) 10.00 root test.t2.c1 - └─TableReader_13 10.00 root data:Selection_12 - └─Selection_12 10.00 cop[tikv] eq(test.t2.c2, test.t1.c2) - └─TableFullScan_11 10000.00 cop[tikv] table:t2 keep order:false, stats:pseudo +└─Projection_11(Seed Part) 10.00 root test.t2.c1 + └─TableReader_14 10.00 root data:Selection_13 + └─Selection_13 10.00 cop[tikv] eq(test.t2.c2, test.t1.c2) + └─TableFullScan_12 10000.00 cop[tikv] table:t2 keep order:false, stats:pseudo select * from t1 where exists(with cte1 as (select c1 from t2 where t2.c2 = t1.c2) select c1 from cte1); c1 c2 2 1 diff --git a/cmd/explaintest/r/explain_cte.result b/cmd/explaintest/r/explain_cte.result index 59fbda4dc20e9..241cf76bf001f 100644 --- a/cmd/explaintest/r/explain_cte.result +++ b/cmd/explaintest/r/explain_cte.result @@ -67,17 +67,18 @@ CTE_0 2.00 root Recursive CTE └─CTETable_17 1.00 root Scan on CTE_0 explain with cte(a) as (with recursive cte1(a) as (select 1 union select a + 1 from cte1 where a < 10) select * from cte1) select * from cte t1, cte t2; id estRows task access object operator info -HashJoin_24 4.00 root CARTESIAN inner join -├─CTEFullScan_27(Build) 2.00 root CTE:t2 data:CTE_0 -└─CTEFullScan_26(Probe) 2.00 root CTE:t1 data:CTE_0 -CTE_0 2.00 root Non-Recursive CTE -└─CTEFullScan_21(Seed Part) 2.00 root CTE:cte1 data:CTE_1 +HashJoin_26 2.56 root CARTESIAN inner join +├─CTEFullScan_29(Build) 1.60 root CTE:t2 data:CTE_0 +└─CTEFullScan_28(Probe) 1.60 root CTE:t1 data:CTE_0 +CTE_0 1.60 root Non-Recursive CTE +└─Selection_21(Seed Part) 1.60 root 1 + └─CTEFullScan_23 2.00 root CTE:cte1 data:CTE_1 CTE_1 2.00 root Recursive CTE -├─Projection_15(Seed Part) 1.00 root 1->Column#2 -│ └─TableDual_16 1.00 root rows:1 -└─Projection_17(Recursive Part) 0.80 root cast(plus(Column#3, 1), bigint(1) BINARY)->Column#5 - └─Selection_18 0.80 root lt(Column#3, 10) - └─CTETable_19 1.00 root Scan on CTE_1 +├─Projection_16(Seed Part) 1.00 root 1->Column#2 +│ └─TableDual_17 1.00 root rows:1 +└─Projection_18(Recursive Part) 0.80 root cast(plus(Column#3, 1), bigint(1) BINARY)->Column#5 + └─Selection_19 0.80 root lt(Column#3, 10) + └─CTETable_20 1.00 root Scan on CTE_1 explain with recursive cte1(a) as (select 1 union select a+1 from cte1 where a < 10), cte2(a) as (select c2 from t1 union select a+1 from cte2 where a < 10) select * from cte1, cte2; id estRows task access object operator info HashJoin_37 16002.00 root CARTESIAN inner join @@ -97,14 +98,15 @@ CTE_1 8001.00 root Recursive CTE └─CTETable_33 10000.00 root Scan on CTE_1 explain with q(a,b) as (select * from t1) select /*+ merge(q) no_merge(q1) */ * from q, q q1 where q.a=1 and q1.a=2; id estRows task access object operator info -HashJoin_17 64000000.00 root CARTESIAN inner join -├─Selection_21(Build) 8000.00 root eq(test.t1.c1, 2) -│ └─CTEFullScan_22 10000.00 root CTE:q1 data:CTE_0 -└─Selection_19(Probe) 8000.00 root eq(test.t1.c1, 1) - └─CTEFullScan_20 10000.00 root CTE:q data:CTE_0 -CTE_0 10000.00 root Non-Recursive CTE -└─TableReader_12(Seed Part) 10000.00 root data:TableFullScan_11 - └─TableFullScan_11 10000.00 cop[tikv] table:t1 keep order:false, stats:pseudo +HashJoin_19 40960000.00 root CARTESIAN inner join +├─Selection_23(Build) 6400.00 root eq(test.t1.c1, 2) +│ └─CTEFullScan_24 8000.00 root CTE:q1 data:CTE_0 +└─Selection_21(Probe) 6400.00 root eq(test.t1.c1, 1) + └─CTEFullScan_22 8000.00 root CTE:q data:CTE_0 +CTE_0 8000.00 root Non-Recursive CTE +└─Selection_11(Seed Part) 8000.00 root or(eq(test.t1.c1, 1), eq(test.t1.c1, 2)) + └─TableReader_14 10000.00 root data:TableFullScan_13 + └─TableFullScan_13 10000.00 cop[tikv] table:t1 keep order:false, stats:pseudo explain with recursive cte(a,b) as (select 1, concat('a', 1) union select a+1, concat(b, 1) from cte where a < 5) select * from cte; id estRows task access object operator info CTEFullScan_17 2.00 root CTE:cte data:CTE_0 @@ -202,3 +204,243 @@ id estRows task access object operator info CTEFullScan_18 0.00 root CTE:cte1 data:CTE_0 CTE_0 0.00 root Non-Recursive CTE └─TableDual_16(Seed Part) 0.00 root rows:0 +CREATE TABLE `customer` ( +`c_customer_sk` int(11) NOT NULL, +`c_customer_id` char(16) NOT NULL, +`c_current_cdemo_sk` int(11) DEFAULT NULL, +`c_current_hdemo_sk` int(11) DEFAULT NULL, +`c_current_addr_sk` int(11) DEFAULT NULL, +`c_first_shipto_date_sk` int(11) DEFAULT NULL, +`c_first_sales_date_sk` int(11) DEFAULT NULL, +`c_salutation` char(10) DEFAULT NULL, +`c_first_name` char(20) DEFAULT NULL, +`c_last_name` char(30) DEFAULT NULL, +`c_preferred_cust_flag` char(1) DEFAULT NULL, +`c_birth_day` int(11) DEFAULT NULL, +`c_birth_month` int(11) DEFAULT NULL, +`c_birth_year` int(11) DEFAULT NULL, +`c_birth_country` varchar(20) DEFAULT NULL, +`c_login` char(13) DEFAULT NULL, +`c_email_address` char(50) DEFAULT NULL, +`c_last_review_date_sk` int(11) DEFAULT NULL, +PRIMARY KEY (`c_customer_sk`) /*T![clustered_index] NONCLUSTERED */ +); +CREATE TABLE `store_sales` ( +`ss_sold_date_sk` int(11) DEFAULT NULL, +`ss_sold_time_sk` int(11) DEFAULT NULL, +`ss_item_sk` int(11) NOT NULL, +`ss_customer_sk` int(11) DEFAULT NULL, +`ss_cdemo_sk` int(11) DEFAULT NULL, +`ss_hdemo_sk` int(11) DEFAULT NULL, +`ss_addr_sk` int(11) DEFAULT NULL, +`ss_store_sk` int(11) DEFAULT NULL, +`ss_promo_sk` int(11) DEFAULT NULL, +`ss_ticket_number` int(11) NOT NULL, +`ss_quantity` int(11) DEFAULT NULL, +`ss_wholesale_cost` decimal(7,2) DEFAULT NULL, +`ss_list_price` decimal(7,2) DEFAULT NULL, +`ss_sales_price` decimal(7,2) DEFAULT NULL, +`ss_ext_discount_amt` decimal(7,2) DEFAULT NULL, +`ss_ext_sales_price` decimal(7,2) DEFAULT NULL, +`ss_ext_wholesale_cost` decimal(7,2) DEFAULT NULL, +`ss_ext_list_price` decimal(7,2) DEFAULT NULL, +`ss_ext_tax` decimal(7,2) DEFAULT NULL, +`ss_coupon_amt` decimal(7,2) DEFAULT NULL, +`ss_net_paid` decimal(7,2) DEFAULT NULL, +`ss_net_paid_inc_tax` decimal(7,2) DEFAULT NULL, +`ss_net_profit` decimal(7,2) DEFAULT NULL, +PRIMARY KEY (`ss_item_sk`,`ss_ticket_number`) /*T![clustered_index] NONCLUSTERED */ +); +CREATE TABLE `date_dim` ( +`d_date_sk` int(11) NOT NULL, +`d_date_id` char(16) NOT NULL, +`d_date` date DEFAULT NULL, +`d_month_seq` int(11) DEFAULT NULL, +`d_week_seq` int(11) DEFAULT NULL, +`d_quarter_seq` int(11) DEFAULT NULL, +`d_year` int(11) DEFAULT NULL, +`d_dow` int(11) DEFAULT NULL, +`d_moy` int(11) DEFAULT NULL, +`d_dom` int(11) DEFAULT NULL, +`d_qoy` int(11) DEFAULT NULL, +`d_fy_year` int(11) DEFAULT NULL, +`d_fy_quarter_seq` int(11) DEFAULT NULL, +`d_fy_week_seq` int(11) DEFAULT NULL, +`d_day_name` char(9) DEFAULT NULL, +`d_quarter_name` char(6) DEFAULT NULL, +`d_holiday` char(1) DEFAULT NULL, +`d_weekend` char(1) DEFAULT NULL, +`d_following_holiday` char(1) DEFAULT NULL, +`d_first_dom` int(11) DEFAULT NULL, +`d_last_dom` int(11) DEFAULT NULL, +`d_same_day_ly` int(11) DEFAULT NULL, +`d_same_day_lq` int(11) DEFAULT NULL, +`d_current_day` char(1) DEFAULT NULL, +`d_current_week` char(1) DEFAULT NULL, +`d_current_month` char(1) DEFAULT NULL, +`d_current_quarter` char(1) DEFAULT NULL, +`d_current_year` char(1) DEFAULT NULL, +PRIMARY KEY (`d_date_sk`) /*T![clustered_index] NONCLUSTERED */ +); +CREATE TABLE `web_sales` ( +`ws_sold_date_sk` int(11) DEFAULT NULL, +`ws_sold_time_sk` int(11) DEFAULT NULL, +`ws_ship_date_sk` int(11) DEFAULT NULL, +`ws_item_sk` int(11) NOT NULL, +`ws_bill_customer_sk` int(11) DEFAULT NULL, +`ws_bill_cdemo_sk` int(11) DEFAULT NULL, +`ws_bill_hdemo_sk` int(11) DEFAULT NULL, +`ws_bill_addr_sk` int(11) DEFAULT NULL, +`ws_ship_customer_sk` int(11) DEFAULT NULL, +`ws_ship_cdemo_sk` int(11) DEFAULT NULL, +`ws_ship_hdemo_sk` int(11) DEFAULT NULL, +`ws_ship_addr_sk` int(11) DEFAULT NULL, +`ws_web_page_sk` int(11) DEFAULT NULL, +`ws_web_site_sk` int(11) DEFAULT NULL, +`ws_ship_mode_sk` int(11) DEFAULT NULL, +`ws_warehouse_sk` int(11) DEFAULT NULL, +`ws_promo_sk` int(11) DEFAULT NULL, +`ws_order_number` int(11) NOT NULL, +`ws_quantity` int(11) DEFAULT NULL, +`ws_wholesale_cost` decimal(7,2) DEFAULT NULL, +`ws_list_price` decimal(7,2) DEFAULT NULL, +`ws_sales_price` decimal(7,2) DEFAULT NULL, +`ws_ext_discount_amt` decimal(7,2) DEFAULT NULL, +`ws_ext_sales_price` decimal(7,2) DEFAULT NULL, +`ws_ext_wholesale_cost` decimal(7,2) DEFAULT NULL, +`ws_ext_list_price` decimal(7,2) DEFAULT NULL, +`ws_ext_tax` decimal(7,2) DEFAULT NULL, +`ws_coupon_amt` decimal(7,2) DEFAULT NULL, +`ws_ext_ship_cost` decimal(7,2) DEFAULT NULL, +`ws_net_paid` decimal(7,2) DEFAULT NULL, +`ws_net_paid_inc_tax` decimal(7,2) DEFAULT NULL, +`ws_net_paid_inc_ship` decimal(7,2) DEFAULT NULL, +`ws_net_paid_inc_ship_tax` decimal(7,2) DEFAULT NULL, +`ws_net_profit` decimal(7,2) DEFAULT NULL, +PRIMARY KEY (`ws_item_sk`,`ws_order_number`) /*T![clustered_index] NONCLUSTERED */ +); +desc format='brief' with year_total as ( +select c_customer_id customer_id +,c_first_name customer_first_name +,c_last_name customer_last_name +,c_preferred_cust_flag customer_preferred_cust_flag +,c_birth_country customer_birth_country +,c_login customer_login +,c_email_address customer_email_address +,d_year dyear +,sum(ss_ext_list_price-ss_ext_discount_amt) year_total +,'s' sale_type +from customer +,store_sales +,date_dim +where c_customer_sk = ss_customer_sk +and ss_sold_date_sk = d_date_sk +group by c_customer_id +,c_first_name +,c_last_name +,c_preferred_cust_flag +,c_birth_country +,c_login +,c_email_address +,d_year +union all +select c_customer_id customer_id +,c_first_name customer_first_name +,c_last_name customer_last_name +,c_preferred_cust_flag customer_preferred_cust_flag +,c_birth_country customer_birth_country +,c_login customer_login +,c_email_address customer_email_address +,d_year dyear +,sum(ws_ext_list_price-ws_ext_discount_amt) year_total +,'w' sale_type +from customer +,web_sales +,date_dim +where c_customer_sk = ws_bill_customer_sk +and ws_sold_date_sk = d_date_sk +group by c_customer_id +,c_first_name +,c_last_name +,c_preferred_cust_flag +,c_birth_country +,c_login +,c_email_address +,d_year +) +select +t_s_secyear.customer_id +,t_s_secyear.customer_first_name +,t_s_secyear.customer_last_name +,t_s_secyear.customer_email_address +from year_total t_s_firstyear +,year_total t_s_secyear +,year_total t_w_firstyear +,year_total t_w_secyear +where t_s_secyear.customer_id = t_s_firstyear.customer_id +and t_s_firstyear.customer_id = t_w_secyear.customer_id +and t_s_firstyear.customer_id = t_w_firstyear.customer_id +and t_s_firstyear.sale_type = 's' +and t_w_firstyear.sale_type = 'w' +and t_s_secyear.sale_type = 's' +and t_w_secyear.sale_type = 'w' +and t_s_firstyear.dyear = 2001 +and t_s_secyear.dyear = 2001+1 +and t_w_firstyear.dyear = 2001 +and t_w_secyear.dyear = 2001+1 +and t_s_firstyear.year_total > 0 +and t_w_firstyear.year_total > 0 +and case when t_w_firstyear.year_total > 0 then t_w_secyear.year_total / t_w_firstyear.year_total else 0.0 end +> case when t_s_firstyear.year_total > 0 then t_s_secyear.year_total / t_s_firstyear.year_total else 0.0 end +order by t_s_secyear.customer_id +,t_s_secyear.customer_first_name +,t_s_secyear.customer_last_name +,t_s_secyear.customer_email_address +limit 100; +id estRows task access object operator info +TopN 40.00 root Column#180, Column#181, Column#182, Column#186, offset:0, count:100 +└─HashJoin 40.00 root inner join, equal:[eq(Column#170, Column#200)], other cond:gt(case(gt(Column#198, 0), div(Column#208, Column#198), 0.0), case(gt(Column#178, 0), div(Column#188, Column#178), 0.0)) + ├─Selection(Build) 40.00 root eq(Column#207, 2002), eq(Column#209, "w"), not(isnull(Column#200)) + │ └─CTEFullScan 50.00 root CTE:t_w_secyear data:CTE_0 + └─HashJoin(Probe) 40.00 root inner join, equal:[eq(Column#170, Column#190)] + ├─Selection(Build) 40.00 root eq(Column#197, 2001), eq(Column#199, "w"), gt(Column#198, 0), not(isnull(Column#190)) + │ └─CTEFullScan 50.00 root CTE:t_w_firstyear data:CTE_0 + └─HashJoin(Probe) 40.00 root inner join, equal:[eq(Column#170, Column#180)] + ├─Selection(Build) 40.00 root eq(Column#187, 2002), eq(Column#189, "s"), not(isnull(Column#180)) + │ └─CTEFullScan 50.00 root CTE:t_s_secyear data:CTE_0 + └─Selection(Probe) 40.00 root eq(Column#177, 2001), eq(Column#179, "s"), gt(Column#178, 0), not(isnull(Column#170)) + └─CTEFullScan 50.00 root CTE:t_s_firstyear data:CTE_0 +CTE_0 50.00 root Non-Recursive CTE +└─Union(Seed Part) 50.00 root + ├─Projection 25.00 root test.customer.c_customer_id, test.customer.c_first_name, test.customer.c_last_name, test.customer.c_preferred_cust_flag, test.customer.c_birth_country, test.customer.c_login, test.customer.c_email_address, test.date_dim.d_year, Column#73, s->Column#169 + │ └─Selection 25.00 root or(or(and(1, and(eq(test.date_dim.d_year, 2001), gt(Column#73, 0))), and(1, eq(test.date_dim.d_year, 2002))), 0) + │ └─HashAgg 31.25 root group by:Column#233, Column#234, Column#235, Column#236, Column#237, Column#238, Column#239, Column#240, funcs:sum(Column#224)->Column#73, funcs:firstrow(Column#225)->test.customer.c_customer_id, funcs:firstrow(Column#226)->test.customer.c_first_name, funcs:firstrow(Column#227)->test.customer.c_last_name, funcs:firstrow(Column#228)->test.customer.c_preferred_cust_flag, funcs:firstrow(Column#229)->test.customer.c_birth_country, funcs:firstrow(Column#230)->test.customer.c_login, funcs:firstrow(Column#231)->test.customer.c_email_address, funcs:firstrow(Column#232)->test.date_dim.d_year + │ └─Projection 31.25 root minus(test.store_sales.ss_ext_list_price, test.store_sales.ss_ext_discount_amt)->Column#224, test.customer.c_customer_id, test.customer.c_first_name, test.customer.c_last_name, test.customer.c_preferred_cust_flag, test.customer.c_birth_country, test.customer.c_login, test.customer.c_email_address, test.date_dim.d_year, test.customer.c_customer_id, test.customer.c_first_name, test.customer.c_last_name, test.customer.c_preferred_cust_flag, test.customer.c_birth_country, test.customer.c_login, test.customer.c_email_address, test.date_dim.d_year + │ └─Projection 31.25 root test.customer.c_customer_id, test.customer.c_first_name, test.customer.c_last_name, test.customer.c_preferred_cust_flag, test.customer.c_birth_country, test.customer.c_login, test.customer.c_email_address, test.store_sales.ss_ext_discount_amt, test.store_sales.ss_ext_list_price, test.date_dim.d_year + │ └─IndexJoin 31.25 root inner join, inner:IndexLookUp, outer key:test.store_sales.ss_customer_sk, inner key:test.customer.c_customer_sk, equal cond:eq(test.store_sales.ss_customer_sk, test.customer.c_customer_sk) + │ ├─HashJoin(Build) 25.00 root inner join, equal:[eq(test.date_dim.d_date_sk, test.store_sales.ss_sold_date_sk)] + │ │ ├─TableReader(Build) 20.00 root data:Selection + │ │ │ └─Selection 20.00 cop[tikv] or(and(1, eq(test.date_dim.d_year, 2001)), or(and(1, eq(test.date_dim.d_year, 2002)), 0)) + │ │ │ └─TableFullScan 10000.00 cop[tikv] table:date_dim keep order:false, stats:pseudo + │ │ └─TableReader(Probe) 9980.01 root data:Selection + │ │ └─Selection 9980.01 cop[tikv] not(isnull(test.store_sales.ss_customer_sk)), not(isnull(test.store_sales.ss_sold_date_sk)) + │ │ └─TableFullScan 10000.00 cop[tikv] table:store_sales keep order:false, stats:pseudo + │ └─IndexLookUp(Probe) 1.00 root + │ ├─IndexRangeScan(Build) 1.00 cop[tikv] table:customer, index:PRIMARY(c_customer_sk) range: decided by [eq(test.customer.c_customer_sk, test.store_sales.ss_customer_sk)], keep order:false, stats:pseudo + │ └─TableRowIDScan(Probe) 1.00 cop[tikv] table:customer keep order:false, stats:pseudo + └─Projection 25.00 root test.customer.c_customer_id, test.customer.c_first_name, test.customer.c_last_name, test.customer.c_preferred_cust_flag, test.customer.c_birth_country, test.customer.c_login, test.customer.c_email_address, test.date_dim.d_year, Column#158, w->Column#169 + └─Selection 25.00 root or(0, or(and(1, and(eq(test.date_dim.d_year, 2001), gt(Column#158, 0))), and(1, eq(test.date_dim.d_year, 2002)))) + └─HashAgg 31.25 root group by:Column#250, Column#251, Column#252, Column#253, Column#254, Column#255, Column#256, Column#257, funcs:sum(Column#241)->Column#158, funcs:firstrow(Column#242)->test.customer.c_customer_id, funcs:firstrow(Column#243)->test.customer.c_first_name, funcs:firstrow(Column#244)->test.customer.c_last_name, funcs:firstrow(Column#245)->test.customer.c_preferred_cust_flag, funcs:firstrow(Column#246)->test.customer.c_birth_country, funcs:firstrow(Column#247)->test.customer.c_login, funcs:firstrow(Column#248)->test.customer.c_email_address, funcs:firstrow(Column#249)->test.date_dim.d_year + └─Projection 31.25 root minus(test.web_sales.ws_ext_list_price, test.web_sales.ws_ext_discount_amt)->Column#241, test.customer.c_customer_id, test.customer.c_first_name, test.customer.c_last_name, test.customer.c_preferred_cust_flag, test.customer.c_birth_country, test.customer.c_login, test.customer.c_email_address, test.date_dim.d_year, test.customer.c_customer_id, test.customer.c_first_name, test.customer.c_last_name, test.customer.c_preferred_cust_flag, test.customer.c_birth_country, test.customer.c_login, test.customer.c_email_address, test.date_dim.d_year + └─Projection 31.25 root test.customer.c_customer_id, test.customer.c_first_name, test.customer.c_last_name, test.customer.c_preferred_cust_flag, test.customer.c_birth_country, test.customer.c_login, test.customer.c_email_address, test.web_sales.ws_ext_discount_amt, test.web_sales.ws_ext_list_price, test.date_dim.d_year + └─IndexJoin 31.25 root inner join, inner:IndexLookUp, outer key:test.web_sales.ws_bill_customer_sk, inner key:test.customer.c_customer_sk, equal cond:eq(test.web_sales.ws_bill_customer_sk, test.customer.c_customer_sk) + ├─HashJoin(Build) 25.00 root inner join, equal:[eq(test.date_dim.d_date_sk, test.web_sales.ws_sold_date_sk)] + │ ├─TableReader(Build) 20.00 root data:Selection + │ │ └─Selection 20.00 cop[tikv] or(0, or(and(1, eq(test.date_dim.d_year, 2001)), and(1, eq(test.date_dim.d_year, 2002)))) + │ │ └─TableFullScan 10000.00 cop[tikv] table:date_dim keep order:false, stats:pseudo + │ └─TableReader(Probe) 9980.01 root data:Selection + │ └─Selection 9980.01 cop[tikv] not(isnull(test.web_sales.ws_bill_customer_sk)), not(isnull(test.web_sales.ws_sold_date_sk)) + │ └─TableFullScan 10000.00 cop[tikv] table:web_sales keep order:false, stats:pseudo + └─IndexLookUp(Probe) 1.00 root + ├─IndexRangeScan(Build) 1.00 cop[tikv] table:customer, index:PRIMARY(c_customer_sk) range: decided by [eq(test.customer.c_customer_sk, test.web_sales.ws_bill_customer_sk)], keep order:false, stats:pseudo + └─TableRowIDScan(Probe) 1.00 cop[tikv] table:customer keep order:false, stats:pseudo diff --git a/cmd/explaintest/t/agg_predicate_pushdown.test b/cmd/explaintest/t/agg_predicate_pushdown.test new file mode 100644 index 0000000000000..0779fe9744030 --- /dev/null +++ b/cmd/explaintest/t/agg_predicate_pushdown.test @@ -0,0 +1,21 @@ +drop database if exists agg_predicate_pushdown; +create database agg_predicate_pushdown; + +create table t(a int, b int, c int); + +desc format='brief' select a, b, avg(c) from t group by a, b, c having +(a > 1) and (a > 2) and 1 and (b > 2) and (avg(c) > 3); + +desc format='brief' select a, b, avg(c) from t group by a, b, c having +(a > 1 or b > 2) and (a > 2 or b < 1) and 1 and (b > 2) and (avg(c) > 3); + +desc format='brief' select a, b, avg(c) from t group by a, b, c having +(a > 1 and b > 2) or (a > 2 and b < 1) or (b > 2 and avg(c) > 3); + +desc format='brief' select a, b, avg(c) from t group by a, b, c having +(a > 1 or avg(c) > 1) and (a < 3); + +desc format='brief' select a, b, avg(c) from t group by a, b, c having +(a > 1 and avg(c) > 1) or (a < 3); + +use test; diff --git a/cmd/explaintest/t/explain_cte.test b/cmd/explaintest/t/explain_cte.test index c657ad5c68898..c7adb659d9cea 100644 --- a/cmd/explaintest/t/explain_cte.test +++ b/cmd/explaintest/t/explain_cte.test @@ -42,3 +42,198 @@ explain with recursive cte1(c1) as (select c1 from t1 union select c1 + 1 c1 fro explain with recursive cte1(c1) as (select c1 from t1 union select c1 from t2 limit 1) select * from cte1; explain with recursive cte1(c1) as (select c1 from t1 union select c1 from t2 limit 100 offset 100) select * from cte1; explain with recursive cte1(c1) as (select c1 from t1 union select c1 from t2 limit 0 offset 0) select * from cte1; + +# TPC-DS Q11 +CREATE TABLE `customer` ( + `c_customer_sk` int(11) NOT NULL, + `c_customer_id` char(16) NOT NULL, + `c_current_cdemo_sk` int(11) DEFAULT NULL, + `c_current_hdemo_sk` int(11) DEFAULT NULL, + `c_current_addr_sk` int(11) DEFAULT NULL, + `c_first_shipto_date_sk` int(11) DEFAULT NULL, + `c_first_sales_date_sk` int(11) DEFAULT NULL, + `c_salutation` char(10) DEFAULT NULL, + `c_first_name` char(20) DEFAULT NULL, + `c_last_name` char(30) DEFAULT NULL, + `c_preferred_cust_flag` char(1) DEFAULT NULL, + `c_birth_day` int(11) DEFAULT NULL, + `c_birth_month` int(11) DEFAULT NULL, + `c_birth_year` int(11) DEFAULT NULL, + `c_birth_country` varchar(20) DEFAULT NULL, + `c_login` char(13) DEFAULT NULL, + `c_email_address` char(50) DEFAULT NULL, + `c_last_review_date_sk` int(11) DEFAULT NULL, + PRIMARY KEY (`c_customer_sk`) /*T![clustered_index] NONCLUSTERED */ +); +CREATE TABLE `store_sales` ( + `ss_sold_date_sk` int(11) DEFAULT NULL, + `ss_sold_time_sk` int(11) DEFAULT NULL, + `ss_item_sk` int(11) NOT NULL, + `ss_customer_sk` int(11) DEFAULT NULL, + `ss_cdemo_sk` int(11) DEFAULT NULL, + `ss_hdemo_sk` int(11) DEFAULT NULL, + `ss_addr_sk` int(11) DEFAULT NULL, + `ss_store_sk` int(11) DEFAULT NULL, + `ss_promo_sk` int(11) DEFAULT NULL, + `ss_ticket_number` int(11) NOT NULL, + `ss_quantity` int(11) DEFAULT NULL, + `ss_wholesale_cost` decimal(7,2) DEFAULT NULL, + `ss_list_price` decimal(7,2) DEFAULT NULL, + `ss_sales_price` decimal(7,2) DEFAULT NULL, + `ss_ext_discount_amt` decimal(7,2) DEFAULT NULL, + `ss_ext_sales_price` decimal(7,2) DEFAULT NULL, + `ss_ext_wholesale_cost` decimal(7,2) DEFAULT NULL, + `ss_ext_list_price` decimal(7,2) DEFAULT NULL, + `ss_ext_tax` decimal(7,2) DEFAULT NULL, + `ss_coupon_amt` decimal(7,2) DEFAULT NULL, + `ss_net_paid` decimal(7,2) DEFAULT NULL, + `ss_net_paid_inc_tax` decimal(7,2) DEFAULT NULL, + `ss_net_profit` decimal(7,2) DEFAULT NULL, + PRIMARY KEY (`ss_item_sk`,`ss_ticket_number`) /*T![clustered_index] NONCLUSTERED */ +); +CREATE TABLE `date_dim` ( + `d_date_sk` int(11) NOT NULL, + `d_date_id` char(16) NOT NULL, + `d_date` date DEFAULT NULL, + `d_month_seq` int(11) DEFAULT NULL, + `d_week_seq` int(11) DEFAULT NULL, + `d_quarter_seq` int(11) DEFAULT NULL, + `d_year` int(11) DEFAULT NULL, + `d_dow` int(11) DEFAULT NULL, + `d_moy` int(11) DEFAULT NULL, + `d_dom` int(11) DEFAULT NULL, + `d_qoy` int(11) DEFAULT NULL, + `d_fy_year` int(11) DEFAULT NULL, + `d_fy_quarter_seq` int(11) DEFAULT NULL, + `d_fy_week_seq` int(11) DEFAULT NULL, + `d_day_name` char(9) DEFAULT NULL, + `d_quarter_name` char(6) DEFAULT NULL, + `d_holiday` char(1) DEFAULT NULL, + `d_weekend` char(1) DEFAULT NULL, + `d_following_holiday` char(1) DEFAULT NULL, + `d_first_dom` int(11) DEFAULT NULL, + `d_last_dom` int(11) DEFAULT NULL, + `d_same_day_ly` int(11) DEFAULT NULL, + `d_same_day_lq` int(11) DEFAULT NULL, + `d_current_day` char(1) DEFAULT NULL, + `d_current_week` char(1) DEFAULT NULL, + `d_current_month` char(1) DEFAULT NULL, + `d_current_quarter` char(1) DEFAULT NULL, + `d_current_year` char(1) DEFAULT NULL, + PRIMARY KEY (`d_date_sk`) /*T![clustered_index] NONCLUSTERED */ +); +CREATE TABLE `web_sales` ( + `ws_sold_date_sk` int(11) DEFAULT NULL, + `ws_sold_time_sk` int(11) DEFAULT NULL, + `ws_ship_date_sk` int(11) DEFAULT NULL, + `ws_item_sk` int(11) NOT NULL, + `ws_bill_customer_sk` int(11) DEFAULT NULL, + `ws_bill_cdemo_sk` int(11) DEFAULT NULL, + `ws_bill_hdemo_sk` int(11) DEFAULT NULL, + `ws_bill_addr_sk` int(11) DEFAULT NULL, + `ws_ship_customer_sk` int(11) DEFAULT NULL, + `ws_ship_cdemo_sk` int(11) DEFAULT NULL, + `ws_ship_hdemo_sk` int(11) DEFAULT NULL, + `ws_ship_addr_sk` int(11) DEFAULT NULL, + `ws_web_page_sk` int(11) DEFAULT NULL, + `ws_web_site_sk` int(11) DEFAULT NULL, + `ws_ship_mode_sk` int(11) DEFAULT NULL, + `ws_warehouse_sk` int(11) DEFAULT NULL, + `ws_promo_sk` int(11) DEFAULT NULL, + `ws_order_number` int(11) NOT NULL, + `ws_quantity` int(11) DEFAULT NULL, + `ws_wholesale_cost` decimal(7,2) DEFAULT NULL, + `ws_list_price` decimal(7,2) DEFAULT NULL, + `ws_sales_price` decimal(7,2) DEFAULT NULL, + `ws_ext_discount_amt` decimal(7,2) DEFAULT NULL, + `ws_ext_sales_price` decimal(7,2) DEFAULT NULL, + `ws_ext_wholesale_cost` decimal(7,2) DEFAULT NULL, + `ws_ext_list_price` decimal(7,2) DEFAULT NULL, + `ws_ext_tax` decimal(7,2) DEFAULT NULL, + `ws_coupon_amt` decimal(7,2) DEFAULT NULL, + `ws_ext_ship_cost` decimal(7,2) DEFAULT NULL, + `ws_net_paid` decimal(7,2) DEFAULT NULL, + `ws_net_paid_inc_tax` decimal(7,2) DEFAULT NULL, + `ws_net_paid_inc_ship` decimal(7,2) DEFAULT NULL, + `ws_net_paid_inc_ship_tax` decimal(7,2) DEFAULT NULL, + `ws_net_profit` decimal(7,2) DEFAULT NULL, + PRIMARY KEY (`ws_item_sk`,`ws_order_number`) /*T![clustered_index] NONCLUSTERED */ +); +desc format='brief' with year_total as ( + select c_customer_id customer_id + ,c_first_name customer_first_name + ,c_last_name customer_last_name + ,c_preferred_cust_flag customer_preferred_cust_flag + ,c_birth_country customer_birth_country + ,c_login customer_login + ,c_email_address customer_email_address + ,d_year dyear + ,sum(ss_ext_list_price-ss_ext_discount_amt) year_total + ,'s' sale_type + from customer + ,store_sales + ,date_dim + where c_customer_sk = ss_customer_sk + and ss_sold_date_sk = d_date_sk + group by c_customer_id + ,c_first_name + ,c_last_name + ,c_preferred_cust_flag + ,c_birth_country + ,c_login + ,c_email_address + ,d_year + union all + select c_customer_id customer_id + ,c_first_name customer_first_name + ,c_last_name customer_last_name + ,c_preferred_cust_flag customer_preferred_cust_flag + ,c_birth_country customer_birth_country + ,c_login customer_login + ,c_email_address customer_email_address + ,d_year dyear + ,sum(ws_ext_list_price-ws_ext_discount_amt) year_total + ,'w' sale_type + from customer + ,web_sales + ,date_dim + where c_customer_sk = ws_bill_customer_sk + and ws_sold_date_sk = d_date_sk + group by c_customer_id + ,c_first_name + ,c_last_name + ,c_preferred_cust_flag + ,c_birth_country + ,c_login + ,c_email_address + ,d_year + ) + select + t_s_secyear.customer_id + ,t_s_secyear.customer_first_name + ,t_s_secyear.customer_last_name + ,t_s_secyear.customer_email_address + from year_total t_s_firstyear + ,year_total t_s_secyear + ,year_total t_w_firstyear + ,year_total t_w_secyear + where t_s_secyear.customer_id = t_s_firstyear.customer_id + and t_s_firstyear.customer_id = t_w_secyear.customer_id + and t_s_firstyear.customer_id = t_w_firstyear.customer_id + and t_s_firstyear.sale_type = 's' + and t_w_firstyear.sale_type = 'w' + and t_s_secyear.sale_type = 's' + and t_w_secyear.sale_type = 'w' + and t_s_firstyear.dyear = 2001 + and t_s_secyear.dyear = 2001+1 + and t_w_firstyear.dyear = 2001 + and t_w_secyear.dyear = 2001+1 + and t_s_firstyear.year_total > 0 + and t_w_firstyear.year_total > 0 + and case when t_w_firstyear.year_total > 0 then t_w_secyear.year_total / t_w_firstyear.year_total else 0.0 end + > case when t_s_firstyear.year_total > 0 then t_s_secyear.year_total / t_s_firstyear.year_total else 0.0 end + order by t_s_secyear.customer_id + ,t_s_secyear.customer_first_name + ,t_s_secyear.customer_last_name + ,t_s_secyear.customer_email_address +limit 100; diff --git a/planner/core/logical_plan_builder.go b/planner/core/logical_plan_builder.go index c8e38780eecba..67014aab55f80 100644 --- a/planner/core/logical_plan_builder.go +++ b/planner/core/logical_plan_builder.go @@ -3899,11 +3899,15 @@ func (b *PlanBuilder) tryBuildCTE(ctx context.Context, tn *ast.TableName, asName cte.cteClass = &CTEClass{IsDistinct: cte.isDistinct, seedPartLogicalPlan: cte.seedLP, recursivePartLogicalPlan: cte.recurLP, IDForStorage: cte.storageID, optFlag: cte.optFlag, HasLimit: hasLimit, LimitBeg: limitBeg, - LimitEnd: limitEnd} + LimitEnd: limitEnd, pushDownPredicates: make([]expression.Expression, 0), ColumnMap: make(map[string]*expression.Column)} } var p LogicalPlan lp := LogicalCTE{cteAsName: tn.Name, cte: cte.cteClass, seedStat: cte.seedStat}.Init(b.ctx, b.getSelectOffset()) + prevSchema := cte.seedLP.Schema().Clone() lp.SetSchema(getResultCTESchema(cte.seedLP.Schema(), b.ctx.GetSessionVars())) + for i, col := range lp.schema.Columns { + lp.cte.ColumnMap[string(col.HashCode(nil))] = prevSchema.Columns[i] + } p = lp p.SetOutputNames(cte.seedLP.OutputNames()) if len(asName.String()) > 0 { diff --git a/planner/core/logical_plans.go b/planner/core/logical_plans.go index a5cedfe83c610..85d70585d2843 100644 --- a/planner/core/logical_plans.go +++ b/planner/core/logical_plans.go @@ -1285,6 +1285,9 @@ type CTEClass struct { LimitBeg uint64 LimitEnd uint64 IsInApply bool + // pushDownPredicates may be push-downed by different references. + pushDownPredicates []expression.Expression + ColumnMap map[string]*expression.Column } // LogicalCTE is for CTE. diff --git a/planner/core/rule_predicate_push_down.go b/planner/core/rule_predicate_push_down.go index fc7154d9063d2..82201b74d8f92 100644 --- a/planner/core/rule_predicate_push_down.go +++ b/planner/core/rule_predicate_push_down.go @@ -439,6 +439,94 @@ func (p *LogicalUnionAll) PredicatePushDown(predicates []expression.Expression, return nil, p } +// pushDownPredicatesForAggregation split a condition to two parts, can be pushed-down or can not be pushed-down below aggregation. +func (la *LogicalAggregation) pushDownPredicatesForAggregation(cond expression.Expression, groupByColumns *expression.Schema, exprsOriginal []expression.Expression) ([]expression.Expression, []expression.Expression) { + var condsToPush []expression.Expression + var ret []expression.Expression + switch cond.(type) { + case *expression.Constant: + condsToPush = append(condsToPush, cond) + // Consider SQL list "select sum(b) from t group by a having 1=0". "1=0" is a constant predicate which should be + // retained and pushed down at the same time. Because we will get a wrong query result that contains one column + // with value 0 rather than an empty query result. + ret = append(ret, cond) + case *expression.ScalarFunction: + extractedCols := expression.ExtractColumns(cond) + ok := true + for _, col := range extractedCols { + if !groupByColumns.Contains(col) { + ok = false + break + } + } + if ok { + newFunc := expression.ColumnSubstitute(cond, la.Schema(), exprsOriginal) + condsToPush = append(condsToPush, newFunc) + } else { + ret = append(ret, cond) + } + default: + ret = append(ret, cond) + } + return condsToPush, ret +} + +// pushDownPredicatesForAggregation split a CNF condition to two parts, can be pushed-down or can not be pushed-down below aggregation. +// It would consider the CNF. +// For example, +// (a > 1 or avg(b) > 1) and (a < 3), and `avg(b) > 1` can't be pushed-down. +// Then condsToPush: a < 3, ret: a > 1 or avg(b) > 1 +func (la *LogicalAggregation) pushDownCNFPredicatesForAggregation(cond expression.Expression, groupByColumns *expression.Schema, exprsOriginal []expression.Expression) ([]expression.Expression, []expression.Expression) { + var condsToPush []expression.Expression + var ret []expression.Expression + subCNFItem := expression.SplitCNFItems(cond) + if len(subCNFItem) == 1 { + return la.pushDownPredicatesForAggregation(subCNFItem[0], groupByColumns, exprsOriginal) + } + for _, item := range subCNFItem { + condsToPushForItem, retForItem := la.pushDownDNFPredicatesForAggregation(item, groupByColumns, exprsOriginal) + if len(condsToPushForItem) > 0 { + condsToPush = append(condsToPush, expression.ComposeDNFCondition(la.ctx, condsToPushForItem...)) + } + if len(retForItem) > 0 { + ret = append(ret, expression.ComposeDNFCondition(la.ctx, retForItem...)) + } + } + return condsToPush, ret +} + +// pushDownDNFPredicatesForAggregation split a DNF condition to two parts, can be pushed-down or can not be pushed-down below aggregation. +// It would consider the DNF. +// For example, +// (a > 1 and avg(b) > 1) or (a < 3), and `avg(b) > 1` can't be pushed-down. +// Then condsToPush: (a < 3) and (a > 1), ret: (a > 1 and avg(b) > 1) or (a < 3) +func (la *LogicalAggregation) pushDownDNFPredicatesForAggregation(cond expression.Expression, groupByColumns *expression.Schema, exprsOriginal []expression.Expression) ([]expression.Expression, []expression.Expression) { + var condsToPush []expression.Expression + var ret []expression.Expression + subDNFItem := expression.SplitDNFItems(cond) + if len(subDNFItem) == 1 { + return la.pushDownPredicatesForAggregation(subDNFItem[0], groupByColumns, exprsOriginal) + } + for _, item := range subDNFItem { + condsToPushForItem, retForItem := la.pushDownCNFPredicatesForAggregation(item, groupByColumns, exprsOriginal) + if len(condsToPushForItem) > 0 { + condsToPush = append(condsToPush, expression.ComposeCNFCondition(la.ctx, condsToPushForItem...)) + } else { + return nil, []expression.Expression{cond} + } + if len(retForItem) > 0 { + ret = append(ret, expression.ComposeCNFCondition(la.ctx, retForItem...)) + } + } + if len(ret) == 0 { + // All the condition can be pushed down. + return []expression.Expression{cond}, nil + } + dnfPushDownCond := expression.ComposeDNFCondition(la.ctx, condsToPush...) + // Some condition can't be pushed down, we need to keep all the condition. + return []expression.Expression{dnfPushDownCond}, []expression.Expression{cond} +} + // PredicatePushDown implements LogicalPlan PredicatePushDown interface. func (la *LogicalAggregation) PredicatePushDown(predicates []expression.Expression, opt *logicalOptimizeOp) (ret []expression.Expression, retPlan LogicalPlan) { var condsToPush []expression.Expression @@ -447,31 +535,14 @@ func (la *LogicalAggregation) PredicatePushDown(predicates []expression.Expressi exprsOriginal = append(exprsOriginal, fun.Args[0]) } groupByColumns := expression.NewSchema(la.GetGroupByCols()...) + // It's almost the same as pushDownCNFPredicatesForAggregation, except that the condition is a slice. for _, cond := range predicates { - switch cond.(type) { - case *expression.Constant: - condsToPush = append(condsToPush, cond) - // Consider SQL list "select sum(b) from t group by a having 1=0". "1=0" is a constant predicate which should be - // retained and pushed down at the same time. Because we will get a wrong query result that contains one column - // with value 0 rather than an empty query result. - ret = append(ret, cond) - case *expression.ScalarFunction: - extractedCols := expression.ExtractColumns(cond) - ok := true - for _, col := range extractedCols { - if !groupByColumns.Contains(col) { - ok = false - break - } - } - if ok { - newFunc := expression.ColumnSubstitute(cond, la.Schema(), exprsOriginal) - condsToPush = append(condsToPush, newFunc) - } else { - ret = append(ret, cond) - } - default: - ret = append(ret, cond) + subCondsToPush, subRet := la.pushDownDNFPredicatesForAggregation(cond, groupByColumns, exprsOriginal) + if len(subCondsToPush) > 0 { + condsToPush = append(condsToPush, subCondsToPush...) + } + if len(subRet) > 0 { + ret = append(ret, subRet...) } } la.baseLogicalPlan.PredicatePushDown(condsToPush, opt) @@ -855,3 +926,22 @@ func (adder *exprPrefixAdder) addExprPrefix4DNFCond(condition *expression.Scalar return []expression.Expression{expression.ComposeDNFCondition(adder.sctx, newAccessItems...)}, nil } + +// PredicatePushDown implements LogicalPlan PredicatePushDown interface. +func (p *LogicalCTE) PredicatePushDown(predicates []expression.Expression, opt *logicalOptimizeOp) ([]expression.Expression, LogicalPlan) { + if p.cte.recursivePartLogicalPlan != nil { + // Doesn't support recursive CTE yet. + return predicates, p.self + } + if len(predicates) == 0 { + p.cte.pushDownPredicates = append(p.cte.pushDownPredicates, expression.NewOne()) + return predicates, p.self + } + newPred := make([]expression.Expression, 0, len(predicates)) + for i := range predicates { + newPred = append(newPred, predicates[i].Clone()) + ResolveExprAndReplace(newPred[i], p.cte.ColumnMap) + } + p.cte.pushDownPredicates = append(p.cte.pushDownPredicates, expression.ComposeCNFCondition(p.ctx, newPred...)) + return predicates, p.self +} diff --git a/planner/core/stats.go b/planner/core/stats.go index 253376c9bf117..7613ffdb6837c 100644 --- a/planner/core/stats.go +++ b/planner/core/stats.go @@ -1258,6 +1258,13 @@ func (p *LogicalCTE) DeriveStats(childStats []*property.StatsInfo, selfSchema *e var err error if p.cte.seedPartPhysicalPlan == nil { + // Build push-downed predicates. + if len(p.cte.pushDownPredicates) > 0 { + newCond := expression.ComposeDNFCondition(p.ctx, p.cte.pushDownPredicates...) + newSel := LogicalSelection{Conditions: []expression.Expression{newCond}}.Init(p.SCtx(), p.cte.seedPartLogicalPlan.SelectBlockOffset()) + newSel.SetChildren(p.cte.seedPartLogicalPlan) + p.cte.seedPartLogicalPlan = newSel + } p.cte.seedPartPhysicalPlan, _, err = DoOptimize(context.TODO(), p.ctx, p.cte.optFlag, p.cte.seedPartLogicalPlan) if err != nil { return nil, err