planner/cascades: add rule transformation rule InjectProjectionBelowAgg (#16078)

This commit is contained in:
SeaRise
2020-06-04 20:45:12 +08:00
committed by GitHub
parent 2c55650617
commit e38232a288
7 changed files with 323 additions and 96 deletions

View File

@ -44,7 +44,8 @@
"select count(case when a > 0 and a <= 1000 then b end) from t",
"select count(case when a <= 0 or a > 1000 then null else b end) from t",
"select count(distinct case when a > 0 and a <= 1000 then b end) from t",
"select count(b), sum(b), avg(b), b, max(b), min(b), bit_and(b), bit_or(b), bit_xor(b) from t group by a having sum(b) >= 0 and count(b) >= 0 order by b"
"select count(b), sum(b), avg(b), b, max(b), min(b), bit_and(b), bit_or(b), bit_xor(b) from t group by a having sum(b) >= 0 and count(b) >= 0 order by b",
"select group_concat(a, b), min(b), avg(a / b), a from t group by (a+b), a order by a"
]
},
{

View File

@ -134,10 +134,10 @@
{
"SQL": "select sum(a) from t",
"Plan": [
"HashAgg_12 1.00 root funcs:sum(Column#4)->Column#3",
"└─TableReader_13 1.00 root data:HashAgg_14",
" └─HashAgg_14 1.00 cop[tikv] funcs:sum(test.t.a)->Column#4",
" └─TableFullScan_10 10000.00 cop[tikv] table:t keep order:false, stats:pseudo"
"HashAgg_14 1.00 root funcs:sum(Column#4)->Column#3",
"└─TableReader_15 1.00 root data:HashAgg_16",
" └─HashAgg_16 1.00 cop[tikv] funcs:sum(test.t.a)->Column#4",
" └─TableFullScan_13 10000.00 cop[tikv] table:t keep order:false, stats:pseudo"
],
"Result": [
"10"
@ -158,12 +158,12 @@
{
"SQL": "select b, avg(a) from t group by b order by b",
"Plan": [
"Projection_10 8000.00 root test.t.b, Column#3",
"└─Sort_19 8000.00 root test.t.b",
" └─HashAgg_12 8000.00 root group by:Column#9, funcs:avg(Column#7)->Column#3, funcs:firstrow(Column#8)->test.t.b",
"Projection_12 8000.00 root test.t.b, Column#3",
"└─Sort_21 8000.00 root test.t.b",
" └─HashAgg_14 8000.00 root group by:test.t.b, funcs:avg(Column#7)->Column#3, funcs:firstrow(test.t.b)->test.t.b",
" └─Projection_15 10000.00 root cast(test.t.a, decimal(65,4) BINARY)->Column#7, test.t.b, test.t.b",
" └─TableReader_13 10000.00 root data:TableFullScan_14",
" └─TableFullScan_14 10000.00 cop[tikv] table:t keep order:false, stats:pseudo"
" └─TableReader_16 10000.00 root data:TableFullScan_17",
" └─TableFullScan_17 10000.00 cop[tikv] table:t keep order:false, stats:pseudo"
],
"Result": [
"11 1.0000",
@ -175,12 +175,12 @@
{
"SQL": "select b, sum(a) from t group by b order by b",
"Plan": [
"Projection_10 8000.00 root test.t.b, Column#3",
"└─Sort_19 8000.00 root test.t.b",
" └─HashAgg_16 8000.00 root group by:test.t.b, funcs:sum(Column#4)->Column#3, funcs:firstrow(test.t.b)->test.t.b",
" └─TableReader_17 8000.00 root data:HashAgg_18",
" └─HashAgg_18 8000.00 cop[tikv] group by:test.t.b, funcs:sum(test.t.a)->Column#4",
" └─TableFullScan_14 10000.00 cop[tikv] table:t keep order:false, stats:pseudo"
"Projection_12 8000.00 root test.t.b, Column#3",
"└─Sort_21 8000.00 root test.t.b",
" └─HashAgg_18 8000.00 root group by:test.t.b, funcs:sum(Column#4)->Column#3, funcs:firstrow(test.t.b)->test.t.b",
" └─TableReader_19 8000.00 root data:HashAgg_20",
" └─HashAgg_20 8000.00 cop[tikv] group by:test.t.b, funcs:sum(test.t.a)->Column#4",
" └─TableFullScan_17 10000.00 cop[tikv] table:t keep order:false, stats:pseudo"
],
"Result": [
"11 1",
@ -192,14 +192,14 @@
{
"SQL": "select b, avg(a) from t group by b having sum(a) > 1 order by b",
"Plan": [
"Projection_12 6400.00 root test.t.b, Column#3",
"└─Projection_14 6400.00 root test.t.b, Column#3, Column#4",
" └─Sort_27 6400.00 root test.t.b",
" └─Selection_26 6400.00 root gt(Column#4, 1)",
" └─HashAgg_17 8000.00 root group by:Column#14, funcs:avg(Column#11)->Column#3, funcs:sum(Column#12)->Column#4, funcs:firstrow(Column#13)->test.t.b",
"Projection_14 6400.00 root test.t.b, Column#3",
"└─Projection_16 6400.00 root test.t.b, Column#3, Column#4",
" └─Sort_29 6400.00 root test.t.b",
" └─Selection_28 6400.00 root gt(Column#4, 1)",
" └─HashAgg_19 8000.00 root group by:test.t.b, funcs:avg(Column#11)->Column#3, funcs:sum(Column#12)->Column#4, funcs:firstrow(test.t.b)->test.t.b",
" └─Projection_20 10000.00 root cast(test.t.a, decimal(65,4) BINARY)->Column#11, cast(test.t.a, decimal(65,0) BINARY)->Column#12, test.t.b, test.t.b",
" └─TableReader_18 10000.00 root data:TableFullScan_19",
" └─TableFullScan_19 10000.00 cop[tikv] table:t keep order:false, stats:pseudo"
" └─TableReader_21 10000.00 root data:TableFullScan_22",
" └─TableFullScan_22 10000.00 cop[tikv] table:t keep order:false, stats:pseudo"
],
"Result": [
"22 2.0000",
@ -210,10 +210,10 @@
{
"SQL": "select max(a+b) from t",
"Plan": [
"HashAgg_31 1.00 root funcs:max(Column#4)->Column#3",
"└─TableReader_32 1.00 root data:HashAgg_33",
" └─HashAgg_33 1.00 cop[tikv] funcs:max(plus(test.t.a, test.t.b))->Column#4",
" └─TableFullScan_29 10000.00 cop[tikv] table:t keep order:false, stats:pseudo"
"HashAgg_68 1.00 root funcs:max(Column#4)->Column#3",
"└─TableReader_69 1.00 root data:HashAgg_70",
" └─HashAgg_70 1.00 cop[tikv] funcs:max(plus(test.t.a, test.t.b))->Column#4",
" └─TableFullScan_41 10000.00 cop[tikv] table:t keep order:false, stats:pseudo"
],
"Result": [
"48"
@ -237,13 +237,13 @@
{
"SQL": "select b, sum(a) from t group by b having b > 1 order by b",
"Plan": [
"Projection_14 6400.00 root test.t.b, Column#3",
"└─Sort_24 6400.00 root test.t.b",
" └─HashAgg_21 6400.00 root group by:test.t.b, funcs:sum(Column#4)->Column#3, funcs:firstrow(test.t.b)->test.t.b",
" └─TableReader_22 6400.00 root data:HashAgg_23",
" └─HashAgg_23 6400.00 cop[tikv] group by:test.t.b, funcs:sum(test.t.a)->Column#4",
" └─Selection_18 8000.00 cop[tikv] gt(test.t.b, 1)",
" └─TableFullScan_19 10000.00 cop[tikv] table:t keep order:false, stats:pseudo"
"Projection_16 6400.00 root test.t.b, Column#3",
"└─Sort_26 6400.00 root test.t.b",
" └─HashAgg_23 6400.00 root group by:test.t.b, funcs:sum(Column#4)->Column#3, funcs:firstrow(test.t.b)->test.t.b",
" └─TableReader_24 6400.00 root data:HashAgg_25",
" └─HashAgg_25 6400.00 cop[tikv] group by:test.t.b, funcs:sum(test.t.a)->Column#4",
" └─Selection_21 8000.00 cop[tikv] gt(test.t.b, 1)",
" └─TableFullScan_22 10000.00 cop[tikv] table:t keep order:false, stats:pseudo"
],
"Result": [
"11 1",
@ -255,13 +255,13 @@
{
"SQL": "select c, sum(a) from (select a+b as c, a from t) t1 group by c having c > 1 order by c",
"Plan": [
"Projection_18 6400.00 root Column#3, Column#4",
"└─Sort_30 6400.00 root Column#3",
" └─HashAgg_26 6400.00 root group by:Column#7, funcs:sum(Column#8)->Column#4, funcs:firstrow(Column#7)->Column#3",
" └─TableReader_27 6400.00 root data:HashAgg_28",
" └─HashAgg_28 6400.00 cop[tikv] group by:plus(test.t.a, test.t.b), funcs:sum(test.t.a)->Column#8",
" └─Selection_23 8000.00 cop[tikv] gt(plus(test.t.a, test.t.b), 1)",
" └─TableFullScan_24 10000.00 cop[tikv] table:t keep order:false, stats:pseudo"
"Projection_23 6400.00 root Column#3, Column#4",
"└─Sort_35 6400.00 root Column#3",
" └─HashAgg_32 6400.00 root group by:Column#7, funcs:sum(Column#8)->Column#4, funcs:firstrow(Column#7)->Column#3",
" └─TableReader_33 6400.00 root data:HashAgg_34",
" └─HashAgg_34 6400.00 cop[tikv] group by:plus(test.t.a, test.t.b), funcs:sum(test.t.a)->Column#8",
" └─Selection_28 8000.00 cop[tikv] gt(plus(test.t.a, test.t.b), 1)",
" └─TableFullScan_29 10000.00 cop[tikv] table:t keep order:false, stats:pseudo"
],
"Result": [
"12 1",
@ -286,10 +286,10 @@
{
"SQL": "select avg(a.b) from t a left join t b on a.a = b.a",
"Plan": [
"HashAgg_14 1.00 root funcs:avg(Column#6, Column#7)->Column#5",
"└─TableReader_15 1.00 root data:HashAgg_16",
" └─HashAgg_16 1.00 cop[tikv] funcs:count(test.t.b)->Column#6, funcs:sum(test.t.b)->Column#7",
" └─TableFullScan_12 10000.00 cop[tikv] table:a keep order:false, stats:pseudo"
"HashAgg_16 1.00 root funcs:avg(Column#6, Column#7)->Column#5",
"└─TableReader_17 1.00 root data:HashAgg_18",
" └─HashAgg_18 1.00 cop[tikv] funcs:count(test.t.b)->Column#6, funcs:sum(test.t.b)->Column#7",
" └─TableFullScan_15 10000.00 cop[tikv] table:a keep order:false, stats:pseudo"
],
"Result": [
"27.5000"
@ -367,10 +367,10 @@
{
"SQL": "select sum(case when a > 0 and a <= 1000 then b else 0 end) from t",
"Plan": [
"HashAgg_16 1.00 root funcs:sum(Column#4)->Column#3",
"└─TableReader_17 1.00 root data:HashAgg_18",
" └─HashAgg_18 1.00 cop[tikv] funcs:sum(test.t.b)->Column#4",
" └─TableRangeScan_14 250.00 cop[tikv] table:t range:(0,1000], keep order:false, stats:pseudo"
"HashAgg_18 1.00 root funcs:sum(Column#4)->Column#3",
"└─TableReader_19 1.00 root data:HashAgg_20",
" └─HashAgg_20 1.00 cop[tikv] funcs:sum(test.t.b)->Column#4",
" └─TableRangeScan_17 250.00 cop[tikv] table:t range:(0,1000], keep order:false, stats:pseudo"
],
"Result": [
"110"
@ -379,10 +379,10 @@
{
"SQL": "select sum(case when a > 0 then (case when a <= 1000 then b end) else 0 end) from t",
"Plan": [
"HashAgg_19 1.00 root funcs:sum(Column#4)->Column#3",
"└─TableReader_20 1.00 root data:HashAgg_21",
" └─HashAgg_21 1.00 cop[tikv] funcs:sum(test.t.b)->Column#4",
" └─TableRangeScan_17 250.00 cop[tikv] table:t range:(0,1000], keep order:false, stats:pseudo"
"HashAgg_21 1.00 root funcs:sum(Column#4)->Column#3",
"└─TableReader_22 1.00 root data:HashAgg_23",
" └─HashAgg_23 1.00 cop[tikv] funcs:sum(test.t.b)->Column#4",
" └─TableRangeScan_20 250.00 cop[tikv] table:t range:(0,1000], keep order:false, stats:pseudo"
],
"Result": [
"110"
@ -391,10 +391,10 @@
{
"SQL": "select sum(case when a <= 0 or a > 1000 then 0.0 else b end) from t",
"Plan": [
"HashAgg_16 1.00 root funcs:sum(Column#4)->Column#3",
"└─TableReader_17 1.00 root data:HashAgg_18",
" └─HashAgg_18 1.00 cop[tikv] funcs:sum(cast(test.t.b))->Column#4",
" └─TableRangeScan_14 250.00 cop[tikv] table:t range:(0,1000], keep order:false, stats:pseudo"
"HashAgg_18 1.00 root funcs:sum(Column#4)->Column#3",
"└─TableReader_19 1.00 root data:HashAgg_20",
" └─HashAgg_20 1.00 cop[tikv] funcs:sum(cast(test.t.b))->Column#4",
" └─TableRangeScan_17 250.00 cop[tikv] table:t range:(0,1000], keep order:false, stats:pseudo"
],
"Result": [
"110.0"
@ -451,6 +451,22 @@
"1 33 33.0000 33 33 33 33 33 33",
"1 44 44.0000 44 44 44 44 44 44"
]
},
{
"SQL": "select group_concat(a, b), min(b), avg(a / b), a from t group by (a+b), a order by a",
"Plan": [
"Sort_15 8000.00 root test.t.a",
"└─HashAgg_11 8000.00 root group by:Column#9, test.t.a, funcs:group_concat(Column#6, Column#7 separator \",\")->Column#3, funcs:min(test.t.b)->Column#4, funcs:avg(Column#8)->Column#5, funcs:firstrow(test.t.a)->test.t.a",
" └─Projection_12 10000.00 root cast(test.t.a, var_string(20))->Column#6, cast(test.t.b, var_string(20))->Column#7, test.t.b, div(cast(test.t.a, decimal(20,0) BINARY), cast(test.t.b, decimal(20,0) BINARY))->Column#8, test.t.a, plus(test.t.a, test.t.b)->Column#9, test.t.a",
" └─TableReader_13 10000.00 root data:TableFullScan_14",
" └─TableFullScan_14 10000.00 cop[tikv] table:t keep order:false, stats:pseudo"
],
"Result": [
"111 11 0.09090909 1",
"222 22 0.09090909 2",
"333 33 0.09090909 3",
"444 44 0.09090909 4"
]
}
]
},
@ -460,11 +476,11 @@
{
"SQL": "select /*+ HASH_AGG() */ avg(distinct a) from t;",
"Plan": [
"HashAgg_12 1.00 root funcs:avg(distinct Column#8)->Column#5",
"└─Projection_15 8000.00 root cast(test.t.a, decimal(65,4) BINARY)->Column#8",
" └─TableReader_13 8000.00 root data:HashAgg_14",
" └─HashAgg_14 8000.00 cop[tikv] group by:test.t.a, ",
" └─TableFullScan_10 10000.00 cop[tikv] table:t keep order:false, stats:pseudo"
"HashAgg_16 1.00 root funcs:avg(distinct Column#8)->Column#5",
"└─Projection_17 8000.00 root cast(test.t.a, decimal(65,4) BINARY)->Column#8",
" └─TableReader_18 8000.00 root data:HashAgg_19",
" └─HashAgg_19 8000.00 cop[tikv] group by:test.t.a, ",
" └─TableFullScan_15 10000.00 cop[tikv] table:t keep order:false, stats:pseudo"
],
"Result": [
"1.5000"
@ -486,11 +502,11 @@
{
"SQL": "select /*+ HASH_AGG() */ avg(b), c, avg(b), count(distinct A, B), count(distinct A), count(distinct c), sum(b) from t group by c;",
"Plan": [
"Projection_8 8000.00 root Column#5, test.t.c, Column#5, Column#6, Column#7, Column#8, Column#9",
"└─HashAgg_13 8000.00 root group by:test.t.c, funcs:avg(Column#11, Column#12)->Column#5, funcs:count(distinct test.t.a, test.t.b)->Column#6, funcs:count(distinct test.t.a)->Column#7, funcs:count(distinct test.t.c)->Column#8, funcs:sum(Column#13)->Column#9, funcs:firstrow(test.t.c)->test.t.c",
" └─TableReader_14 8000.00 root data:HashAgg_15",
" └─HashAgg_15 8000.00 cop[tikv] group by:test.t.a, test.t.b, test.t.c, funcs:count(test.t.b)->Column#11, funcs:sum(test.t.b)->Column#12, funcs:sum(test.t.b)->Column#13",
" └─TableFullScan_11 10000.00 cop[tikv] table:t keep order:false, stats:pseudo"
"Projection_10 8000.00 root Column#5, test.t.c, Column#5, Column#6, Column#7, Column#8, Column#9",
"└─HashAgg_15 8000.00 root group by:test.t.c, funcs:avg(Column#11, Column#12)->Column#5, funcs:count(distinct test.t.a, test.t.b)->Column#6, funcs:count(distinct test.t.a)->Column#7, funcs:count(distinct test.t.c)->Column#8, funcs:sum(Column#13)->Column#9, funcs:firstrow(test.t.c)->test.t.c",
" └─TableReader_16 8000.00 root data:HashAgg_17",
" └─HashAgg_17 8000.00 cop[tikv] group by:test.t.a, test.t.b, test.t.c, funcs:count(test.t.b)->Column#11, funcs:sum(test.t.b)->Column#12, funcs:sum(test.t.b)->Column#13",
" └─TableFullScan_14 10000.00 cop[tikv] table:t keep order:false, stats:pseudo"
],
"Result": [
"1.0000 1 1.0000 1 1 1 1",
@ -570,10 +586,10 @@
{
"SQL": "select /*+ HASH_AGG(), AGG_TO_COP() */ avg(distinct a) from t;",
"Plan": [
"HashAgg_6 1.00 root funcs:avg(distinct Column#7)->Column#5",
"HashAgg_8 1.00 root funcs:avg(distinct Column#7)->Column#5",
"└─Projection_9 10000.00 root cast(test.t.a, decimal(65,4) BINARY)->Column#7",
" └─TableReader_7 10000.00 root data:TableFullScan_8",
" └─TableFullScan_8 10000.00 cop[tikv] table:t keep order:false, stats:pseudo"
" └─TableReader_10 10000.00 root data:TableFullScan_11",
" └─TableFullScan_11 10000.00 cop[tikv] table:t keep order:false, stats:pseudo"
],
"Result": [
"1.5000"
@ -594,11 +610,11 @@
{
"SQL": "select /*+ HASH_AGG(), AGG_TO_COP() */ avg(b), c, avg(b), count(distinct A, B), count(distinct A), count(distinct c), sum(b) from t group by c;",
"Plan": [
"Projection_6 8000.00 root Column#5, test.t.c, Column#5, Column#6, Column#7, Column#8, Column#9",
"└─HashAgg_7 8000.00 root group by:Column#18, funcs:avg(Column#11)->Column#5, funcs:count(distinct Column#12, Column#13)->Column#6, funcs:count(distinct Column#14)->Column#7, funcs:count(distinct Column#15)->Column#8, funcs:sum(Column#16)->Column#9, funcs:firstrow(Column#17)->test.t.c",
" └─Projection_10 10000.00 root cast(test.t.b, decimal(65,4) BINARY)->Column#11, test.t.a, test.t.b, test.t.a, test.t.c, cast(test.t.b, decimal(65,0) BINARY)->Column#16, test.t.c, test.t.c",
" └─TableReader_8 10000.00 root data:TableFullScan_9",
" └─TableFullScan_9 10000.00 cop[tikv] table:t keep order:false, stats:pseudo"
"Projection_8 8000.00 root Column#5, test.t.c, Column#5, Column#6, Column#7, Column#8, Column#9",
"└─HashAgg_9 8000.00 root group by:test.t.c, funcs:avg(Column#11)->Column#5, funcs:count(distinct test.t.a, test.t.b)->Column#6, funcs:count(distinct test.t.a)->Column#7, funcs:count(distinct test.t.c)->Column#8, funcs:sum(Column#12)->Column#9, funcs:firstrow(test.t.c)->test.t.c",
" └─Projection_10 10000.00 root cast(test.t.b, decimal(65,4) BINARY)->Column#11, test.t.a, test.t.b, test.t.a, test.t.c, cast(test.t.b, decimal(65,0) BINARY)->Column#12, test.t.c, test.t.c",
" └─TableReader_11 10000.00 root data:TableFullScan_12",
" └─TableFullScan_12 10000.00 cop[tikv] table:t keep order:false, stats:pseudo"
],
"Result": [
"1.0000 1 1.0000 1 1 1 1",
@ -995,25 +1011,25 @@
{
"SQL": "select sum(a), (select t1.a from t1 where t1.a = t2.a limit 1), (select t1.b from t1 where t1.b = t2.b limit 1) from t2",
"Plan": [
"Projection_28 1.00 root Column#3, test.t1.a, test.t1.b",
"└─Apply_30 1.00 root CARTESIAN left outer join",
" ├─Apply_32(Build) 1.00 root CARTESIAN left outer join",
" │ ├─HashAgg_37(Build) 1.00 root funcs:sum(Column#8)->Column#3, funcs:firstrow(Column#9)->test.t2.a, funcs:firstrow(Column#10)->test.t2.b",
" │ │ └─TableReader_38 1.00 root data:HashAgg_39",
" │ │ └─HashAgg_39 1.00 cop[tikv] funcs:sum(test.t2.a)->Column#8, funcs:firstrow(test.t2.a)->Column#9, funcs:firstrow(test.t2.b)->Column#10",
" │ │ └─TableFullScan_35 10000.00 cop[tikv] table:t2 keep order:false, stats:pseudo",
" │ └─MaxOneRow_40(Probe) 1.00 root ",
" │ └─Limit_41 1.00 root offset:0, count:1",
" │ └─TableReader_42 1.00 root data:Limit_43",
" │ └─Limit_43 1.00 cop[tikv] offset:0, count:1",
" │ └─Selection_44 1.00 cop[tikv] eq(test.t1.a, test.t2.a)",
" │ └─TableFullScan_45 1.00 cop[tikv] table:t1 keep order:false, stats:pseudo",
" └─MaxOneRow_46(Probe) 1.00 root ",
" └─Limit_47 1.00 root offset:0, count:1",
" └─TableReader_48 1.00 root data:Limit_49",
" └─Limit_49 1.00 cop[tikv] offset:0, count:1",
" └─Selection_50 1.00 cop[tikv] eq(test.t1.b, test.t2.b)",
" └─TableFullScan_51 1.00 cop[tikv] table:t1 keep order:false, stats:pseudo"
"Projection_30 1.00 root Column#3, test.t1.a, test.t1.b",
"└─Apply_32 1.00 root CARTESIAN left outer join",
" ├─Apply_34(Build) 1.00 root CARTESIAN left outer join",
" │ ├─HashAgg_39(Build) 1.00 root funcs:sum(Column#8)->Column#3, funcs:firstrow(Column#9)->test.t2.a, funcs:firstrow(Column#10)->test.t2.b",
" │ │ └─TableReader_40 1.00 root data:HashAgg_41",
" │ │ └─HashAgg_41 1.00 cop[tikv] funcs:sum(test.t2.a)->Column#8, funcs:firstrow(test.t2.a)->Column#9, funcs:firstrow(test.t2.b)->Column#10",
" │ │ └─TableFullScan_38 10000.00 cop[tikv] table:t2 keep order:false, stats:pseudo",
" │ └─MaxOneRow_42(Probe) 1.00 root ",
" │ └─Limit_43 1.00 root offset:0, count:1",
" │ └─TableReader_44 1.00 root data:Limit_45",
" │ └─Limit_45 1.00 cop[tikv] offset:0, count:1",
" │ └─Selection_46 1.00 cop[tikv] eq(test.t1.a, test.t2.a)",
" │ └─TableFullScan_47 1.00 cop[tikv] table:t1 keep order:false, stats:pseudo",
" └─MaxOneRow_48(Probe) 1.00 root ",
" └─Limit_49 1.00 root offset:0, count:1",
" └─TableReader_50 1.00 root data:Limit_51",
" └─Limit_51 1.00 cop[tikv] offset:0, count:1",
" └─Selection_52 1.00 cop[tikv] eq(test.t1.b, test.t2.b)",
" └─TableFullScan_53 1.00 cop[tikv] table:t1 keep order:false, stats:pseudo"
],
"Result": [
"6 1 11"

View File

@ -205,5 +205,14 @@
"cases": [
"select a from t t1 where exists (select 1 from t t2 where t1.a = t2.b)"
]
},
{
"name": "TestInjectProj",
"cases": [
"select * from t order by (a+b) limit 10",
"select max(a), min(b), avg(c) from t group by a+b",
"select max(a), min(b), avg(a / b) from t group by a",
"select max(a), min(b), avg(a / b) from t group by (a+b)"
]
}
]

View File

@ -2352,5 +2352,64 @@
]
}
]
},
{
"Name": "TestInjectProj",
"Cases": [
{
"SQL": "select * from t order by (a+b) limit 10",
"Result": [
"Group#0 Schema:[test.t.a,test.t.b,test.t.c,test.t.d,test.t.e,test.t.c_str,test.t.d_str,test.t.e_str,test.t.f,test.t.g,test.t.h,test.t.i_date]",
" Projection_6 input:[Group#1], test.t.a, test.t.b, test.t.c, test.t.d, test.t.e, test.t.c_str, test.t.d_str, test.t.e_str, test.t.f, test.t.g, test.t.h, test.t.i_date",
"Group#1 Schema:[test.t.a,test.t.b,test.t.c,test.t.d,test.t.e,test.t.c_str,test.t.d_str,test.t.e_str,test.t.f,test.t.g,test.t.h,test.t.i_date,Column#13]",
" TopN_8 input:[Group#2], Column#13, offset:0, count:10",
"Group#2 Schema:[test.t.a,test.t.b,test.t.c,test.t.d,test.t.e,test.t.c_str,test.t.d_str,test.t.e_str,test.t.f,test.t.g,test.t.h,test.t.i_date,Column#13]",
" Projection_7 input:[Group#3], test.t.a, test.t.b, test.t.c, test.t.d, test.t.e, test.t.c_str, test.t.d_str, test.t.e_str, test.t.f, test.t.g, test.t.h, test.t.i_date, plus(test.t.a, test.t.b)->Column#13",
"Group#3 Schema:[test.t.a,test.t.b,test.t.c,test.t.d,test.t.e,test.t.c_str,test.t.d_str,test.t.e_str,test.t.f,test.t.g,test.t.h,test.t.i_date]",
" Projection_2 input:[Group#4], test.t.a, test.t.b, test.t.c, test.t.d, test.t.e, test.t.c_str, test.t.d_str, test.t.e_str, test.t.f, test.t.g, test.t.h, test.t.i_date",
"Group#4 Schema:[test.t.a,test.t.b,test.t.c,test.t.d,test.t.e,test.t.c_str,test.t.d_str,test.t.e_str,test.t.f,test.t.g,test.t.h,test.t.i_date]",
" DataSource_1 table:t"
]
},
{
"SQL": "select max(a), min(b), avg(c) from t group by a+b",
"Result": [
"Group#0 Schema:[Column#13,Column#14,Column#15]",
" Projection_3 input:[Group#1], Column#13, Column#14, Column#15",
"Group#1 Schema:[Column#13,Column#14,Column#15]",
" Aggregation_5 input:[Group#2], group by:Column#17, funcs:max(test.t.a), min(test.t.b), avg(Column#16)",
"Group#2 Schema:[test.t.a,test.t.b,Column#16,Column#17]",
" Projection_4 input:[Group#3], test.t.a, test.t.b, cast(test.t.c, decimal(65,30) BINARY)->Column#16, plus(test.t.a, test.t.b)->Column#17",
"Group#3 Schema:[test.t.a,test.t.b,test.t.c]",
" DataSource_1 table:t"
]
},
{
"SQL": "select max(a), min(b), avg(a / b) from t group by a",
"Result": [
"Group#0 Schema:[Column#13,Column#14,Column#15]",
" Projection_3 input:[Group#1], Column#13, Column#14, Column#15",
"Group#1 Schema:[Column#13,Column#14,Column#15]",
" Aggregation_5 input:[Group#2], group by:test.t.a, funcs:max(test.t.a), min(test.t.b), avg(Column#16)",
"Group#2 Schema:[test.t.a,test.t.b,Column#16,test.t.a]",
" Projection_4 input:[Group#3], test.t.a, test.t.b, div(cast(test.t.a, decimal(20,0) BINARY), cast(test.t.b, decimal(20,0) BINARY))->Column#16, test.t.a",
"Group#3 Schema:[test.t.a,test.t.b]",
" DataSource_1 table:t"
]
},
{
"SQL": "select max(a), min(b), avg(a / b) from t group by (a+b)",
"Result": [
"Group#0 Schema:[Column#13,Column#14,Column#15]",
" Projection_3 input:[Group#1], Column#13, Column#14, Column#15",
"Group#1 Schema:[Column#13,Column#14,Column#15]",
" Aggregation_5 input:[Group#2], group by:Column#17, funcs:max(test.t.a), min(test.t.b), avg(Column#16)",
"Group#2 Schema:[test.t.a,test.t.b,Column#16,Column#17]",
" Projection_4 input:[Group#3], test.t.a, test.t.b, div(cast(test.t.a, decimal(20,0) BINARY), cast(test.t.b, decimal(20,0) BINARY))->Column#16, plus(test.t.a, test.t.b)->Column#17",
"Group#3 Schema:[test.t.a,test.t.b]",
" DataSource_1 table:t"
]
}
]
}
]

View File

@ -139,6 +139,9 @@ var PostTransformationBatch = TransformationRuleBatch{
NewRuleEliminateProjection(),
NewRuleMergeAdjacentProjection(),
},
memo.OperandAggregation: {
NewRuleInjectProjectionBelowAgg(),
},
memo.OperandTopN: {
NewRuleInjectProjectionBelowTopN(),
},
@ -2222,6 +2225,122 @@ func (r *InjectProjectionBelowTopN) OnTransform(old *memo.ExprIter) (newExprs []
return []*memo.GroupExpr{topProjGroupExpr}, true, false, nil
}
// InjectProjectionBelowAgg injects Projection below Agg if Agg's AggFuncDesc.Args or
// Agg's GroupByItem contain ScalarFunctions.
type InjectProjectionBelowAgg struct {
baseRule
}
// NewRuleInjectProjectionBelowAgg creates a new Transformation NewRuleInjectProjectionBelowAgg.
// It will extract the ScalarFunctions of `AggFuncDesc` and `GroupByItems` into a Projection and injects it below Agg.
// The reason why we need this rule is that, AggExecutor in TiDB does not support ScalarFunction
// as `AggFuncDesc.Arg` and `GroupByItem`. So we have to use a Projection to calculate the ScalarFunctions in advance.
// The pattern of this rule is: a single Aggregation.
func NewRuleInjectProjectionBelowAgg() Transformation {
rule := &InjectProjectionBelowAgg{}
rule.pattern = memo.BuildPattern(
memo.OperandAggregation,
memo.EngineTiDBOnly,
)
return rule
}
// Match implements Transformation interface.
func (r *InjectProjectionBelowAgg) Match(expr *memo.ExprIter) bool {
agg := expr.GetExpr().ExprNode.(*plannercore.LogicalAggregation)
return agg.IsCompleteModeAgg()
}
// OnTransform implements Transformation interface.
// It will convert `Agg -> X` to `Agg -> Proj -> X`.
func (r *InjectProjectionBelowAgg) OnTransform(old *memo.ExprIter) (newExprs []*memo.GroupExpr, eraseOld bool, eraseAll bool, err error) {
agg := old.GetExpr().ExprNode.(*plannercore.LogicalAggregation)
hasScalarFunc := false
copyFuncs := make([]*aggregation.AggFuncDesc, 0, len(agg.AggFuncs))
for _, aggFunc := range agg.AggFuncs {
copyFunc := aggFunc.Clone()
//WrapCastForAggArgs will modify AggFunc, so we should clone AggFunc.
copyFunc.WrapCastForAggArgs(agg.SCtx())
copyFuncs = append(copyFuncs, copyFunc)
for _, arg := range copyFunc.Args {
_, isScalarFunc := arg.(*expression.ScalarFunction)
hasScalarFunc = hasScalarFunc || isScalarFunc
}
}
for i := 0; !hasScalarFunc && i < len(agg.GroupByItems); i++ {
_, isScalarFunc := agg.GroupByItems[i].(*expression.ScalarFunction)
hasScalarFunc = hasScalarFunc || isScalarFunc
}
if !hasScalarFunc {
return nil, false, false, nil
}
projSchemaCols := make([]*expression.Column, 0, len(copyFuncs)+len(agg.GroupByItems))
projExprs := make([]expression.Expression, 0, cap(projSchemaCols))
for _, f := range copyFuncs {
for i, arg := range f.Args {
switch expr := arg.(type) {
case *expression.Constant:
continue
case *expression.Column:
projExprs = append(projExprs, expr)
projSchemaCols = append(projSchemaCols, expr)
default:
projExprs = append(projExprs, expr)
newArg := &expression.Column{
UniqueID: agg.SCtx().GetSessionVars().AllocPlanColumnID(),
RetType: arg.GetType(),
}
projSchemaCols = append(projSchemaCols, newArg)
f.Args[i] = newArg
}
}
}
newGroupByItems := make([]expression.Expression, len(agg.GroupByItems))
for i, item := range agg.GroupByItems {
switch expr := item.(type) {
case *expression.Constant:
newGroupByItems[i] = expr
case *expression.Column:
newGroupByItems[i] = expr
projExprs = append(projExprs, expr)
projSchemaCols = append(projSchemaCols, expr)
default:
projExprs = append(projExprs, expr)
newArg := &expression.Column{
UniqueID: agg.SCtx().GetSessionVars().AllocPlanColumnID(),
RetType: item.GetType(),
}
projSchemaCols = append(projSchemaCols, newArg)
newGroupByItems[i] = newArg
}
}
// Construct GroupExpr, Group (Agg -> Proj -> Child).
proj := plannercore.LogicalProjection{
Exprs: projExprs,
}.Init(agg.SCtx(), agg.SelectBlockOffset())
projSchema := expression.NewSchema(projSchemaCols...)
proj.SetSchema(projSchema)
projExpr := memo.NewGroupExpr(proj)
projExpr.SetChildren(old.GetExpr().Children[0])
projGroup := memo.NewGroupWithSchema(projExpr, projSchema)
newAgg := plannercore.LogicalAggregation{
AggFuncs: copyFuncs,
GroupByItems: newGroupByItems,
}.Init(agg.SCtx(), agg.SelectBlockOffset())
newAgg.CopyAggHints(agg)
newAggExpr := memo.NewGroupExpr(newAgg)
newAggExpr.SetChildren(projGroup)
return []*memo.GroupExpr{newAggExpr}, true, false, nil
}
// TransformApplyToJoin transforms a LogicalApply to LogicalJoin if it's
// inner children has no correlated columns from it's outer schema.
type TransformApplyToJoin struct {

View File

@ -425,3 +425,28 @@ func (s *testTransformationRuleSuite) TestDecorrelate(c *C) {
s.testData.GetTestCases(c, &input, &output)
testGroupToString(input, output, s, c)
}
func (s *testTransformationRuleSuite) TestInjectProj(c *C) {
s.optimizer.ResetTransformationRules(map[memo.Operand][]Transformation{
memo.OperandLimit: {
NewRuleTransformLimitToTopN(),
},
}, map[memo.Operand][]Transformation{
memo.OperandAggregation: {
NewRuleInjectProjectionBelowAgg(),
},
memo.OperandTopN: {
NewRuleInjectProjectionBelowTopN(),
},
})
defer func() {
s.optimizer.ResetTransformationRules(DefaultRuleBatches...)
}()
var input []string
var output []struct {
SQL string
Result []string
}
s.testData.GetTestCases(c, &input, &output)
testGroupToString(input, output, s, c)
}

View File

@ -87,8 +87,6 @@ func (agg *TiDBHashAggImpl) CalcCost(outCount float64, children ...memo.Implemen
func (agg *TiDBHashAggImpl) AttachChildren(children ...memo.Implementation) memo.Implementation {
hashAgg := agg.plan.(*plannercore.PhysicalHashAgg)
hashAgg.SetChildren(children[0].GetPlan())
// Inject extraProjection if the AggFuncs or GroupByItems contain ScalarFunction.
plannercore.InjectProjBelowAgg(hashAgg, hashAgg.AggFuncs, hashAgg.GroupByItems)
return agg
}