Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add stronger min/max rewrite #1528

Open
wants to merge 7 commits into
base: master
Choose a base branch
from

Conversation

XueQinliang
Copy link

@XueQinliang XueQinliang commented Aug 24, 2023

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

@CLAassistant
Copy link

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants