planner/cascades: add rule transformation rule InjectProjectionBelowAgg (#16078)
This commit is contained in:
@ -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"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
202
planner/cascades/testdata/integration_suite_out.json
vendored
202
planner/cascades/testdata/integration_suite_out.json
vendored
@ -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"
|
||||
|
||||
@ -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)"
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
@ -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"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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)
|
||||
}
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user