Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Task Description
对于针对同一列的min/max同时出现的场景,目前的方案是全表扫描,但如果在单列上有索引的话,可以通过拆成多个子查询的方法,尽可能利用索引直接获取到最大值或最小值,避免全表扫描。
Solution Description
对一条SQL每一个select和having的表达式中,都有min/max出现,且均可以利用索引,除了min/max表达式中其他均为常数时,可以将每一个min/max拆成select column from table order by column (desc) limit 1这样的形式,从而避免全表扫描。而且对于重复出现的min/max表达式,在改写时会设置为共享表达式,避免多次计算。
Passed Regressions
mysql test
drop table if exists test_table;
set names utf8;
create table test_table(id int primary key, c1 int, c2 float, c3 varchar(10));
insert into test_table values (0,1,1.1,'aa');
insert into test_table values (1,2,4.5,'bb');
insert into test_table values (2,3,6.5,'aaa');
insert into test_table values (3,-1,2.1,'aaaa');
insert into test_table values (4,0,1.10,'bba');
create index i1 on test_table(c1);
create index i2 on test_table(c2);
create index i3 on test_table(c3);
--echo # TEST SINGLE MIN/MAX
explain select max(c1) from test_table;
select max(c1) from test_table;
explain select min(c1) from test_table;
select min(c1) from test_table;
explain select max(c2) from test_table;
select max(c2) from test_table;
explain select min(c2) from test_table;
select min(c2) from test_table;
explain select min(c3) from test_table;
select min(c3) from test_table;
explain select max(c3) from test_table;
select max(c3) from test_table;
--echo # TEST MULTI MIN/MAX FOR ONE COLUMN
explain select min(c1),max(c1) from test_table;
select min(c1),max(c1) from test_table;
explain select max(c2),min(c2) from test_table;
select max(c2),min(c2) from test_table;
explain select max(c3),min(c3) from test_table;
select max(c3),min(c3) from test_table;
--echo # TEST MULTI MIN/MAX FOR MULTI COLUMN
explain select max(c1),min(c1),max(c2),min(c2),max(c3),min(c3) from test_table;
select max(c1),min(c1),max(c2),min(c2),max(c3),min(c3) from test_table;
--echo # TEST DUPLICATE MULTI MIN/MAX FOR MULTI COLUMN
explain select max(c1),min(c1),max(c2),min(c2),max(c1),min(c2) from test_table;
select max(c1),min(c1),max(c2),min(c2),max(c1),min(c2) from test_table;
--echo # TEST MIN/MAX WITH HAVING
explain select max(c1) from test_table having max(c1) > 0;
select max(c1) from test_table having max(c1) > 0;
explain select min(c1) from test_table having min(c1) < 0;
select min(c1) from test_table having min(c1) < 0;
explain select max(c1),min(c1) from test_table having max(c1) > 0;
select max(c1),min(c1) from test_table having max(c1) > 0;
explain select min(c1),max(c2) from test_table having min(c1) < 0;
select min(c1),max(c2) from test_table having min(c1) < 0;
explain select min(c1) from test_table having max(c1) > 0 and min(c1) < 0;
select min(c1) from test_table having max(c1) > 0 and min(c1) < 0;
explain select max(c1) from test_table having min(c1) < 0 and max(c1) > 0;
select max(c1) from test_table having min(c1) < 0 and max(c1) > 0;
explain select max(c1),min(c1) from test_table having max(c1) > 5;
select max(c1),min(c1) from test_table having max(c1) > 5;
explain select min(c1),max(c2) from test_table having min(c1) < -10;
select min(c1),max(c2) from test_table having min(c1) < -10;
explain select max(c1),max(c2) from test_table having min(c1) < 0 and min(c2) < 1;
select max(c1),max(c2) from test_table having min(c1) < 0 and min(c2) < 1;
explain select max(c1),max(c2) from test_table having min(c1) < 0 and min(c2) < 0;
select max(c1),max(c2) from test_table having min(c1) < 0 and min(c2) < 0;
--echo # TEST MIN/MAX IN EXPR
explain select min(c1) from test_table having min(c1) + 5 > 0;
select min(c1) from test_table having min(c1) + 5 > 0;
explain select max(c1),max(c1)+1,max(c2)+1,min(c2)-1 from test_table;
select max(c1),max(c1)+1,max(c2)+1,min(c2)-1 from test_table;
explain select max(c1)*2, min(c2)+min(c2) from test_table having max(c1) * 2 + 5 > 0;
select max(c1)*2, min(c2)+min(c2) from test_table having max(c1) * 2 + 5 > 0;
explain select max(c1)*2, min(c2)+min(c2) from test_table having max(c1) * 2 + 5 > 0 and min(c2) - 1 < 0;
select max(c1)*2, min(c2)+min(c2) from test_table having max(c1) * 2 + 5 > 0 and min(c2) - 1 < 0;
--echo # TEST MORE THAN ONE MIN/MAX IN ONE EXPR
explain select max(c1)+min(c1) from test_table;
select max(c1)+min(c1) from test_table;
explain select max(c1) from test_table having max(c1)+min(c1) > 0;
select max(c1) from test_table having max(c1)+min(c1) > 0;
explain select max(c1)+max(c2) from test_table having min(c1)+min(c2) > 0;
select max(c1)+max(c2) from test_table having min(c1)+min(c2) > 0;
--echo # TEST MIN/MAX DO NOT REWRITE
explain select min(c1+1) from test_table;
select min(c1+1) from test_table;
drop index i1 on test_table;
explain select max(c1) from test_table;
select max(c1) from test_table;
explain select min(c1) from test_table;
select min(c1) from test_table;
explain select max(c2) from test_table having min(c1) < 0;
select max(c2) from test_table having min(c1) < 0;
explain select max(c1),min(c1) from test_table having max(c1) > 0;
select max(c1),min(c1) from test_table having max(c1) > 0;
explain select min(c1),max(c2) from test_table having min(c1) < 0;
select min(c1),max(c2) from test_table having min(c1) < 0;
--echo # TEST MIN/MAX UNION INDEX
drop index i2 on test_table;
create index i4 on test_table(c1,c2);
explain select max(c2) from test_table where c1 = 1;
select max(c2) from test_table where c1 = 1;
explain select min(c2) from test_table where c1 = 1;
select min(c2) from test_table where c1 = 1;
explain select min(c2),max(c2) from test_table where c1 = 1;
select min(c2),max(c2) from test_table where c1 = 1;
Upgrade Compatibility
Other Information
Release Note