Merge with implementation of WL#1724.

sql/ha_myisam.cc:
  Auto merged
sql/handler.cc:
  Auto merged
sql/item.cc:
  Auto merged
sql/item.h:
  Auto merged
sql/item_sum.cc:
  Auto merged
sql/item_sum.h:
  Auto merged
sql/key.cc:
  Auto merged
sql/mysql_priv.h:
  Auto merged
sql/opt_sum.cc:
  Auto merged
sql/sql_acl.cc:
  Auto merged
sql/sql_handler.cc:
  Auto merged
sql/sql_insert.cc:
  Auto merged
sql/sql_select.h:
  Auto merged
sql/opt_range.cc:
  Manual merge
sql/sql_select.cc:
  Manual merge
This commit is contained in:
unknown 2004-10-11 10:47:08 +03:00
commit 81f7ade662
18 changed files with 5100 additions and 233 deletions

View File

@ -200,19 +200,19 @@ select distinct 1 from t1,t3 where t1.a=t3.a;
1 1
explain SELECT distinct t1.a from t1; explain SELECT distinct t1.a from t1;
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 index NULL PRIMARY 4 NULL 4 Using index 1 SIMPLE t1 range NULL PRIMARY 4 NULL 5 Using index for group-by
explain SELECT distinct t1.a from t1 order by a desc; explain SELECT distinct t1.a from t1 order by a desc;
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 index NULL PRIMARY 4 NULL 4 Using index 1 SIMPLE t1 range NULL PRIMARY 4 NULL 5 Using index for group-by; Using temporary; Using filesort
explain SELECT t1.a from t1 group by a order by a desc; explain SELECT t1.a from t1 group by a order by a desc;
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 index NULL PRIMARY 4 NULL 4 Using index 1 SIMPLE t1 range NULL PRIMARY 4 NULL 5 Using index for group-by; Using temporary; Using filesort
explain SELECT distinct t1.a from t1 order by a desc limit 1; explain SELECT distinct t1.a from t1 order by a desc limit 1;
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 index NULL PRIMARY 4 NULL 4 Using index 1 SIMPLE t1 index NULL PRIMARY 4 NULL 5 Using index
explain SELECT distinct a from t3 order by a desc limit 2; explain SELECT distinct a from t3 order by a desc limit 2;
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t3 index NULL a 5 NULL 204 Using index 1 SIMPLE t3 index NULL a 5 NULL 10 Using index
explain SELECT distinct a,b from t3 order by a+1; explain SELECT distinct a,b from t3 order by a+1;
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t3 ALL NULL NULL NULL NULL 204 Using temporary; Using filesort 1 SIMPLE t3 ALL NULL NULL NULL NULL 204 Using temporary; Using filesort

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,579 @@
#
# Test file for WL#1724 (Min/Max Optimization for Queries with Group By Clause).
# The queries in this file test query execution via QUICK_GROUP_MIN_MAX_SELECT.
#
#
# TODO:
# Add queries with:
# - C != const
# - C IS NOT NULL
# - HAVING clause
--disable_warnings
drop table if exists t1;
--enable_warnings
create table t1 (
a1 char(64), a2 char(64), b char(16), c char(16) not null, d char(16), dummy char(64) default ' '
);
insert into t1 (a1, a2, b, c, d) values
('a','a','a','a111','xy1'),('a','a','a','b111','xy2'),('a','a','a','c111','xy3'),('a','a','a','d111','xy4'),
('a','a','b','e112','xy1'),('a','a','b','f112','xy2'),('a','a','b','g112','xy3'),('a','a','b','h112','xy4'),
('a','b','a','i121','xy1'),('a','b','a','j121','xy2'),('a','b','a','k121','xy3'),('a','b','a','l121','xy4'),
('a','b','b','m122','xy1'),('a','b','b','n122','xy2'),('a','b','b','o122','xy3'),('a','b','b','p122','xy4'),
('b','a','a','a211','xy1'),('b','a','a','b211','xy2'),('b','a','a','c211','xy3'),('b','a','a','d211','xy4'),
('b','a','b','e212','xy1'),('b','a','b','f212','xy2'),('b','a','b','g212','xy3'),('b','a','b','h212','xy4'),
('b','b','a','i221','xy1'),('b','b','a','j221','xy2'),('b','b','a','k221','xy3'),('b','b','a','l221','xy4'),
('b','b','b','m222','xy1'),('b','b','b','n222','xy2'),('b','b','b','o222','xy3'),('b','b','b','p222','xy4'),
('c','a','a','a311','xy1'),('c','a','a','b311','xy2'),('c','a','a','c311','xy3'),('c','a','a','d311','xy4'),
('c','a','b','e312','xy1'),('c','a','b','f312','xy2'),('c','a','b','g312','xy3'),('c','a','b','h312','xy4'),
('c','b','a','i321','xy1'),('c','b','a','j321','xy2'),('c','b','a','k321','xy3'),('c','b','a','l321','xy4'),
('c','b','b','m322','xy1'),('c','b','b','n322','xy2'),('c','b','b','o322','xy3'),('c','b','b','p322','xy4'),
('d','a','a','a411','xy1'),('d','a','a','b411','xy2'),('d','a','a','c411','xy3'),('d','a','a','d411','xy4'),
('d','a','b','e412','xy1'),('d','a','b','f412','xy2'),('d','a','b','g412','xy3'),('d','a','b','h412','xy4'),
('d','b','a','i421','xy1'),('d','b','a','j421','xy2'),('d','b','a','k421','xy3'),('d','b','a','l421','xy4'),
('d','b','b','m422','xy1'),('d','b','b','n422','xy2'),('d','b','b','o422','xy3'),('d','b','b','p422','xy4'),
('a','a','a','a111','xy1'),('a','a','a','b111','xy2'),('a','a','a','c111','xy3'),('a','a','a','d111','xy4'),
('a','a','b','e112','xy1'),('a','a','b','f112','xy2'),('a','a','b','g112','xy3'),('a','a','b','h112','xy4'),
('a','b','a','i121','xy1'),('a','b','a','j121','xy2'),('a','b','a','k121','xy3'),('a','b','a','l121','xy4'),
('a','b','b','m122','xy1'),('a','b','b','n122','xy2'),('a','b','b','o122','xy3'),('a','b','b','p122','xy4'),
('b','a','a','a211','xy1'),('b','a','a','b211','xy2'),('b','a','a','c211','xy3'),('b','a','a','d211','xy4'),
('b','a','b','e212','xy1'),('b','a','b','f212','xy2'),('b','a','b','g212','xy3'),('b','a','b','h212','xy4'),
('b','b','a','i221','xy1'),('b','b','a','j221','xy2'),('b','b','a','k221','xy3'),('b','b','a','l221','xy4'),
('b','b','b','m222','xy1'),('b','b','b','n222','xy2'),('b','b','b','o222','xy3'),('b','b','b','p222','xy4'),
('c','a','a','a311','xy1'),('c','a','a','b311','xy2'),('c','a','a','c311','xy3'),('c','a','a','d311','xy4'),
('c','a','b','e312','xy1'),('c','a','b','f312','xy2'),('c','a','b','g312','xy3'),('c','a','b','h312','xy4'),
('c','b','a','i321','xy1'),('c','b','a','j321','xy2'),('c','b','a','k321','xy3'),('c','b','a','l321','xy4'),
('c','b','b','m322','xy1'),('c','b','b','n322','xy2'),('c','b','b','o322','xy3'),('c','b','b','p322','xy4'),
('d','a','a','a411','xy1'),('d','a','a','b411','xy2'),('d','a','a','c411','xy3'),('d','a','a','d411','xy4'),
('d','a','b','e412','xy1'),('d','a','b','f412','xy2'),('d','a','b','g412','xy3'),('d','a','b','h412','xy4'),
('d','b','a','i421','xy1'),('d','b','a','j421','xy2'),('d','b','a','k421','xy3'),('d','b','a','l421','xy4'),
('d','b','b','m422','xy1'),('d','b','b','n422','xy2'),('d','b','b','o422','xy3'),('d','b','b','p422','xy4');
create index idx_t1_0 on t1 (a1);
create index idx_t1_1 on t1 (a1,a2,b,c);
create index idx_t1_2 on t1 (a1,a2,b);
analyze table t1;
-- t2 is the same as t1, but with some NULLs in the MIN/MAX column, and one more
-- nullable attribute
--disable_warnings
drop table if exists t2;
--enable_warnings
create table t2 (
a1 char(64), a2 char(64) not null, b char(16), c char(16), d char(16), dummy char(64) default ' '
);
insert into t2 select * from t1;
-- add few rows with NULL's in the MIN/MAX column
insert into t2 (a1, a2, b, c, d) values
('a','a',NULL,'a777','xyz'),('a','a',NULL,'a888','xyz'),('a','a',NULL,'a999','xyz'),
('a','a','a',NULL,'xyz'),
('a','a','b',NULL,'xyz'),
('a','b','a',NULL,'xyz'),
('c','a',NULL,'c777','xyz'),('c','a',NULL,'c888','xyz'),('c','a',NULL,'c999','xyz'),
('d','b','b',NULL,'xyz'),
('e','a','a',NULL,'xyz'),('e','a','a',NULL,'xyz'),('e','a','a',NULL,'xyz'),('e','a','a',NULL,'xyz'),
('e','a','b',NULL,'xyz'),('e','a','b',NULL,'xyz'),('e','a','b',NULL,'xyz'),('e','a','b',NULL,'xyz'),
('a','a',NULL,'a777','xyz'),('a','a',NULL,'a888','xyz'),('a','a',NULL,'a999','xyz'),
('a','a','a',NULL,'xyz'),
('a','a','b',NULL,'xyz'),
('a','b','a',NULL,'xyz'),
('c','a',NULL,'c777','xyz'),('c','a',NULL,'c888','xyz'),('c','a',NULL,'c999','xyz'),
('d','b','b',NULL,'xyz'),
('e','a','a',NULL,'xyz'),('e','a','a',NULL,'xyz'),('e','a','a',NULL,'xyz'),('e','a','a',NULL,'xyz'),
('e','a','b',NULL,'xyz'),('e','a','b',NULL,'xyz'),('e','a','b',NULL,'xyz'),('e','a','b',NULL,'xyz');
create index idx_t2_0 on t2 (a1);
create index idx_t2_1 on t2 (a1,a2,b,c);
create index idx_t2_2 on t2 (a1,a2,b);
analyze table t2;
-- Table t3 is the same as t1, but with smaller column lenghts.
-- This allows to test different branches of the cost computation procedure
-- when the number of keys per block are less than the number of keys in the
-- sub-groups formed by predicates over non-group attributes.
--disable_warnings
drop table if exists t3;
--enable_warnings
create table t3 (
a1 char(1), a2 char(1), b char(1), c char(4) not null, d char(3), dummy char(1) default ' '
);
insert into t3 (a1, a2, b, c, d) values
('a','a','a','a111','xy1'),('a','a','a','b111','xy2'),('a','a','a','c111','xy3'),('a','a','a','d111','xy4'),
('a','a','b','e112','xy1'),('a','a','b','f112','xy2'),('a','a','b','g112','xy3'),('a','a','b','h112','xy4'),
('a','b','a','i121','xy1'),('a','b','a','j121','xy2'),('a','b','a','k121','xy3'),('a','b','a','l121','xy4'),
('a','b','b','m122','xy1'),('a','b','b','n122','xy2'),('a','b','b','o122','xy3'),('a','b','b','p122','xy4'),
('b','a','a','a211','xy1'),('b','a','a','b211','xy2'),('b','a','a','c211','xy3'),('b','a','a','d211','xy4'),
('b','a','b','e212','xy1'),('b','a','b','f212','xy2'),('b','a','b','g212','xy3'),('b','a','b','h212','xy4'),
('b','b','a','i221','xy1'),('b','b','a','j221','xy2'),('b','b','a','k221','xy3'),('b','b','a','l221','xy4'),
('b','b','b','m222','xy1'),('b','b','b','n222','xy2'),('b','b','b','o222','xy3'),('b','b','b','p222','xy4'),
('c','a','a','a311','xy1'),('c','a','a','b311','xy2'),('c','a','a','c311','xy3'),('c','a','a','d311','xy4'),
('c','a','b','e312','xy1'),('c','a','b','f312','xy2'),('c','a','b','g312','xy3'),('c','a','b','h312','xy4'),
('c','b','a','i321','xy1'),('c','b','a','j321','xy2'),('c','b','a','k321','xy3'),('c','b','a','l321','xy4'),
('c','b','b','m322','xy1'),('c','b','b','n322','xy2'),('c','b','b','o322','xy3'),('c','b','b','p322','xy4');
insert into t3 (a1, a2, b, c, d) values
('a','a','a','a111','xy1'),('a','a','a','b111','xy2'),('a','a','a','c111','xy3'),('a','a','a','d111','xy4'),
('a','a','b','e112','xy1'),('a','a','b','f112','xy2'),('a','a','b','g112','xy3'),('a','a','b','h112','xy4'),
('a','b','a','i121','xy1'),('a','b','a','j121','xy2'),('a','b','a','k121','xy3'),('a','b','a','l121','xy4'),
('a','b','b','m122','xy1'),('a','b','b','n122','xy2'),('a','b','b','o122','xy3'),('a','b','b','p122','xy4'),
('b','a','a','a211','xy1'),('b','a','a','b211','xy2'),('b','a','a','c211','xy3'),('b','a','a','d211','xy4'),
('b','a','b','e212','xy1'),('b','a','b','f212','xy2'),('b','a','b','g212','xy3'),('b','a','b','h212','xy4'),
('b','b','a','i221','xy1'),('b','b','a','j221','xy2'),('b','b','a','k221','xy3'),('b','b','a','l221','xy4'),
('b','b','b','m222','xy1'),('b','b','b','n222','xy2'),('b','b','b','o222','xy3'),('b','b','b','p222','xy4'),
('c','a','a','a311','xy1'),('c','a','a','b311','xy2'),('c','a','a','c311','xy3'),('c','a','a','d311','xy4'),
('c','a','b','e312','xy1'),('c','a','b','f312','xy2'),('c','a','b','g312','xy3'),('c','a','b','h312','xy4'),
('c','b','a','i321','xy1'),('c','b','a','j321','xy2'),('c','b','a','k321','xy3'),('c','b','a','l321','xy4'),
('c','b','b','m322','xy1'),('c','b','b','n322','xy2'),('c','b','b','o322','xy3'),('c','b','b','p322','xy4');
insert into t3 (a1, a2, b, c, d) values
('a','a','a','a111','xy1'),('a','a','a','b111','xy2'),('a','a','a','c111','xy3'),('a','a','a','d111','xy4'),
('a','a','b','e112','xy1'),('a','a','b','f112','xy2'),('a','a','b','g112','xy3'),('a','a','b','h112','xy4'),
('a','b','a','i121','xy1'),('a','b','a','j121','xy2'),('a','b','a','k121','xy3'),('a','b','a','l121','xy4'),
('a','b','b','m122','xy1'),('a','b','b','n122','xy2'),('a','b','b','o122','xy3'),('a','b','b','p122','xy4'),
('b','a','a','a211','xy1'),('b','a','a','b211','xy2'),('b','a','a','c211','xy3'),('b','a','a','d211','xy4'),
('b','a','b','e212','xy1'),('b','a','b','f212','xy2'),('b','a','b','g212','xy3'),('b','a','b','h212','xy4'),
('b','b','a','i221','xy1'),('b','b','a','j221','xy2'),('b','b','a','k221','xy3'),('b','b','a','l221','xy4'),
('b','b','b','m222','xy1'),('b','b','b','n222','xy2'),('b','b','b','o222','xy3'),('b','b','b','p222','xy4'),
('c','a','a','a311','xy1'),('c','a','a','b311','xy2'),('c','a','a','c311','xy3'),('c','a','a','d311','xy4'),
('c','a','b','e312','xy1'),('c','a','b','f312','xy2'),('c','a','b','g312','xy3'),('c','a','b','h312','xy4'),
('c','b','a','i321','xy1'),('c','b','a','j321','xy2'),('c','b','a','k321','xy3'),('c','b','a','l321','xy4'),
('c','b','b','m322','xy1'),('c','b','b','n322','xy2'),('c','b','b','o322','xy3'),('c','b','b','p322','xy4');
insert into t3 (a1, a2, b, c, d) values
('a','a','a','a111','xy1'),('a','a','a','b111','xy2'),('a','a','a','c111','xy3'),('a','a','a','d111','xy4'),
('a','a','b','e112','xy1'),('a','a','b','f112','xy2'),('a','a','b','g112','xy3'),('a','a','b','h112','xy4'),
('a','b','a','i121','xy1'),('a','b','a','j121','xy2'),('a','b','a','k121','xy3'),('a','b','a','l121','xy4'),
('a','b','b','m122','xy1'),('a','b','b','n122','xy2'),('a','b','b','o122','xy3'),('a','b','b','p122','xy4'),
('b','a','a','a211','xy1'),('b','a','a','b211','xy2'),('b','a','a','c211','xy3'),('b','a','a','d211','xy4'),
('b','a','b','e212','xy1'),('b','a','b','f212','xy2'),('b','a','b','g212','xy3'),('b','a','b','h212','xy4'),
('b','b','a','i221','xy1'),('b','b','a','j221','xy2'),('b','b','a','k221','xy3'),('b','b','a','l221','xy4'),
('b','b','b','m222','xy1'),('b','b','b','n222','xy2'),('b','b','b','o222','xy3'),('b','b','b','p222','xy4'),
('c','a','a','a311','xy1'),('c','a','a','b311','xy2'),('c','a','a','c311','xy3'),('c','a','a','d311','xy4'),
('c','a','b','e312','xy1'),('c','a','b','f312','xy2'),('c','a','b','g312','xy3'),('c','a','b','h312','xy4'),
('c','b','a','i321','xy1'),('c','b','a','j321','xy2'),('c','b','a','k321','xy3'),('c','b','a','l321','xy4'),
('c','b','b','m322','xy1'),('c','b','b','n322','xy2'),('c','b','b','o322','xy3'),('c','b','b','p322','xy4');
create index idx_t3_0 on t3 (a1);
create index idx_t3_1 on t3 (a1,a2,b,c);
create index idx_t3_2 on t3 (a1,a2,b);
analyze table t3;
--
-- Queries without a WHERE clause. These queries do not use ranges.
--
-- plans
explain select a1, min(a2) from t1 group by a1;
explain select a1, max(a2) from t1 group by a1;
explain select a1, min(a2), max(a2) from t1 group by a1;
explain select a1, a2, b, min(c), max(c) from t1 group by a1,a2,b;
explain select a1,a2,b,max(c),min(c) from t1 group by a1,a2,b;
explain select a1,a2,b,max(c),min(c) from t2 group by a1,a2,b;
-- Select fields in different order
explain select min(a2), a1, max(a2), min(a2), a1 from t1 group by a1;
explain select a1, b, min(c), a1, max(c), b, a2, max(c), max(c) from t1 group by a1, a2, b;
explain select min(a2) from t1 group by a1;
explain select a2, min(c), max(c) from t1 group by a1,a2,b;
-- queries
select a1, min(a2) from t1 group by a1;
select a1, max(a2) from t1 group by a1;
select a1, min(a2), max(a2) from t1 group by a1;
select a1, a2, b, min(c), max(c) from t1 group by a1,a2,b;
select a1,a2,b,max(c),min(c) from t1 group by a1,a2,b;
select a1,a2,b,max(c),min(c) from t2 group by a1,a2,b;
-- Select fields in different order
select min(a2), a1, max(a2), min(a2), a1 from t1 group by a1;
select a1, b, min(c), a1, max(c), b, a2, max(c), max(c) from t1 group by a1, a2, b;
select min(a2) from t1 group by a1;
select a2, min(c), max(c) from t1 group by a1,a2,b;
--
-- Queries with a where clause
--
-- A) Preds only over the group 'A' attributes
-- plans
explain select a1,a2,b,min(c),max(c) from t1 where a1 < 'd' group by a1,a2,b;
explain select a1,a2,b,min(c),max(c) from t1 where a1 >= 'b' group by a1,a2,b;
explain select a1,a2,b, max(c) from t1 where a1 >= 'c' or a1 < 'b' group by a1,a2,b;
explain select a1, max(c) from t1 where a1 >= 'c' or a1 < 'b' group by a1,a2,b;
explain select a1,a2,b,min(c),max(c) from t1 where a1 >= 'c' or a2 < 'b' group by a1,a2,b;
explain select a1,a2,b, max(c) from t1 where a1 = 'z' or a1 = 'b' or a1 = 'd' group by a1,a2,b;
explain select a1,a2,b,min(c),max(c) from t1 where a1 = 'z' or a1 = 'b' or a1 = 'd' group by a1,a2,b;
explain select a1,a2,b, max(c) from t1 where (a1 = 'b' or a1 = 'd' or a1 = 'a' or a1 = 'c') and (a2 > 'a') group by a1,a2,b;
explain select a1,a2,b,min(c),max(c) from t1 where (a1 = 'b' or a1 = 'd' or a1 = 'a' or a1 = 'c') and (a2 > 'a') group by a1,a2,b;
explain select a1,min(c),max(c) from t1 where a1 >= 'b' group by a1,a2,b;
explain select a1, max(c) from t1 where a1 in ('a','b','d') group by a1,a2,b;
explain select a1,a2,b, max(c) from t2 where a1 < 'd' group by a1,a2,b;
explain select a1,a2,b,min(c),max(c) from t2 where a1 < 'd' group by a1,a2,b;
explain select a1,a2,b,min(c),max(c) from t2 where a1 >= 'b' group by a1,a2,b;
explain select a1,a2,b, max(c) from t2 where a1 >= 'c' or a1 < 'b' group by a1,a2,b;
explain select a1, max(c) from t2 where a1 >= 'c' or a1 < 'b' group by a1,a2,b;
explain select a1,a2,b,min(c),max(c) from t2 where a1 >= 'c' or a2 < 'b' group by a1,a2,b;
explain select a1,a2,b, max(c) from t2 where a1 = 'z' or a1 = 'b' or a1 = 'd' group by a1,a2,b;
explain select a1,a2,b,min(c),max(c) from t2 where a1 = 'z' or a1 = 'b' or a1 = 'd' group by a1,a2,b;
explain select a1,a2,b, max(c) from t2 where (a1 = 'b' or a1 = 'd' or a1 = 'a' or a1 = 'c') and (a2 > 'a') group by a1,a2,b;
explain select a1,a2,b,min(c),max(c) from t2 where (a1 = 'b' or a1 = 'd' or a1 = 'a' or a1 = 'c') and (a2 > 'a') group by a1,a2,b;
explain select a1,min(c),max(c) from t2 where a1 >= 'b' group by a1,a2,b;
explain select a1, max(c) from t2 where a1 in ('a','b','d') group by a1,a2,b;
-- queries
select a1,a2,b,min(c),max(c) from t1 where a1 < 'd' group by a1,a2,b;
select a1,a2,b,min(c),max(c) from t1 where a1 >= 'b' group by a1,a2,b;
select a1,a2,b, max(c) from t1 where a1 >= 'c' or a1 < 'b' group by a1,a2,b;
select a1, max(c) from t1 where a1 >= 'c' or a1 < 'b' group by a1,a2,b;
select a1,a2,b,min(c),max(c) from t1 where a1 >= 'c' or a2 < 'b' group by a1,a2,b;
select a1,a2,b, max(c) from t1 where a1 = 'z' or a1 = 'b' or a1 = 'd' group by a1,a2,b;
select a1,a2,b,min(c),max(c) from t1 where a1 = 'z' or a1 = 'b' or a1 = 'd' group by a1,a2,b;
select a1,a2,b, max(c) from t1 where (a1 = 'b' or a1 = 'd' or a1 = 'a' or a1 = 'c') and (a2 > 'a') group by a1,a2,b;
select a1,a2,b,min(c),max(c) from t1 where (a1 = 'b' or a1 = 'd' or a1 = 'a' or a1 = 'c') and (a2 > 'a') group by a1,a2,b;
select a1,min(c),max(c) from t1 where a1 >= 'b' group by a1,a2,b;
select a1, max(c) from t1 where a1 in ('a','b','d') group by a1,a2,b;
select a1,a2,b, max(c) from t2 where a1 < 'd' group by a1,a2,b;
select a1,a2,b,min(c),max(c) from t2 where a1 < 'd' group by a1,a2,b;
select a1,a2,b,min(c),max(c) from t2 where a1 >= 'b' group by a1,a2,b;
select a1,a2,b, max(c) from t2 where a1 >= 'c' or a1 < 'b' group by a1,a2,b;
select a1, max(c) from t2 where a1 >= 'c' or a1 < 'b' group by a1,a2,b;
select a1,a2,b,min(c),max(c) from t2 where a1 >= 'c' or a2 < 'b' group by a1,a2,b;
select a1,a2,b, max(c) from t2 where a1 = 'z' or a1 = 'b' or a1 = 'd' group by a1,a2,b;
select a1,a2,b,min(c),max(c) from t2 where a1 = 'z' or a1 = 'b' or a1 = 'd' group by a1,a2,b;
select a1,a2,b, max(c) from t2 where (a1 = 'b' or a1 = 'd' or a1 = 'a' or a1 = 'c') and (a2 > 'a') group by a1,a2,b;
select a1,a2,b,min(c),max(c) from t2 where (a1 = 'b' or a1 = 'd' or a1 = 'a' or a1 = 'c') and (a2 > 'a') group by a1,a2,b;
select a1,min(c),max(c) from t2 where a1 >= 'b' group by a1,a2,b;
select a1, max(c) from t2 where a1 in ('a','b','d') group by a1,a2,b;
-- B) Equalities only over the non-group 'B' attributes
-- plans
explain select a1,a2,b,max(c),min(c) from t1 where (a2 = 'a') and (b = 'b') group by a1;
explain select a1,max(c),min(c) from t1 where (a2 = 'a') and (b = 'b') group by a1;
explain select a1,a2,b, max(c) from t1 where (b = 'b') group by a1,a2;
explain select a1,a2,b,min(c),max(c) from t1 where (b = 'b') group by a1,a2;
explain select a1,a2, max(c) from t1 where (b = 'b') group by a1,a2;
explain select a1,a2,b,max(c),min(c) from t2 where (a2 = 'a') and (b = 'b') group by a1;
explain select a1,max(c),min(c) from t2 where (a2 = 'a') and (b = 'b') group by a1;
explain select a1,a2,b, max(c) from t2 where (b = 'b') group by a1,a2;
explain select a1,a2,b,min(c),max(c) from t2 where (b = 'b') group by a1,a2;
explain select a1,a2, max(c) from t2 where (b = 'b') group by a1,a2;
-- these queries test case 2) in TRP_GROUP_MIN_MAX::update_cost()
explain select a1,a2,b,max(c),min(c) from t3 where (a2 = 'a') and (b = 'b') group by a1;
explain select a1,max(c),min(c) from t3 where (a2 = 'a') and (b = 'b') group by a1;
-- queries
select a1,a2,b,max(c),min(c) from t1 where (a2 = 'a') and (b = 'b') group by a1;
select a1,max(c),min(c) from t1 where (a2 = 'a') and (b = 'b') group by a1;
select a1,a2,b, max(c) from t1 where (b = 'b') group by a1,a2;
select a1,a2,b,min(c),max(c) from t1 where (b = 'b') group by a1,a2;
select a1,a2, max(c) from t1 where (b = 'b') group by a1,a2;
select a1,a2,b,max(c),min(c) from t2 where (a2 = 'a') and (b = 'b') group by a1;
select a1,max(c),min(c) from t2 where (a2 = 'a') and (b = 'b') group by a1;
select a1,a2,b, max(c) from t2 where (b = 'b') group by a1,a2;
select a1,a2,b,min(c),max(c) from t2 where (b = 'b') group by a1,a2;
select a1,a2, max(c) from t2 where (b = 'b') group by a1,a2;
-- these queries test case 2) in TRP_GROUP_MIN_MAX::update_cost()
select a1,a2,b,max(c),min(c) from t3 where (a2 = 'a') and (b = 'b') group by a1;
select a1,max(c),min(c) from t3 where (a2 = 'a') and (b = 'b') group by a1;
-- IS NULL (makes sense for t2 only)
-- plans
explain select a1,a2,b,min(c) from t2 where (a2 = 'a') and b is NULL group by a1;
explain select a1,a2,b,max(c) from t2 where (a2 = 'a') and b is NULL group by a1;
explain select a1,a2,b,min(c) from t2 where b is NULL group by a1,a2;
explain select a1,a2,b,max(c) from t2 where b is NULL group by a1,a2;
explain select a1,a2,b,min(c),max(c) from t2 where b is NULL group by a1,a2;
explain select a1,a2,b,min(c),max(c) from t2 where b is NULL group by a1,a2;
-- queries
select a1,a2,b,min(c) from t2 where (a2 = 'a') and b is NULL group by a1;
select a1,a2,b,max(c) from t2 where (a2 = 'a') and b is NULL group by a1;
select a1,a2,b,min(c) from t2 where b is NULL group by a1,a2;
select a1,a2,b,max(c) from t2 where b is NULL group by a1,a2;
select a1,a2,b,min(c),max(c) from t2 where b is NULL group by a1,a2;
select a1,a2,b,min(c),max(c) from t2 where b is NULL group by a1,a2;
-- C) Range predicates for the MIN/MAX attribute
-- plans
explain select a1,a2,b, max(c) from t1 where (c > 'b1') group by a1,a2,b;
explain select a1,a2,b,min(c),max(c) from t1 where (c > 'b1') group by a1,a2,b;
explain select a1,a2,b, max(c) from t1 where (c > 'f123') group by a1,a2,b;
explain select a1,a2,b,min(c),max(c) from t1 where (c > 'f123') group by a1,a2,b;
explain select a1,a2,b, max(c) from t1 where (c < 'a0') group by a1,a2,b;
explain select a1,a2,b,min(c),max(c) from t1 where (c < 'a0') group by a1,a2,b;
explain select a1,a2,b, max(c) from t1 where (c < 'k321') group by a1,a2,b;
explain select a1,a2,b,min(c),max(c) from t1 where (c < 'k321') group by a1,a2,b;
explain select a1,a2,b, max(c) from t1 where (c < 'a0') or (c > 'b1') group by a1,a2,b;
explain select a1,a2,b,min(c),max(c) from t1 where (c < 'a0') or (c > 'b1') group by a1,a2,b;
explain select a1,a2,b, max(c) from t1 where (c > 'b1') or (c <= 'g1') group by a1,a2,b;
explain select a1,a2,b,min(c),max(c) from t1 where (c > 'b1') or (c <= 'g1') group by a1,a2,b;
explain select a1,a2,b,min(c),max(c) from t1 where (c > 'b111') and (c <= 'g112') group by a1,a2,b;
explain select a1,a2,b,min(c),max(c) from t1 where (c < 'c5') or (c = 'g412') or (c = 'k421') group by a1,a2,b;
explain select a1,a2,b,min(c),max(c) from t1 where ((c > 'b111') and (c <= 'g112')) or ((c > 'd000') and (c <= 'i110')) group by a1,a2,b;
explain select a1,a2,b,min(c),max(c) from t1 where (c between 'b111' and 'g112') or (c between 'd000' and 'i110') group by a1,a2,b;
explain select a1,a2,b, max(c) from t2 where (c > 'b1') group by a1,a2,b;
explain select a1,a2,b,min(c),max(c) from t2 where (c > 'b1') group by a1,a2,b;
explain select a1,a2,b, max(c) from t2 where (c > 'f123') group by a1,a2,b;
explain select a1,a2,b,min(c),max(c) from t2 where (c > 'f123') group by a1,a2,b;
explain select a1,a2,b, max(c) from t2 where (c < 'a0') group by a1,a2,b;
explain select a1,a2,b,min(c),max(c) from t2 where (c < 'a0') group by a1,a2,b;
explain select a1,a2,b, max(c) from t2 where (c < 'k321') group by a1,a2,b;
explain select a1,a2,b,min(c),max(c) from t2 where (c < 'k321') group by a1,a2,b;
explain select a1,a2,b, max(c) from t2 where (c < 'a0') or (c > 'b1') group by a1,a2,b;
explain select a1,a2,b,min(c),max(c) from t2 where (c < 'a0') or (c > 'b1') group by a1,a2,b;
explain select a1,a2,b, max(c) from t2 where (c > 'b1') or (c <= 'g1') group by a1,a2,b;
explain select a1,a2,b,min(c),max(c) from t2 where (c > 'b1') or (c <= 'g1') group by a1,a2,b;
explain select a1,a2,b,min(c),max(c) from t2 where (c > 'b111') and (c <= 'g112') group by a1,a2,b;
explain select a1,a2,b,min(c),max(c) from t2 where (c < 'c5') or (c = 'g412') or (c = 'k421') group by a1,a2,b;
explain select a1,a2,b,min(c),max(c) from t2 where ((c > 'b111') and (c <= 'g112')) or ((c > 'd000') and (c <= 'i110')) group by a1,a2,b;
-- queries
select a1,a2,b, max(c) from t1 where (c > 'b1') group by a1,a2,b;
select a1,a2,b,min(c),max(c) from t1 where (c > 'b1') group by a1,a2,b;
select a1,a2,b, max(c) from t1 where (c > 'f123') group by a1,a2,b;
select a1,a2,b,min(c),max(c) from t1 where (c > 'f123') group by a1,a2,b;
select a1,a2,b, max(c) from t1 where (c < 'a0') group by a1,a2,b;
select a1,a2,b,min(c),max(c) from t1 where (c < 'a0') group by a1,a2,b;
select a1,a2,b, max(c) from t1 where (c < 'k321') group by a1,a2,b;
select a1,a2,b,min(c),max(c) from t1 where (c < 'k321') group by a1,a2,b;
select a1,a2,b, max(c) from t1 where (c < 'a0') or (c > 'b1') group by a1,a2,b;
select a1,a2,b,min(c),max(c) from t1 where (c < 'a0') or (c > 'b1') group by a1,a2,b;
select a1,a2,b, max(c) from t1 where (c > 'b1') or (c <= 'g1') group by a1,a2,b;
select a1,a2,b,min(c),max(c) from t1 where (c > 'b1') or (c <= 'g1') group by a1,a2,b;
select a1,a2,b,min(c),max(c) from t1 where (c > 'b111') and (c <= 'g112') group by a1,a2,b;
select a1,a2,b,min(c),max(c) from t1 where (c < 'c5') or (c = 'g412') or (c = 'k421') group by a1,a2,b;
select a1,a2,b,min(c),max(c) from t1 where ((c > 'b111') and (c <= 'g112')) or ((c > 'd000') and (c <= 'i110')) group by a1,a2,b;
select a1,a2,b,min(c),max(c) from t1 where (c between 'b111' and 'g112') or (c between 'd000' and 'i110') group by a1,a2,b;
select a1,a2,b, max(c) from t2 where (c > 'b1') group by a1,a2,b;
select a1,a2,b,min(c),max(c) from t2 where (c > 'b1') group by a1,a2,b;
select a1,a2,b, max(c) from t2 where (c > 'f123') group by a1,a2,b;
select a1,a2,b,min(c),max(c) from t2 where (c > 'f123') group by a1,a2,b;
select a1,a2,b, max(c) from t2 where (c < 'a0') group by a1,a2,b;
select a1,a2,b,min(c),max(c) from t2 where (c < 'a0') group by a1,a2,b;
select a1,a2,b, max(c) from t2 where (c < 'k321') group by a1,a2,b;
select a1,a2,b,min(c),max(c) from t2 where (c < 'k321') group by a1,a2,b;
select a1,a2,b, max(c) from t2 where (c < 'a0') or (c > 'b1') group by a1,a2,b;
select a1,a2,b,min(c),max(c) from t2 where (c < 'a0') or (c > 'b1') group by a1,a2,b;
select a1,a2,b, max(c) from t2 where (c > 'b1') or (c <= 'g1') group by a1,a2,b;
select a1,a2,b,min(c),max(c) from t2 where (c > 'b1') or (c <= 'g1') group by a1,a2,b;
select a1,a2,b,min(c),max(c) from t2 where (c > 'b111') and (c <= 'g112') group by a1,a2,b;
select a1,a2,b,min(c),max(c) from t2 where (c < 'c5') or (c = 'g412') or (c = 'k421') group by a1,a2,b;
select a1,a2,b,min(c),max(c) from t2 where ((c > 'b111') and (c <= 'g112')) or ((c > 'd000') and (c <= 'i110')) group by a1,a2,b;
-- A,B,C) Predicates referencing mixed classes of attributes
-- plans
explain select a1,a2,b,min(c),max(c) from t1 where (a1 >= 'c' or a2 < 'b') and (b > 'a') group by a1,a2,b;
explain select a1,a2,b,min(c),max(c) from t1 where (a1 >= 'c' or a2 < 'b') and (c > 'b111') group by a1,a2,b;
explain select a1,a2,b,min(c),max(c) from t1 where (a2 >= 'b') and (b = 'a') and (c > 'b111') group by a1,a2,b;
explain select a1,a2,b,min(c) from t1 where ((a1 > 'a') or (a1 < '9')) and ((a2 >= 'b') and (a2 < 'z')) and (b = 'a') and ((c < 'h112') or (c = 'j121') or (c > 'k121' and c < 'm122') or (c > 'o122')) group by a1,a2,b;
explain select a1,a2,b,min(c) from t1 where ((a1 > 'a') or (a1 < '9')) and ((a2 >= 'b') and (a2 < 'z')) and (b = 'a') and ((c = 'j121') or (c > 'k121' and c < 'm122') or (c > 'o122') or (c < 'h112') or (c = 'c111')) group by a1,a2,b;
explain select a1,a2,b,min(c) from t1 where (a1 > 'a') and (a2 > 'a') and (b = 'c') group by a1,a2,b;
explain select a1,a2,b,min(c) from t1 where (ord(a1) > 97) and (ord(a2) + ord(a1) > 194) and (b = 'c') group by a1,a2,b;
explain select a1,a2,b,min(c),max(c) from t2 where (a1 >= 'c' or a2 < 'b') and (b > 'a') group by a1,a2,b;
explain select a1,a2,b,min(c),max(c) from t2 where (a1 >= 'c' or a2 < 'b') and (c > 'b111') group by a1,a2,b;
explain select a1,a2,b,min(c),max(c) from t2 where (a2 >= 'b') and (b = 'a') and (c > 'b111') group by a1,a2,b;
explain select a1,a2,b,min(c) from t2 where ((a1 > 'a') or (a1 < '9')) and ((a2 >= 'b') and (a2 < 'z')) and (b = 'a') and ((c < 'h112') or (c = 'j121') or (c > 'k121' and c < 'm122') or (c > 'o122')) group by a1,a2,b;
explain select a1,a2,b,min(c) from t2 where ((a1 > 'a') or (a1 < '9')) and ((a2 >= 'b') and (a2 < 'z')) and (b = 'a') and ((c = 'j121') or (c > 'k121' and c < 'm122') or (c > 'o122') or (c < 'h112') or (c = 'c111')) group by a1,a2,b;
explain select a1,a2,b,min(c) from t2 where (a1 > 'a') and (a2 > 'a') and (b = 'c') group by a1,a2,b;
-- queries
select a1,a2,b,min(c),max(c) from t1 where (a1 >= 'c' or a2 < 'b') and (b > 'a') group by a1,a2,b;
select a1,a2,b,min(c),max(c) from t1 where (a1 >= 'c' or a2 < 'b') and (c > 'b111') group by a1,a2,b;
select a1,a2,b,min(c),max(c) from t1 where (a2 >= 'b') and (b = 'a') and (c > 'b111') group by a1,a2,b;
select a1,a2,b,min(c) from t1 where ((a1 > 'a') or (a1 < '9')) and ((a2 >= 'b') and (a2 < 'z')) and (b = 'a') and ((c < 'h112') or (c = 'j121') or (c > 'k121' and c < 'm122') or (c > 'o122')) group by a1,a2,b;
select a1,a2,b,min(c) from t1 where ((a1 > 'a') or (a1 < '9')) and ((a2 >= 'b') and (a2 < 'z')) and (b = 'a') and ((c = 'j121') or (c > 'k121' and c < 'm122') or (c > 'o122') or (c < 'h112') or (c = 'c111')) group by a1,a2,b;
select a1,a2,b,min(c) from t1 where (a1 > 'a') and (a2 > 'a') and (b = 'c') group by a1,a2,b;
select a1,a2,b,min(c) from t1 where (ord(a1) > 97) and (ord(a2) + ord(a1) > 194) and (b = 'c') group by a1,a2,b;
select a1,a2,b,min(c),max(c) from t2 where (a1 >= 'c' or a2 < 'b') and (b > 'a') group by a1,a2,b;
select a1,a2,b,min(c),max(c) from t2 where (a1 >= 'c' or a2 < 'b') and (c > 'b111') group by a1,a2,b;
select a1,a2,b,min(c),max(c) from t2 where (a2 >= 'b') and (b = 'a') and (c > 'b111') group by a1,a2,b;
select a1,a2,b,min(c) from t2 where ((a1 > 'a') or (a1 < '9')) and ((a2 >= 'b') and (a2 < 'z')) and (b = 'a') and ((c < 'h112') or (c = 'j121') or (c > 'k121' and c < 'm122') or (c > 'o122')) group by a1,a2,b;
select a1,a2,b,min(c) from t2 where ((a1 > 'a') or (a1 < '9')) and ((a2 >= 'b') and (a2 < 'z')) and (b = 'a') and ((c = 'j121') or (c > 'k121' and c < 'm122') or (c > 'o122') or (c < 'h112') or (c = 'c111')) group by a1,a2,b;
select a1,a2,b,min(c) from t2 where (a1 > 'a') and (a2 > 'a') and (b = 'c') group by a1,a2,b;
--
-- GROUP BY queries without MIN/MAX
--
-- plans
explain select a1,a2,b from t1 where (a1 >= 'c' or a2 < 'b') and (b > 'a') group by a1,a2,b;
explain select a1,a2,b from t1 where (a2 >= 'b') and (b = 'a') group by a1,a2,b;
explain select a1,a2,b,c from t1 where (a2 >= 'b') and (b = 'a') and (c = 'i121') group by a1,a2,b;
explain select a1,a2,b from t1 where (a1 > 'a') and (a2 > 'a') and (b = 'c') group by a1,a2,b;
explain select a1,a2,b from t2 where (a1 >= 'c' or a2 < 'b') and (b > 'a') group by a1,a2,b;
explain select a1,a2,b from t2 where (a2 >= 'b') and (b = 'a') group by a1,a2,b;
explain select a1,a2,b,c from t2 where (a2 >= 'b') and (b = 'a') and (c = 'i121') group by a1,a2,b;
explain select a1,a2,b from t2 where (a1 > 'a') and (a2 > 'a') and (b = 'c') group by a1,a2,b;
-- queries
select a1,a2,b from t1 where (a1 >= 'c' or a2 < 'b') and (b > 'a') group by a1,a2,b;
select a1,a2,b from t1 where (a2 >= 'b') and (b = 'a') group by a1,a2,b;
select a1,a2,b,c from t1 where (a2 >= 'b') and (b = 'a') and (c = 'i121') group by a1,a2,b;
select a1,a2,b from t1 where (a1 > 'a') and (a2 > 'a') and (b = 'c') group by a1,a2,b;
select a1,a2,b from t2 where (a1 >= 'c' or a2 < 'b') and (b > 'a') group by a1,a2,b;
select a1,a2,b from t2 where (a2 >= 'b') and (b = 'a') group by a1,a2,b;
select a1,a2,b,c from t2 where (a2 >= 'b') and (b = 'a') and (c = 'i121') group by a1,a2,b;
select a1,a2,b from t2 where (a1 > 'a') and (a2 > 'a') and (b = 'c') group by a1,a2,b;
--
-- DISTINCT queries
--
-- plans
explain select distinct a1,a2,b from t1;
explain select distinct a1,a2,b from t1 where (a2 >= 'b') and (b = 'a');
explain select distinct a1,a2,b,c from t1 where (a2 >= 'b') and (b = 'a') and (c = 'i121');
explain select distinct a1,a2,b from t1 where (a1 > 'a') and (a2 > 'a') and (b = 'c');
explain select distinct b from t1 where (a2 >= 'b') and (b = 'a');
explain select distinct a1,a2,b from t2;
explain select distinct a1,a2,b from t2 where (a2 >= 'b') and (b = 'a');
explain select distinct a1,a2,b,c from t2 where (a2 >= 'b') and (b = 'a') and (c = 'i121');
explain select distinct a1,a2,b from t2 where (a1 > 'a') and (a2 > 'a') and (b = 'c');
explain select distinct b from t2 where (a2 >= 'b') and (b = 'a');
-- queries
select distinct a1,a2,b from t1;
select distinct a1,a2,b from t1 where (a2 >= 'b') and (b = 'a');
select distinct a1,a2,b,c from t1 where (a2 >= 'b') and (b = 'a') and (c = 'i121');
select distinct a1,a2,b from t1 where (a1 > 'a') and (a2 > 'a') and (b = 'c');
select distinct b from t1 where (a2 >= 'b') and (b = 'a');
select distinct a1,a2,b from t2;
select distinct a1,a2,b from t2 where (a2 >= 'b') and (b = 'a');
select distinct a1,a2,b,c from t2 where (a2 >= 'b') and (b = 'a') and (c = 'i121');
select distinct a1,a2,b from t2 where (a1 > 'a') and (a2 > 'a') and (b = 'c');
select distinct b from t2 where (a2 >= 'b') and (b = 'a');
--
-- DISTINCT queries with GROUP-BY
--
-- plans
explain select distinct a1,a2,b from t1;
explain select distinct a1,a2,b from t1 where (a2 >= 'b') and (b = 'a') group by a1,a2,b;
explain select distinct a1,a2,b,c from t1 where (a2 >= 'b') and (b = 'a') and (c = 'i121') group by a1,a2,b;
explain select distinct a1,a2,b from t1 where (a1 > 'a') and (a2 > 'a') and (b = 'c') group by a1,a2,b;
explain select distinct b from t1 where (a2 >= 'b') and (b = 'a') group by a1,a2,b;
explain select distinct a1,a2,b from t2;
explain select distinct a1,a2,b from t2 where (a2 >= 'b') and (b = 'a') group by a1,a2,b;
explain select distinct a1,a2,b,c from t2 where (a2 >= 'b') and (b = 'a') and (c = 'i121') group by a1,a2,b;
explain select distinct a1,a2,b from t2 where (a1 > 'a') and (a2 > 'a') and (b = 'c') group by a1,a2,b;
explain select distinct b from t2 where (a2 >= 'b') and (b = 'a') group by a1,a2,b;
-- queries
select distinct a1,a2,b from t1;
select distinct a1,a2,b from t1 where (a2 >= 'b') and (b = 'a') group by a1,a2,b;
select distinct a1,a2,b,c from t1 where (a2 >= 'b') and (b = 'a') and (c = 'i121') group by a1,a2,b;
select distinct a1,a2,b from t1 where (a1 > 'a') and (a2 > 'a') and (b = 'c') group by a1,a2,b;
select distinct b from t1 where (a2 >= 'b') and (b = 'a') group by a1,a2,b;
select distinct a1,a2,b from t2;
select distinct a1,a2,b from t2 where (a2 >= 'b') and (b = 'a') group by a1,a2,b;
select distinct a1,a2,b,c from t2 where (a2 >= 'b') and (b = 'a') and (c = 'i121') group by a1,a2,b;
select distinct a1,a2,b from t2 where (a1 > 'a') and (a2 > 'a') and (b = 'c') group by a1,a2,b;
select distinct b from t2 where (a2 >= 'b') and (b = 'a') group by a1,a2,b;
--
-- COUNT (DISTINCT cols) queries
--
explain select count(distinct a1,a2,b) from t1 where (a2 >= 'b') and (b = 'a');
explain select count(distinct a1,a2,b,c) from t1 where (a2 >= 'b') and (b = 'a') and (c = 'i121');
explain select count(distinct a1,a2,b) from t1 where (a1 > 'a') and (a2 > 'a') and (b = 'c');
explain select count(distinct b) from t1 where (a2 >= 'b') and (b = 'a');
explain select ord(a1) + count(distinct a1,a2,b) from t1 where (a1 > 'a') and (a2 > 'a');
select count(distinct a1,a2,b) from t1 where (a2 >= 'b') and (b = 'a');
select count(distinct a1,a2,b,c) from t1 where (a2 >= 'b') and (b = 'a') and (c = 'i121');
select count(distinct a1,a2,b) from t1 where (a1 > 'a') and (a2 > 'a') and (b = 'c');
select count(distinct b) from t1 where (a2 >= 'b') and (b = 'a');
select ord(a1) + count(distinct a1,a2,b) from t1 where (a1 > 'a') and (a2 > 'a');
--
-- Queries with expressions in the select clause
--
explain select a1,a2,b, concat(min(c), max(c)) from t1 where a1 < 'd' group by a1,a2,b;
explain select concat(a1,min(c)),b from t1 where a1 < 'd' group by a1,a2,b;
explain select concat(a1,min(c)),b,max(c) from t1 where a1 < 'd' group by a1,a2,b;
explain select concat(a1,a2),b,min(c),max(c) from t1 where a1 < 'd' group by a1,a2,b;
explain select concat(ord(min(b)),ord(max(b))),min(b),max(b) from t1 group by a1,a2;
select a1,a2,b, concat(min(c), max(c)) from t1 where a1 < 'd' group by a1,a2,b;
select concat(a1,min(c)),b from t1 where a1 < 'd' group by a1,a2,b;
select concat(a1,min(c)),b,max(c) from t1 where a1 < 'd' group by a1,a2,b;
select concat(a1,a2),b,min(c),max(c) from t1 where a1 < 'd' group by a1,a2,b;
select concat(ord(min(b)),ord(max(b))),min(b),max(b) from t1 group by a1,a2;
--
-- Negative examples: queries that should NOT be treated as optimizable by
-- QUICK_GROUP_MIN_MAX_SELECT
--
-- select a non-indexed attribute
explain select a1,a2,b,d,min(c),max(c) from t1 group by a1,a2,b;
explain select a1,a2,b,d from t1 group by a1,a2,b;
-- predicate that references an attribute that is after the MIN/MAX argument
-- in the index
explain select a1,a2,min(b),max(b) from t1
where (a1 = 'b' or a1 = 'd' or a1 = 'a' or a1 = 'c') and (a2 > 'a') and (c > 'a111') group by a1,a2;
-- predicate that references a non-indexed attribute
explain select a1,a2,b,min(c),max(c) from t1
where (a1 = 'b' or a1 = 'd' or a1 = 'a' or a1 = 'c') and (a2 > 'a') and (d > 'xy2') group by a1,a2,b;
explain select a1,a2,b,c from t1
where (a1 = 'b' or a1 = 'd' or a1 = 'a' or a1 = 'c') and (a2 > 'a') and (d > 'xy2') group by a1,a2,b,c;
-- non-equality predicate for a non-group select attribute
explain select a1,a2,b,max(c),min(c) from t2 where (a2 = 'a') and (b = 'b') or (b < 'b') group by a1;
explain select a1,a2,b from t1 where (a1 = 'b' or a1 = 'd' or a1 = 'a' or a1 = 'c') and (a2 > 'a') and (c > 'a111') group by a1,a2,b;
-- non-group field with an equality predicate that references a keypart after the
-- MIN/MAX argument
explain select a1,a2,min(b),c from t2 where (a2 = 'a') and (c = 'a111') group by a1;
select a1,a2,min(b),c from t2 where (a2 = 'a') and (c = 'a111') group by a1;
-- disjunction for a non-group select attribute
explain select a1,a2,b,max(c),min(c) from t2 where (a2 = 'a') and (b = 'b') or (b = 'a') group by a1;
-- non-range predicate for the MIN/MAX attribute
explain select a1,a2,b,min(c),max(c) from t2
where (c > 'a000') and (c <= 'd999') and (c like '_8__') group by a1,a2,b;
-- not all attributes are indexed by one index
explain select a1, a2, b, c, min(d), max(d) from t1 group by a1,a2,b,c;
-- other aggregate functions than MIN/MAX
explain select a1,a2,count(a2) from t1 group by a1,a2,b;
explain select a1,a2,count(a2) from t1 where (a1 > 'a') group by a1,a2,b;
explain select sum(ord(a1)) from t1 where (a1 > 'a') group by a1,a2,b;
drop table t1;
drop table t2;
drop table t3;

View File

@ -1538,8 +1538,9 @@ ulonglong ha_myisam::get_auto_increment()
mi_flush_bulk_insert(file, table->next_number_index); mi_flush_bulk_insert(file, table->next_number_index);
(void) extra(HA_EXTRA_KEYREAD); (void) extra(HA_EXTRA_KEYREAD);
key_copy(key,table,table->next_number_index, key_copy(key, table->record[0],
table->next_number_key_offset); table->key_info + table->next_number_index,
table->next_number_key_offset);
error=mi_rkey(file,table->record[1],(int) table->next_number_index, error=mi_rkey(file,table->record[1],(int) table->next_number_index,
key,table->next_number_key_offset,HA_READ_PREFIX_LAST); key,table->next_number_key_offset,HA_READ_PREFIX_LAST);
if (error) if (error)

View File

@ -1125,7 +1125,8 @@ ulonglong handler::get_auto_increment()
else else
{ {
byte key[MAX_KEY_LENGTH]; byte key[MAX_KEY_LENGTH];
key_copy(key,table,table->next_number_index, key_copy(key, table->record[0],
table->key_info + table->next_number_index,
table->next_number_key_offset); table->next_number_key_offset);
error=index_read(table->record[1], key, table->next_number_key_offset, error=index_read(table->record[1], key, table->next_number_key_offset,
HA_READ_PREFIX_LAST); HA_READ_PREFIX_LAST);

View File

@ -170,6 +170,45 @@ bool Item_ident::remove_dependence_processor(byte * arg)
} }
/*
Store the pointer to this item field into a list if not already there.
SYNOPSIS
Item_field::collect_item_field_processor()
arg pointer to a List<Item_field>
DESCRIPTION
The method is used by Item::walk to collect all unique Item_field objects
from a tree of Items into a set of items represented as a list.
IMPLEMENTATION
Item_cond::walk() and Item_func::walk() stop the evaluation of the
processor function for its arguments once the processor returns
true.Therefore in order to force this method being called for all item
arguments in a condition the method must return false.
RETURN
false to force the evaluation of collect_item_field_processor
for the subsequent items.
*/
bool Item_field::collect_item_field_processor(byte *arg)
{
DBUG_ENTER("Item_field::collect_item_field_processor");
DBUG_PRINT("info", ("%s", field->field_name ? field->field_name : "noname"));
List<Item_field> *item_list= (List<Item_field>*) arg;
List_iterator<Item_field> item_list_it(*item_list);
Item_field *curr_item;
while ((curr_item= item_list_it++))
{
if (curr_item->eq(this, 1))
DBUG_RETURN(false); /* Already in the set. */
}
item_list->push_back(this);
DBUG_RETURN(false);
}
bool Item::check_cols(uint c) bool Item::check_cols(uint c)
{ {
if (c != 1) if (c != 1)

View File

@ -263,6 +263,7 @@ public:
virtual bool remove_dependence_processor(byte * arg) { return 0; } virtual bool remove_dependence_processor(byte * arg) { return 0; }
virtual bool remove_fixed(byte * arg) { fixed= 0; return 0; } virtual bool remove_fixed(byte * arg) { fixed= 0; return 0; }
virtual bool collect_item_field_processor(byte * arg) { return 0; }
virtual Item *this_item() { return this; } /* For SPs mostly. */ virtual Item *this_item() { return this; } /* For SPs mostly. */
virtual Item *this_const_item() const { return const_cast<Item*>(this); } /* For SPs mostly. */ virtual Item *this_const_item() const { return const_cast<Item*>(this); } /* For SPs mostly. */
@ -497,6 +498,7 @@ public:
bool get_time(TIME *ltime); bool get_time(TIME *ltime);
bool is_null() { return field->is_null(); } bool is_null() { return field->is_null(); }
Item *get_tmp_table_item(THD *thd); Item *get_tmp_table_item(THD *thd);
bool collect_item_field_processor(byte * arg);
void cleanup(); void cleanup();
inline uint32 max_disp_length() { return field->max_length(); } inline uint32 max_disp_length() { return field->max_length(); }
Item_field *filed_for_view_update() { return this; } Item_field *filed_for_view_update() { return this; }
@ -988,6 +990,8 @@ public:
(*ref)->save_in_field(result_field, no_conversions); (*ref)->save_in_field(result_field, no_conversions);
} }
Item *real_item() { return *ref; } Item *real_item() { return *ref; }
bool walk(Item_processor processor, byte *arg)
{ return (*ref)->walk(processor, arg); }
void print(String *str); void print(String *str);
void cleanup(); void cleanup();
}; };

View File

@ -182,6 +182,7 @@ bool Item_sum::walk (Item_processor processor, byte *argument)
return (this->*processor)(argument); return (this->*processor)(argument);
} }
String * String *
Item_sum_num::val_str(String *str) Item_sum_num::val_str(String *str)
{ {

View File

@ -66,94 +66,121 @@ int find_ref_key(TABLE *table,Field *field, uint *key_length)
} }
/* Copy a key from record to some buffer */ /*
/* if length == 0 then copy whole key */ Copy part of a record that forms a key or key prefix to a buffer.
void key_copy(byte *key,TABLE *table,uint idx,uint key_length) SYNOPSIS
key_copy()
to_key buffer that will be used as a key
from_record full record to be copied from
key_info descriptor of the index
key_length specifies length of all keyparts that will be copied
DESCRIPTION
The function takes a complete table record (as e.g. retrieved by
handler::index_read()), and a description of an index on the same table,
and extracts the first key_length bytes of the record which are part of a
key into to_key. If length == 0 then copy all bytes from the record that
form a key.
RETURN
None
*/
void key_copy(byte *to_key, byte *from_record, KEY *key_info, uint key_length)
{ {
uint length; uint length;
KEY *key_info=table->key_info+idx;
KEY_PART_INFO *key_part; KEY_PART_INFO *key_part;
if (key_length == 0) if (key_length == 0)
key_length=key_info->key_length; key_length= key_info->key_length;
for (key_part=key_info->key_part; for (key_part= key_info->key_part; (int) key_length > 0; key_part++)
(int) key_length > 0 ;
key_part++)
{ {
if (key_part->null_bit) if (key_part->null_bit)
{ {
*key++= test(table->record[0][key_part->null_offset] & *to_key++= test(from_record[key_part->null_offset] &
key_part->null_bit); key_part->null_bit);
key_length--; key_length--;
} }
if (key_part->key_part_flag & HA_BLOB_PART) if (key_part->key_part_flag & HA_BLOB_PART)
{ {
char *pos; char *pos;
ulong blob_length=((Field_blob*) key_part->field)->get_length(); ulong blob_length= ((Field_blob*) key_part->field)->get_length();
key_length-=2; key_length-= 2;
((Field_blob*) key_part->field)->get_ptr(&pos); ((Field_blob*) key_part->field)->get_ptr(&pos);
length=min(key_length,key_part->length); length=min(key_length, key_part->length);
set_if_smaller(blob_length,length); set_if_smaller(blob_length, length);
int2store(key,(uint) blob_length); int2store(to_key, (uint) blob_length);
key+=2; // Skip length info to_key+= 2; // Skip length info
memcpy(key,pos,blob_length); memcpy(to_key, pos, blob_length);
} }
else else
{ {
length=min(key_length,key_part->length); length= min(key_length, key_part->length);
memcpy(key,table->record[0]+key_part->offset,(size_t) length); memcpy(to_key, from_record + key_part->offset, (size_t) length);
} }
key+=length; to_key+= length;
key_length-=length; key_length-= length;
} }
} /* key_copy */ }
/* restore a key from some buffer to record */ /*
Restore a key from some buffer to record.
void key_restore(TABLE *table,byte *key,uint idx,uint key_length) SYNOPSIS
key_restore()
to_record record buffer where the key will be restored to
from_key buffer that contains a key
key_info descriptor of the index
key_length specifies length of all keyparts that will be restored
DESCRIPTION
This function converts a key into record format. It can be used in cases
when we want to return a key as a result row.
RETURN
None
*/
void key_restore(byte *to_record, byte *from_key, KEY *key_info,
uint key_length)
{ {
uint length; uint length;
KEY *key_info=table->key_info+idx;
KEY_PART_INFO *key_part; KEY_PART_INFO *key_part;
if (key_length == 0) if (key_length == 0)
{ {
if (idx == (uint) -1) key_length= key_info->key_length;
return;
key_length=key_info->key_length;
} }
for (key_part=key_info->key_part; for (key_part= key_info->key_part ; (int) key_length > 0 ; key_part++)
(int) key_length > 0 ;
key_part++)
{ {
if (key_part->null_bit) if (key_part->null_bit)
{ {
if (*key++) if (*from_key++)
table->record[0][key_part->null_offset]|= key_part->null_bit; to_record[key_part->null_offset]|= key_part->null_bit;
else else
table->record[0][key_part->null_offset]&= ~key_part->null_bit; to_record[key_part->null_offset]&= ~key_part->null_bit;
key_length--; key_length--;
} }
if (key_part->key_part_flag & HA_BLOB_PART) if (key_part->key_part_flag & HA_BLOB_PART)
{ {
uint blob_length=uint2korr(key); uint blob_length= uint2korr(from_key);
key+=2; from_key+= 2;
key_length-=2; key_length-= 2;
((Field_blob*) key_part->field)->set_ptr((ulong) blob_length, ((Field_blob*) key_part->field)->set_ptr((ulong) blob_length,
(char*) key); (char*) from_key);
length=key_part->length; length= key_part->length;
} }
else else
{ {
length=min(key_length,key_part->length); length= min(key_length, key_part->length);
memcpy(table->record[0]+key_part->offset,key,(size_t) length); memcpy(to_record + key_part->offset, from_key, (size_t) length);
} }
key+=length; from_key+= length;
key_length-=length; key_length-= length;
} }
} /* key_restore */ }
/* /*

View File

@ -763,7 +763,8 @@ bool add_proc_to_list(THD *thd, Item *item);
TABLE *unlink_open_table(THD *thd,TABLE *list,TABLE *find); TABLE *unlink_open_table(THD *thd,TABLE *list,TABLE *find);
SQL_SELECT *make_select(TABLE *head, table_map const_tables, SQL_SELECT *make_select(TABLE *head, table_map const_tables,
table_map read_tables, COND *conds, int *error); table_map read_tables, COND *conds, int *error,
bool allow_null_cond= false);
enum find_item_error_report_type {REPORT_ALL_ERRORS, REPORT_EXCEPT_NOT_FOUND, enum find_item_error_report_type {REPORT_ALL_ERRORS, REPORT_EXCEPT_NOT_FOUND,
IGNORE_ERRORS}; IGNORE_ERRORS};
extern const Item **not_found_item; extern const Item **not_found_item;
@ -861,8 +862,9 @@ void print_plan(JOIN* join, double read_time, double record_count,
void mysql_print_status(THD *thd); void mysql_print_status(THD *thd);
/* key.cc */ /* key.cc */
int find_ref_key(TABLE *form,Field *field, uint *offset); int find_ref_key(TABLE *form,Field *field, uint *offset);
void key_copy(byte *key,TABLE *form,uint index,uint key_length); void key_copy(byte *to_key, byte *from_record, KEY *key_info, uint key_length);
void key_restore(TABLE *form,byte *key,uint index,uint key_length); void key_restore(byte *to_record, byte *from_key, KEY *key_info,
uint key_length);
bool key_cmp_if_same(TABLE *form,const byte *key,uint index,uint key_length); bool key_cmp_if_same(TABLE *form,const byte *key,uint index,uint key_length);
void key_unpack(String *to,TABLE *form,uint index); void key_unpack(String *to,TABLE *form,uint index);
bool check_if_key_used(TABLE *table, uint idx, List<Item> &fields); bool check_if_key_used(TABLE *table, uint idx, List<Item> &fields);

File diff suppressed because it is too large Load Diff

View File

@ -146,7 +146,8 @@ public:
QS_TYPE_RANGE_DESC = 2, QS_TYPE_RANGE_DESC = 2,
QS_TYPE_FULLTEXT = 3, QS_TYPE_FULLTEXT = 3,
QS_TYPE_ROR_INTERSECT = 4, QS_TYPE_ROR_INTERSECT = 4,
QS_TYPE_ROR_UNION = 5 QS_TYPE_ROR_UNION = 5,
QS_TYPE_GROUP_MIN_MAX = 6
}; };
/* Get type of this quick select - one of the QS_TYPE_* values */ /* Get type of this quick select - one of the QS_TYPE_* values */
@ -278,14 +279,12 @@ public:
int init(); int init();
int get_next(); int get_next();
void range_end(); void range_end();
int get_next_prefix(uint prefix_length, byte *cur_prefix);
bool reverse_sorted() { return 0; } bool reverse_sorted() { return 0; }
bool unique_key_range(); bool unique_key_range();
int init_ror_merged_scan(bool reuse_handler); int init_ror_merged_scan(bool reuse_handler);
void save_last_pos() void save_last_pos()
{ { file->position(record); }
file->position(record);
};
int get_type() { return QS_TYPE_RANGE; } int get_type() { return QS_TYPE_RANGE; }
void add_keys_and_lengths(String *key_names, String *used_lengths); void add_keys_and_lengths(String *key_names, String *used_lengths);
void add_info_string(String *str); void add_info_string(String *str);
@ -518,6 +517,103 @@ private:
}; };
/*
Index scan for GROUP-BY queries with MIN/MAX aggregate functions.
This class provides a specialized index access method for GROUP-BY queries
of the forms:
SELECT A_1,...,A_k, [B_1,...,B_m], [MIN(C)], [MAX(C)]
FROM T
WHERE [RNG(A_1,...,A_p ; where p <= k)]
[AND EQ(B_1,...,B_m)]
[AND PC(C)]
[AND PA(A_i1,...,A_iq)]
GROUP BY A_1,...,A_k;
or
SELECT DISTINCT A_i1,...,A_ik
FROM T
WHERE [RNG(A_1,...,A_p ; where p <= k)]
[AND PA(A_i1,...,A_iq)];
where all selected fields are parts of the same index.
The class of queries that can be processed by this quick select is fully
specified in the description of get_best_trp_group_min_max() in opt_range.cc.
The get_next() method directly produces result tuples, thus obviating the
need to call end_send_group() because all grouping is already done inside
get_next().
Since one of the requirements is that all select fields are part of the same
index, this class produces only index keys, and not complete records.
*/
class QUICK_GROUP_MIN_MAX_SELECT : public QUICK_SELECT_I
{
private:
handler *file; /* The handler used to get data. */
JOIN *join; /* Descriptor of the current query */
KEY *index_info; /* The index chosen for data access */
byte *record; /* Buffer where the next record is returned. */
byte *tmp_record; /* Temporary storage for next_min(), next_max(). */
byte *group_prefix; /* Key prefix consisting of the GROUP fields. */
uint group_prefix_len; /* Length of the group prefix. */
byte *last_prefix; /* Prefix of the last group for detecting EOF. */
bool have_min; /* Specify whether we are computing */
bool have_max; /* a MIN, a MAX, or both. */
bool seen_first_key; /* Denotes whether the first key was retrieved.*/
KEY_PART_INFO *min_max_arg_part; /* The keypart of the only argument field */
/* of all MIN/MAX functions. */
uint min_max_arg_len; /* The length of the MIN/MAX argument field */
byte *key_infix; /* Infix of constants from equality predicates. */
uint key_infix_len;
DYNAMIC_ARRAY min_max_ranges; /* Array of range ptrs for the MIN/MAX field. */
uint real_prefix_len; /* Length of key prefix extended with key_infix. */
List<Item_sum> *min_functions;
List<Item_sum> *max_functions;
List_iterator<Item_sum> *min_functions_it;
List_iterator<Item_sum> *max_functions_it;
public:
/*
The following two members are public to allow easy access from
TRP_GROUP_MIN_MAX::make_quick()
*/
MEM_ROOT alloc; /* Memory pool for this and quick_prefix_select data. */
QUICK_RANGE_SELECT *quick_prefix_select;/* For retrieval of group prefixes. */
private:
int next_prefix();
int next_min_in_range();
int next_max_in_range();
int next_min();
int next_max();
void update_min_result();
void update_max_result();
public:
QUICK_GROUP_MIN_MAX_SELECT(TABLE *table, JOIN *join, bool have_min,
bool have_max, KEY_PART_INFO *min_max_arg_part,
uint group_prefix_len, uint used_key_parts,
KEY *index_info, uint use_index, double read_cost,
ha_rows records, uint key_infix_len,
byte *key_infix, MEM_ROOT *parent_alloc);
~QUICK_GROUP_MIN_MAX_SELECT();
bool add_range(SEL_ARG *sel_range);
void update_key_stat();
bool alloc_buffers();
int init();
int reset();
int get_next();
bool reverse_sorted() { return false; }
bool unique_key_range() { return false; }
int get_type() { return QS_TYPE_GROUP_MIN_MAX; }
void add_keys_and_lengths(String *key_names, String *used_lengths);
#ifndef DBUG_OFF
void dbug_dump(int indent, bool verbose);
#endif
};
class QUICK_SELECT_DESC: public QUICK_RANGE_SELECT class QUICK_SELECT_DESC: public QUICK_RANGE_SELECT
{ {
public: public:

View File

@ -336,7 +336,7 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds)
1 Otherwise 1 Otherwise
*/ */
static bool simple_pred(Item_func *func_item, Item **args, bool *inv_order) bool simple_pred(Item_func *func_item, Item **args, bool *inv_order)
{ {
Item *item; Item *item;
*inv_order= 0; *inv_order= 0;

View File

@ -1906,7 +1906,7 @@ GRANT_TABLE::GRANT_TABLE(TABLE *form, TABLE *col_privs)
col_privs->field[1]->pack_length()+ col_privs->field[1]->pack_length()+
col_privs->field[2]->pack_length()+ col_privs->field[2]->pack_length()+
col_privs->field[3]->pack_length()); col_privs->field[3]->pack_length());
key_copy(key,col_privs,0,key_len); key_copy(key,col_privs->record[0],col_privs->key_info,key_len);
col_privs->field[4]->store("",0, &my_charset_latin1); col_privs->field[4]->store("",0, &my_charset_latin1);
col_privs->file->ha_index_init(0); col_privs->file->ha_index_init(0);
if (col_privs->file->index_read(col_privs->record[0], if (col_privs->file->index_read(col_privs->record[0],
@ -2018,7 +2018,7 @@ static int replace_column_table(GRANT_TABLE *g_t,
table->field[3]->store(table_name,(uint) strlen(table_name), &my_charset_latin1); table->field[3]->store(table_name,(uint) strlen(table_name), &my_charset_latin1);
key_length=(table->field[0]->pack_length()+ table->field[1]->pack_length()+ key_length=(table->field[0]->pack_length()+ table->field[1]->pack_length()+
table->field[2]->pack_length()+ table->field[3]->pack_length()); table->field[2]->pack_length()+ table->field[3]->pack_length());
key_copy(key,table,0,key_length); key_copy(key,table->record[0],table->key_info,key_length);
rights &= COL_ACLS; // Only ACL for columns rights &= COL_ACLS; // Only ACL for columns
@ -2031,7 +2031,7 @@ static int replace_column_table(GRANT_TABLE *g_t,
{ {
ulong privileges = xx->rights; ulong privileges = xx->rights;
bool old_row_exists=0; bool old_row_exists=0;
key_restore(table,key,0,key_length); key_restore(table->record[0],key,table->key_info,key_length);
table->field[4]->store(xx->column.ptr(),xx->column.length(), table->field[4]->store(xx->column.ptr(),xx->column.length(),
&my_charset_latin1); &my_charset_latin1);
@ -2047,7 +2047,7 @@ static int replace_column_table(GRANT_TABLE *g_t,
} }
old_row_exists = 0; old_row_exists = 0;
restore_record(table,default_values); // Get empty record restore_record(table,default_values); // Get empty record
key_restore(table,key,0,key_length); key_restore(table->record[0],key,table->key_info,key_length);
table->field[4]->store(xx->column.ptr(),xx->column.length(), table->field[4]->store(xx->column.ptr(),xx->column.length(),
&my_charset_latin1); &my_charset_latin1);
} }

View File

@ -337,7 +337,7 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables,
send_error(thd,ER_OUTOFMEMORY); send_error(thd,ER_OUTOFMEMORY);
goto err; goto err;
} }
key_copy(key, table, keyno, key_len); key_copy(key, table->record[0], table->key_info + keyno, key_len);
err=table->file->index_read(table->record[0], err=table->file->index_read(table->record[0],
key,key_len,ha_rkey_mode); key,key_len,ha_rkey_mode);
mode=rkey_to_rnext[(int)ha_rkey_mode]; mode=rkey_to_rnext[(int)ha_rkey_mode];

View File

@ -719,7 +719,7 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info)
goto err; goto err;
} }
} }
key_copy((byte*) key,table,key_nr,0); key_copy((byte*) key,table->record[0],table->key_info+key_nr,0);
if ((error=(table->file->index_read_idx(table->record[1],key_nr, if ((error=(table->file->index_read_idx(table->record[1],key_nr,
(byte*) key, (byte*) key,
table->key_info[key_nr]. table->key_info[key_nr].

View File

@ -188,6 +188,7 @@ static bool update_sum_func(Item_sum **func);
static void select_describe(JOIN *join, bool need_tmp_table,bool need_order, static void select_describe(JOIN *join, bool need_tmp_table,bool need_order,
bool distinct, const char *message=NullS); bool distinct, const char *message=NullS);
static Item *remove_additional_cond(Item* conds); static Item *remove_additional_cond(Item* conds);
static void add_group_and_distinct_keys(JOIN *join, JOIN_TAB *join_tab);
/* /*
@ -624,7 +625,7 @@ JOIN::optimize()
conds=new Item_int((longlong) 1,1); // Always true conds=new Item_int((longlong) 1,1); // Always true
} }
select=make_select(*table, const_table_map, select=make_select(*table, const_table_map,
const_table_map, conds, &error); const_table_map, conds, &error, true);
if (error) if (error)
{ /* purecov: inspected */ { /* purecov: inspected */
error= -1; /* purecov: inspected */ error= -1; /* purecov: inspected */
@ -1316,7 +1317,7 @@ JOIN::exec()
} }
} }
if (curr_join->make_sum_func_list(*curr_all_fields, *curr_fields_list, if (curr_join->make_sum_func_list(*curr_all_fields, *curr_fields_list,
1) || 1, TRUE) ||
(tmp_error= do_select(curr_join, (List<Item> *) 0, curr_tmp_table, (tmp_error= do_select(curr_join, (List<Item> *) 0, curr_tmp_table,
0))) 0)))
{ {
@ -1404,7 +1405,7 @@ JOIN::exec()
set_items_ref_array(items3); set_items_ref_array(items3);
if (curr_join->make_sum_func_list(*curr_all_fields, *curr_fields_list, if (curr_join->make_sum_func_list(*curr_all_fields, *curr_fields_list,
1) || thd->is_fatal_error) 1, TRUE) || thd->is_fatal_error)
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
if (curr_join->group_list || curr_join->order) if (curr_join->group_list || curr_join->order)
@ -2294,6 +2295,12 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
if (s->worst_seeks < 2.0) // Fix for small tables if (s->worst_seeks < 2.0) // Fix for small tables
s->worst_seeks=2.0; s->worst_seeks=2.0;
/*
Add to stat->const_keys those indexes for which all group fields or
all select distinct fields participate in one index.
*/
add_group_and_distinct_keys(join, s);
if (!s->const_keys.is_clear_all() && if (!s->const_keys.is_clear_all() &&
!s->table->pos_in_table_list->embedding) !s->table->pos_in_table_list->embedding)
{ {
@ -2302,7 +2309,9 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
select= make_select(s->table, found_const_table_map, select= make_select(s->table, found_const_table_map,
found_const_table_map, found_const_table_map,
s->on_expr ? s->on_expr : conds, s->on_expr ? s->on_expr : conds,
&error); &error, true);
if (!select)
DBUG_RETURN(1);
records= get_quick_record_count(join->thd, select, s->table, records= get_quick_record_count(join->thd, select, s->table,
&s->const_keys, join->row_limit); &s->const_keys, join->row_limit);
s->quick=select->quick; s->quick=select->quick;
@ -2337,13 +2346,13 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
} }
} }
/* Find best combination and return it */
join->join_tab=stat; join->join_tab=stat;
join->map2table=stat_ref; join->map2table=stat_ref;
join->table= join->all_tables=table_vector; join->table= join->all_tables=table_vector;
join->const_tables=const_count; join->const_tables=const_count;
join->found_const_table_map=found_const_table_map; join->found_const_table_map=found_const_table_map;
/* Find an optimal join order of the non-constant tables. */
if (join->const_tables != join->tables) if (join->const_tables != join->tables)
{ {
optimize_keyuse(join, keyuse_array); optimize_keyuse(join, keyuse_array);
@ -2355,6 +2364,7 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
sizeof(POSITION)*join->const_tables); sizeof(POSITION)*join->const_tables);
join->best_read=1.0; join->best_read=1.0;
} }
/* Generate an execution plan from the found optimal join order. */
DBUG_RETURN(join->thd->killed || get_best_combination(join)); DBUG_RETURN(join->thd->killed || get_best_combination(join));
} }
@ -2551,6 +2561,10 @@ add_key_field(KEY_FIELD **key_fields,uint and_level, COND *cond,
bool is_const=1; bool is_const=1;
for (uint i=0; i<num_values; i++) for (uint i=0; i<num_values; i++)
/*
TODO: This looks like a bug. It should be
is_const&= (value[i])->const_item();
*/
is_const&= (*value)->const_item(); is_const&= (*value)->const_item();
if (is_const) if (is_const)
stat[0].const_keys.merge(possible_keys); stat[0].const_keys.merge(possible_keys);
@ -2574,7 +2588,7 @@ add_key_field(KEY_FIELD **key_fields,uint and_level, COND *cond,
We can't use indexes if the effective collation We can't use indexes if the effective collation
of the operation differ from the field collation. of the operation differ from the field collation.
We can also not used index on a text column, as the column may We also cannot use index on a text column, as the column may
contain 'x' 'x\t' 'x ' and 'read_next_same' will stop after contain 'x' 'x\t' 'x ' and 'read_next_same' will stop after
'x' when searching for WHERE col='x ' 'x' when searching for WHERE col='x '
*/ */
@ -2997,6 +3011,68 @@ static void optimize_keyuse(JOIN *join, DYNAMIC_ARRAY *keyuse_array)
} }
/*
Discover the indexes that can be used for GROUP BY or DISTINCT queries.
SYNOPSIS
add_group_and_distinct_keys()
join
join_tab
DESCRIPTION
If the query has a GROUP BY clause, find all indexes that contain all
GROUP BY fields, and add those indexes to join->const_keys.
If the query has a DISTINCT clause, find all indexes that contain all
SELECT fields, and add those indexes to join->const_keys.
This allows later on such queries to be processed by a
QUICK_GROUP_MIN_MAX_SELECT.
RETURN
None
*/
static void
add_group_and_distinct_keys(JOIN *join, JOIN_TAB *join_tab)
{
List<Item_field> indexed_fields;
List_iterator<Item_field> indexed_fields_it(indexed_fields);
ORDER *cur_group;
Item_field *cur_item;
key_map possible_keys(0);
if (join->group_list)
{ /* Collect all query fields referenced in the GROUP clause. */
for (cur_group= join->group_list; cur_group; cur_group= cur_group->next)
(*cur_group->item)->walk(&Item::collect_item_field_processor,
(byte*) &indexed_fields);
}
else if (join->select_distinct)
{ /* Collect all query fields referenced in the SELECT clause. */
List<Item> &select_items= join->fields_list;
List_iterator<Item> select_items_it(select_items);
Item *item;
while ((item= select_items_it++))
item->walk(&Item::collect_item_field_processor, (byte*) &indexed_fields);
}
else
return;
if (indexed_fields.elements == 0)
return;
/* Intersect the keys of all group fields. */
cur_item= indexed_fields_it++;
possible_keys.merge(cur_item->field->part_of_key);
while ((cur_item= indexed_fields_it++))
{
possible_keys.intersect(cur_item->field->part_of_key);
}
if (!possible_keys.is_clear_all())
join_tab->const_keys.merge(possible_keys);
}
/***************************************************************************** /*****************************************************************************
Go through all combinations of not marked tables and find the one Go through all combinations of not marked tables and find the one
which uses least records which uses least records
@ -4885,42 +4961,45 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
if (select) if (select)
{ {
table_map used_tables; table_map used_tables;
if (join->tables > 1) if (cond) /* Because of QUICK_GROUP_MIN_MAX_SELECT */
cond->update_used_tables(); // Tablenr may have changed { /* there may be a select without a cond. */
if (join->const_tables == join->tables && if (join->tables > 1)
join->thd->lex->current_select->master_unit() == cond->update_used_tables(); // Tablenr may have changed
&join->thd->lex->unit) // not upper level SELECT if (join->const_tables == join->tables &&
join->const_table_map|=RAND_TABLE_BIT; join->thd->lex->current_select->master_unit() ==
{ // Check const tables &join->thd->lex->unit) // not upper level SELECT
COND *const_cond= join->const_table_map|=RAND_TABLE_BIT;
make_cond_for_table(cond,join->const_table_map,(table_map) 0); { // Check const tables
DBUG_EXECUTE("where",print_where(const_cond,"constants");); COND *const_cond=
for (JOIN_TAB *tab= join->join_tab+join->const_tables; make_cond_for_table(cond,join->const_table_map,(table_map) 0);
tab < join->join_tab+join->tables ; tab++) DBUG_EXECUTE("where",print_where(const_cond,"constants"););
{ for (JOIN_TAB *tab= join->join_tab+join->const_tables;
if (tab->on_expr) tab < join->join_tab+join->tables ; tab++)
{ {
JOIN_TAB *cond_tab= tab->first_inner; if (tab->on_expr)
COND *tmp= make_cond_for_table(tab->on_expr, {
join->const_table_map, JOIN_TAB *cond_tab= tab->first_inner;
(table_map) 0); COND *tmp= make_cond_for_table(tab->on_expr,
if (!tmp) join->const_table_map,
continue; (table_map) 0);
tmp= new Item_func_trig_cond(tmp, &cond_tab->not_null_compl); if (!tmp)
if (!tmp) continue;
DBUG_RETURN(1); tmp= new Item_func_trig_cond(tmp, &cond_tab->not_null_compl);
tmp->quick_fix_field(); if (!tmp)
cond_tab->select_cond= !cond_tab->select_cond ? tmp : DBUG_RETURN(1);
new Item_cond_and(cond_tab->select_cond,tmp); tmp->quick_fix_field();
if (!cond_tab->select_cond) cond_tab->select_cond= !cond_tab->select_cond ? tmp :
DBUG_RETURN(1); new Item_cond_and(cond_tab->select_cond,tmp);
cond_tab->select_cond->quick_fix_field(); if (!cond_tab->select_cond)
} DBUG_RETURN(1);
} cond_tab->select_cond->quick_fix_field();
if (const_cond && !const_cond->val_int()) }
{ }
DBUG_PRINT("info",("Found impossible WHERE condition")); if (const_cond && !const_cond->val_int())
DBUG_RETURN(1); // Impossible const condition {
DBUG_PRINT("info",("Found impossible WHERE condition"));
DBUG_RETURN(1); // Impossible const condition
}
} }
} }
used_tables=((select->const_tables=join->const_table_map) | used_tables=((select->const_tables=join->const_table_map) |
@ -4952,8 +5031,10 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
join->best_positions[i].records_read= rows2double(tab->quick->records); join->best_positions[i].records_read= rows2double(tab->quick->records);
} }
COND *tmp=make_cond_for_table(cond,used_tables,current_map); COND *tmp= NULL;
if (!tmp && tab->quick) if (cond)
tmp= make_cond_for_table(cond,used_tables,current_map);
if (cond && !tmp && tab->quick)
{ // Outer join { // Outer join
if (tab->type != JT_ALL) if (tab->type != JT_ALL)
{ {
@ -4976,7 +5057,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
} }
} }
if (tmp) if (tmp || !cond)
{ {
DBUG_EXECUTE("where",print_where(tmp,tab->table->table_name);); DBUG_EXECUTE("where",print_where(tmp,tab->table->table_name););
SQL_SELECT *sel=tab->select=(SQL_SELECT*) SQL_SELECT *sel=tab->select=(SQL_SELECT*)
@ -4989,9 +5070,17 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
The guard will turn the predicate on only after The guard will turn the predicate on only after
the first match for outer tables is encountered. the first match for outer tables is encountered.
*/ */
if (!(tmp= add_found_match_trig_cond(first_inner_tab, tmp, 0))) if (cond)
DBUG_RETURN(1); {/*
tab->select_cond=sel->cond=tmp; Because of QUICK_GROUP_MIN_MAX_SELECT there may be a select without
a cond, so neutralize the hack above.
*/
if (!(tmp= add_found_match_trig_cond(first_inner_tab, tmp, 0)))
DBUG_RETURN(1);
tab->select_cond=sel->cond=tmp;
}
else
tab->select_cond= sel->cond= NULL;
sel->head=tab->table; sel->head=tab->table;
if (tab->quick) if (tab->quick)
@ -5031,7 +5120,8 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
the index if we are using limit and this is the first table the index if we are using limit and this is the first table
*/ */
if ((!tab->keys.is_subset(tab->const_keys) && i > 0) || if (cond &&
(!tab->keys.is_subset(tab->const_keys) && i > 0) ||
(!tab->const_keys.is_clear_all() && i == join->const_tables && (!tab->const_keys.is_clear_all() && i == join->const_tables &&
join->unit->select_limit_cnt < join->unit->select_limit_cnt <
join->best_positions[i].records_read && join->best_positions[i].records_read &&
@ -5089,7 +5179,8 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
} }
if (i != join->const_tables && tab->use_quick != 2) if (i != join->const_tables && tab->use_quick != 2)
{ /* Read with cache */ { /* Read with cache */
if ((tmp=make_cond_for_table(cond, if (cond &&
(tmp=make_cond_for_table(cond,
join->const_table_map | join->const_table_map |
current_map, current_map,
current_map))) current_map)))
@ -7468,11 +7559,18 @@ do_select(JOIN *join,List<Item> *fields,TABLE *table,Procedure *procedure)
} }
else else
{ {
if (join->sort_and_group || (join->procedure && /* Test if data is accessed via QUICK_GROUP_MIN_MAX_SELECT. */
join->procedure->flags & PROC_GROUP)) bool is_using_quick_group_min_max_select=
end_select=end_send_group; (join->join_tab->select && join->join_tab->select->quick &&
(join->join_tab->select->quick->get_type() ==
QUICK_SELECT_I::QS_TYPE_GROUP_MIN_MAX));
if ((join->sort_and_group ||
(join->procedure && join->procedure->flags & PROC_GROUP)) &&
!is_using_quick_group_min_max_select)
end_select= end_send_group;
else else
end_select=end_send; end_select= end_send;
} }
join->join_tab[join->tables-1].next_select=end_select; join->join_tab[join->tables-1].next_select=end_select;
@ -9264,7 +9362,8 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
& HA_READ_PREV) || & HA_READ_PREV) ||
quick_type == QUICK_SELECT_I::QS_TYPE_INDEX_MERGE || quick_type == QUICK_SELECT_I::QS_TYPE_INDEX_MERGE ||
quick_type == QUICK_SELECT_I::QS_TYPE_ROR_INTERSECT || quick_type == QUICK_SELECT_I::QS_TYPE_ROR_INTERSECT ||
quick_type == QUICK_SELECT_I::QS_TYPE_ROR_UNION) quick_type == QUICK_SELECT_I::QS_TYPE_ROR_UNION ||
quick_type == QUICK_SELECT_I::QS_TYPE_GROUP_MIN_MAX)
DBUG_RETURN(0); // Use filesort DBUG_RETURN(0); // Use filesort
/* ORDER BY range_key DESC */ /* ORDER BY range_key DESC */
@ -10720,6 +10819,7 @@ bool JOIN::alloc_func_list()
field_list All items field_list All items
send_fields Items in select list send_fields Items in select list
before_group_by Set to 1 if this is called before GROUP BY handling before_group_by Set to 1 if this is called before GROUP BY handling
recompute Set to TRUE if sum_funcs must be recomputed
NOTES NOTES
Calls ::setup() for all item_sum objects in field_list Calls ::setup() for all item_sum objects in field_list
@ -10730,13 +10830,16 @@ bool JOIN::alloc_func_list()
*/ */
bool JOIN::make_sum_func_list(List<Item> &field_list, List<Item> &send_fields, bool JOIN::make_sum_func_list(List<Item> &field_list, List<Item> &send_fields,
bool before_group_by) bool before_group_by, bool recompute)
{ {
List_iterator_fast<Item> it(field_list); List_iterator_fast<Item> it(field_list);
Item_sum **func; Item_sum **func;
Item *item; Item *item;
DBUG_ENTER("make_sum_func_list"); DBUG_ENTER("make_sum_func_list");
if (*sum_funcs && !recompute)
DBUG_RETURN(FALSE); /* We have already initialized sum_funcs. */
func= sum_funcs; func= sum_funcs;
while ((item=it++)) while ((item=it++))
{ {
@ -11510,11 +11613,16 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
extra.append(tab->keys.print(buf)); extra.append(tab->keys.print(buf));
extra.append(')'); extra.append(')');
} }
else else if (tab->select->cond)
extra.append("; Using where"); extra.append("; Using where");
} }
if (key_read) if (key_read)
extra.append("; Using index"); {
if (quick_type == QUICK_SELECT_I::QS_TYPE_GROUP_MIN_MAX)
extra.append("; Using index for group-by");
else
extra.append("; Using index");
}
if (table->reginfo.not_exists_optimize) if (table->reginfo.not_exists_optimize)
extra.append("; Not exists"); extra.append("; Not exists");
if (need_tmp_table) if (need_tmp_table)

View File

@ -303,7 +303,7 @@ class JOIN :public Sql_alloc
void restore_tmp(); void restore_tmp();
bool alloc_func_list(); bool alloc_func_list();
bool make_sum_func_list(List<Item> &all_fields, List<Item> &send_fields, bool make_sum_func_list(List<Item> &all_fields, List<Item> &send_fields,
bool before_group_by); bool before_group_by, bool recompute= FALSE);
inline void set_items_ref_array(Item **ptr) inline void set_items_ref_array(Item **ptr)
{ {
@ -399,6 +399,7 @@ bool create_myisam_from_heap(THD *thd, TABLE *table, TMP_TABLE_PARAM *param,
uint find_shortest_key(TABLE *table, const key_map *usable_keys); uint find_shortest_key(TABLE *table, const key_map *usable_keys);
/* functions from opt_sum.cc */ /* functions from opt_sum.cc */
bool simple_pred(Item_func *func_item, Item **args, bool *inv_order);
int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds); int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds);
/* from sql_delete.cc, used by opt_range.cc */ /* from sql_delete.cc, used by opt_range.cc */