1
0
mirror of https://github.com/MariaDB/server.git synced 2025-08-08 11:22:35 +03:00

MWL#121-124 DS-MRR support for key-ordered retrieval, etc

- Merge into 5.3-main
This commit is contained in:
Sergey Petrunya
2010-11-01 18:49:59 +03:00
42 changed files with 2688 additions and 327 deletions

View File

@@ -402,3 +402,33 @@ SELECT * FROM t1 WHERE parent_id IS NOT NULL ORDER BY id DESC LIMIT 1;
id parent_id name
60 40 F
drop table t1;
#
# BUG#628785: multi_range_read.cc:430: int DsMrr_impl::dsmrr_init(): Assertion `do_sort_keys || do_rowid_fetch' failed
#
set @save_join_cache_level= @@join_cache_level;
set @save_optimizer_switch= @@optimizer_switch;
SET SESSION join_cache_level=9;
Warnings:
Warning 1292 Truncated incorrect join_cache_level value: '9'
SET SESSION optimizer_switch='mrr_sort_keys=off';
CREATE TABLE `t1` (
`pk` int(11) NOT NULL AUTO_INCREMENT,
`col_int_nokey` int(11) DEFAULT NULL,
`col_int_key` int(11) DEFAULT NULL,
`col_varchar_key` varchar(1) DEFAULT NULL,
`col_varchar_nokey` varchar(1) DEFAULT NULL,
PRIMARY KEY (`pk`),
KEY `col_varchar_key` (`col_varchar_key`,`col_int_key`)
) ENGINE=InnoDB AUTO_INCREMENT=101 DEFAULT CHARSET=latin1;
INSERT INTO `t1` VALUES (1,6,NULL,'r','r');
INSERT INTO `t1` VALUES (2,8,0,'c','c');
INSERT INTO `t1` VALUES (97,7,0,'z','z');
INSERT INTO `t1` VALUES (98,1,1,'j','j');
INSERT INTO `t1` VALUES (99,7,8,'c','c');
INSERT INTO `t1` VALUES (100,2,5,'f','f');
SELECT table1 .`col_varchar_key`
FROM t1 table1 STRAIGHT_JOIN ( t1 table3 JOIN t1 table4 ON table4 .`pk` = table3 .`col_int_nokey` ) ON table4 .`col_varchar_nokey` ;
col_varchar_key
DROP TABLE t1;
set join_cache_level=@save_join_cache_level;
set optimizer_switch=@save_optimizer_switch;

View File

@@ -0,0 +1,148 @@
drop table if exists t0,t1,t2,t3;
set @save_join_cache_level=@@join_cache_level;
set join_cache_level=6;
set @save_storage_engine=@@storage_engine;
set storage_engine=innodb;
create table t0(a int);
insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
create table t1(a char(8), b char(8), filler char(100), primary key(a));
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` char(8) NOT NULL DEFAULT '',
`b` char(8) DEFAULT NULL,
`filler` char(100) DEFAULT NULL,
PRIMARY KEY (`a`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
insert into t1 select
concat('a-', 1000 + A.a + B.a*10 + C.a*100, '=A'),
concat('b-', 1000 + A.a + B.a*10 + C.a*100, '=B'),
'filler'
from t0 A, t0 B, t0 C;
create table t2 (a char(8));
insert into t2 values ('a-1010=A'), ('a-1030=A'), ('a-1020=A');
This should use join buffer:
explain select * from t1, t2 where t1.a=t2.a;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 ALL NULL NULL NULL NULL 3
1 SIMPLE t1 eq_ref PRIMARY PRIMARY 8 test.t2.a 1 Using join buffer
This output must be sorted by value of t1.a:
select * from t1, t2 where t1.a=t2.a;
a b filler a
a-1010=A b-1010=B filler a-1010=A
a-1020=A b-1020=B filler a-1020=A
a-1030=A b-1030=B filler a-1030=A
drop table t1, t2;
create table t1(
a char(8) character set utf8, b int, filler char(100),
primary key(a,b)
);
insert into t1 select
concat('a-', 1000 + A.a + B.a*10 + C.a*100, '=A'),
1000 + A.a + B.a*10 + C.a*100,
'filler'
from t0 A, t0 B, t0 C;
create table t2 (a char(8) character set utf8, b int);
insert into t2 values ('a-1010=A', 1010), ('a-1030=A', 1030), ('a-1020=A', 1020);
explain select * from t1, t2 where t1.a=t2.a and t1.b=t2.b;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 ALL NULL NULL NULL NULL 3
1 SIMPLE t1 eq_ref PRIMARY PRIMARY 28 test.t2.a,test.t2.b 1 Using join buffer
select * from t1, t2 where t1.a=t2.a and t1.b=t2.b;
a b filler a b
a-1010=A 1010 filler a-1010=A 1010
a-1020=A 1020 filler a-1020=A 1020
a-1030=A 1030 filler a-1030=A 1030
insert into t2 values ('a-1030=A', 1030), ('a-1020=A', 1020);
explain select * from t1, t2 where t1.a=t2.a and t1.b=t2.b;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 ALL NULL NULL NULL NULL 5
1 SIMPLE t1 eq_ref PRIMARY PRIMARY 28 test.t2.a,test.t2.b 1 Using join buffer
select * from t1, t2 where t1.a=t2.a and t1.b=t2.b;
a b filler a b
a-1010=A 1010 filler a-1010=A 1010
a-1020=A 1020 filler a-1020=A 1020
a-1020=A 1020 filler a-1020=A 1020
a-1030=A 1030 filler a-1030=A 1030
a-1030=A 1030 filler a-1030=A 1030
drop table t1, t2;
create table t1(
a varchar(8) character set utf8, b int, filler char(100),
primary key(a,b)
);
insert into t1 select
concat('a-', 1000 + A.a + B.a*10 + C.a*100, '=A'),
1000 + A.a + B.a*10 + C.a*100,
'filler'
from t0 A, t0 B, t0 C;
create table t2 (a char(8) character set utf8, b int);
insert into t2 values ('a-1010=A', 1010), ('a-1030=A', 1030), ('a-1020=A', 1020);
explain select * from t1, t2 where t1.a=t2.a and t1.b=t2.b;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 ALL NULL NULL NULL NULL 3
1 SIMPLE t1 eq_ref PRIMARY PRIMARY 30 test.t2.a,test.t2.b 1 Using index condition(BKA); Using join buffer
select * from t1, t2 where t1.a=t2.a and t1.b=t2.b;
a b filler a b
a-1010=A 1010 filler a-1010=A 1010
a-1020=A 1020 filler a-1020=A 1020
a-1030=A 1030 filler a-1030=A 1030
explain select * from t1, t2 where t1.a=t2.a;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 ALL NULL NULL NULL NULL 3
1 SIMPLE t1 ref PRIMARY PRIMARY 26 test.t2.a 1 Using index condition(BKA); Using join buffer
select * from t1, t2 where t1.a=t2.a;
a b filler a b
a-1010=A 1010 filler a-1010=A 1010
a-1020=A 1020 filler a-1020=A 1020
a-1030=A 1030 filler a-1030=A 1030
drop table t1, t2;
create table t1 (a int, b int, c int, filler char(100), primary key(a,b,c));
insert into t1 select A.a, B.a, C.a, 'filler' from t0 A, t0 B, t0 C;
insert into t1 values (11, 11, 11, 'filler');
insert into t1 values (11, 11, 12, 'filler');
insert into t1 values (11, 11, 13, 'filler');
insert into t1 values (11, 22, 1234, 'filler');
insert into t1 values (11, 33, 124, 'filler');
insert into t1 values (11, 33, 125, 'filler');
create table t2 (a int, b int);
insert into t2 values (11,33), (11,22), (11,11);
explain select * from t1, t2 where t1.a=t2.a and t1.b=t2.b;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 ALL NULL NULL NULL NULL 3
1 SIMPLE t1 ref PRIMARY PRIMARY 8 test.t2.a,test.t2.b 1 Using join buffer
select * from t1, t2 where t1.a=t2.a and t1.b=t2.b;
a b c filler a b
11 11 11 filler 11 11
11 11 12 filler 11 11
11 11 13 filler 11 11
11 22 1234 filler 11 22
11 33 124 filler 11 33
11 33 125 filler 11 33
set join_cache_level=0;
select * from t1, t2 where t1.a=t2.a and t1.b=t2.b;
a b c filler a b
11 33 124 filler 11 33
11 33 125 filler 11 33
11 22 1234 filler 11 22
11 11 11 filler 11 11
11 11 12 filler 11 11
11 11 13 filler 11 11
set join_cache_level=6;
explain select * from t1, t2 where t1.a=t2.a and t2.b + t1.b > 100;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 ALL NULL NULL NULL NULL 3
1 SIMPLE t1 ref PRIMARY PRIMARY 4 test.t2.a 1 Using index condition(BKA); Using join buffer
select * from t1, t2 where t1.a=t2.a and t2.b + t1.b > 100;
a b c filler a b
set optimizer_switch='index_condition_pushdown=off';
explain select * from t1, t2 where t1.a=t2.a and t2.b + t1.b > 100;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 ALL NULL NULL NULL NULL 3
1 SIMPLE t1 ref PRIMARY PRIMARY 4 test.t2.a 1 Using where; Using join buffer
select * from t1, t2 where t1.a=t2.a and t2.b + t1.b > 100;
a b c filler a b
set optimizer_switch='index_condition_pushdown=on';
drop table t1,t2;
set @@join_cache_level= @save_join_cache_level;
set storage_engine=@save_storage_engine;
drop table t0;

View File

@@ -1,4 +1,5 @@
drop table if exists t1,t2,t3,t4;
set @mrr_buffer_size_save= @@mrr_buffer_size;
set @save_storage_engine= @@storage_engine;
set storage_engine=aria;
create table t1(a int);
@@ -292,6 +293,35 @@ NULL 9 0
NULL 9 0
drop table t1, t2;
set storage_engine= @save_storage_engine;
set @@mrr_buffer_size= @mrr_buffer_size_save;
#
# Crash in quick_range_seq_next() in maria-5.3-dsmrr-cpk with join_cache_level = {8,1}
#
set @save_join_cache_level= @@join_cache_level;
SET SESSION join_cache_level = 8;
CREATE TABLE `t1` (
`col_int_key` int(11) DEFAULT NULL,
`col_datetime_key` datetime DEFAULT NULL,
`col_varchar_key` varchar(1) DEFAULT NULL,
`col_varchar_nokey` varchar(1) DEFAULT NULL,
KEY `col_varchar_key` (`col_varchar_key`,`col_int_key`)
) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1;
INSERT INTO `t1` VALUES (6,'2005-10-07 00:00:00','e','e');
INSERT INTO `t1` VALUES (51,'2000-07-15 05:00:34','f','f');
CREATE TABLE `t2` (
`col_int_key` int(11) DEFAULT NULL,
`col_datetime_key` datetime DEFAULT NULL,
`col_varchar_key` varchar(1) DEFAULT NULL,
`col_varchar_nokey` varchar(1) DEFAULT NULL,
KEY `col_varchar_key` (`col_varchar_key`,`col_int_key`)
) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1;
INSERT INTO `t2` VALUES (2,'2004-10-11 18:13:16','w','w');
INSERT INTO `t2` VALUES (2,'1900-01-01 00:00:00','d','d');
SELECT table2 .`col_datetime_key`
FROM t2 JOIN ( t1 table2 JOIN t2 table3 ON table3 .`col_varchar_key` < table2 .`col_varchar_key` ) ON table3 .`col_varchar_nokey` ;
col_datetime_key
drop table t1, t2;
set join_cache_level=@save_join_cache_level;
CREATE TABLE t1(
pk int NOT NULL, i int NOT NULL, v varchar(1) NOT NULL,
PRIMARY KEY (pk), INDEX idx (v, i)

View File

@@ -0,0 +1,294 @@
drop table if exists t1,t2,t3,t4;
set @save_storage_engine= @@storage_engine;
set storage_engine=aria;
create table t1(a int);
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` int(11) DEFAULT NULL
) ENGINE=Aria DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1
insert into t1 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
create table t2(a int);
insert into t2 select A.a + 10*(B.a + 10*C.a) from t1 A, t1 B, t1 C;
create table t3 (
a char(8) not null, b char(8) not null, filler char(200),
key(a)
);
insert into t3 select @a:=concat('c-', 1000+ A.a, '=w'), @a, 'filler' from t2 A;
insert into t3 select concat('c-', 1000+A.a, '=w'), concat('c-', 2000+A.a, '=w'),
'filler-1' from t2 A;
insert into t3 select concat('c-', 1000+A.a, '=w'), concat('c-', 3000+A.a, '=w'),
'filler-2' from t2 A;
select a,filler from t3 where a >= 'c-9011=w';
a filler
select a,filler from t3 where a >= 'c-1011=w' and a <= 'c-1015=w';
a filler
c-1011=w filler
c-1012=w filler
c-1013=w filler
c-1014=w filler
c-1015=w filler
c-1011=w filler-1
c-1012=w filler-1
c-1013=w filler-1
c-1014=w filler-1
c-1015=w filler-1
c-1011=w filler-2
c-1012=w filler-2
c-1013=w filler-2
c-1014=w filler-2
c-1015=w filler-2
select a,filler from t3 where (a>='c-1011=w' and a <= 'c-1013=w') or
(a>='c-1014=w' and a <= 'c-1015=w');
a filler
c-1011=w filler
c-1012=w filler
c-1013=w filler
c-1014=w filler
c-1015=w filler
c-1011=w filler-1
c-1012=w filler-1
c-1013=w filler-1
c-1014=w filler-1
c-1015=w filler-1
c-1011=w filler-2
c-1012=w filler-2
c-1013=w filler-2
c-1014=w filler-2
c-1015=w filler-2
insert into t3 values ('c-1013=z', 'c-1013=z', 'err');
insert into t3 values ('a-1014=w', 'a-1014=w', 'err');
select a,filler from t3 where (a>='c-1011=w' and a <= 'c-1013=w') or
(a>='c-1014=w' and a <= 'c-1015=w');
a filler
c-1011=w filler
c-1012=w filler
c-1013=w filler
c-1014=w filler
c-1015=w filler
c-1011=w filler-1
c-1012=w filler-1
c-1013=w filler-1
c-1014=w filler-1
c-1015=w filler-1
c-1011=w filler-2
c-1012=w filler-2
c-1013=w filler-2
c-1014=w filler-2
c-1015=w filler-2
delete from t3 where b in ('c-1013=z', 'a-1014=w');
select a,filler from t3 where a='c-1011=w' or a='c-1012=w' or a='c-1013=w' or
a='c-1014=w' or a='c-1015=w';
a filler
c-1011=w filler
c-1012=w filler
c-1013=w filler
c-1014=w filler
c-1015=w filler
c-1011=w filler-1
c-1012=w filler-1
c-1013=w filler-1
c-1014=w filler-1
c-1015=w filler-1
c-1011=w filler-2
c-1012=w filler-2
c-1013=w filler-2
c-1014=w filler-2
c-1015=w filler-2
insert into t3 values ('c-1013=w', 'del-me', 'inserted');
select a,filler from t3 where a='c-1011=w' or a='c-1012=w' or a='c-1013=w' or
a='c-1014=w' or a='c-1015=w';
a filler
c-1011=w filler
c-1012=w filler
c-1013=w filler
c-1014=w filler
c-1015=w filler
c-1011=w filler-1
c-1012=w filler-1
c-1013=w filler-1
c-1014=w filler-1
c-1015=w filler-1
c-1011=w filler-2
c-1012=w filler-2
c-1013=w filler-2
c-1014=w filler-2
c-1015=w filler-2
c-1013=w inserted
delete from t3 where b='del-me';
alter table t3 add primary key(b);
select b,filler from t3 where (b>='c-1011=w' and b<= 'c-1018=w') or
b IN ('c-1019=w', 'c-1020=w', 'c-1021=w',
'c-1022=w', 'c-1023=w', 'c-1024=w');
b filler
c-1011=w filler
c-1012=w filler
c-1013=w filler
c-1014=w filler
c-1015=w filler
c-1016=w filler
c-1017=w filler
c-1018=w filler
c-1019=w filler
c-1020=w filler
c-1021=w filler
c-1022=w filler
c-1023=w filler
c-1024=w filler
select b,filler from t3 where (b>='c-1011=w' and b<= 'c-1020=w') or
b IN ('c-1021=w', 'c-1022=w', 'c-1023=w');
b filler
c-1011=w filler
c-1012=w filler
c-1013=w filler
c-1014=w filler
c-1015=w filler
c-1016=w filler
c-1017=w filler
c-1018=w filler
c-1019=w filler
c-1020=w filler
c-1021=w filler
c-1022=w filler
c-1023=w filler
select b,filler from t3 where (b>='c-1011=w' and b<= 'c-1018=w') or
b IN ('c-1019=w', 'c-1020=w') or
(b>='c-1021=w' and b<= 'c-1023=w');
b filler
c-1011=w filler
c-1012=w filler
c-1013=w filler
c-1014=w filler
c-1015=w filler
c-1016=w filler
c-1017=w filler
c-1018=w filler
c-1019=w filler
c-1020=w filler
c-1021=w filler
c-1022=w filler
c-1023=w filler
create table t4 (a varchar(10), b int, c char(10), filler char(200),
key idx1 (a, b, c));
insert into t4 (filler) select concat('NULL-', 15-a) from t2 order by a limit 15;
insert into t4 (a,b,c,filler)
select 'b-1',NULL,'c-1', concat('NULL-', 15-a) from t2 order by a limit 15;
insert into t4 (a,b,c,filler)
select 'b-1',NULL,'c-222', concat('NULL-', 15-a) from t2 order by a limit 15;
insert into t4 (a,b,c,filler)
select 'bb-1',NULL,'cc-2', concat('NULL-', 15-a) from t2 order by a limit 15;
insert into t4 (a,b,c,filler)
select 'zz-1',NULL,'cc-2', 'filler-data' from t2 order by a limit 500;
explain
select * from t4 where a IS NULL and b IS NULL and (c IS NULL or c='no-such-row1'
or c='no-such-row2');
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t4 range idx1 idx1 29 NULL 16 Using index condition; Using MRR
select * from t4 where a IS NULL and b IS NULL and (c IS NULL or c='no-such-row1'
or c='no-such-row2');
a b c filler
NULL NULL NULL NULL-15
NULL NULL NULL NULL-14
NULL NULL NULL NULL-13
NULL NULL NULL NULL-12
NULL NULL NULL NULL-11
NULL NULL NULL NULL-10
NULL NULL NULL NULL-9
NULL NULL NULL NULL-8
NULL NULL NULL NULL-7
NULL NULL NULL NULL-6
NULL NULL NULL NULL-5
NULL NULL NULL NULL-4
NULL NULL NULL NULL-3
NULL NULL NULL NULL-2
NULL NULL NULL NULL-1
explain
select * from t4 where (a ='b-1' or a='bb-1') and b IS NULL and (c='c-1' or c='cc-2');
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t4 range idx1 idx1 29 NULL 32 Using index condition; Using MRR
select * from t4 where (a ='b-1' or a='bb-1') and b IS NULL and (c='c-1' or c='cc-2');
a b c filler
b-1 NULL c-1 NULL-15
b-1 NULL c-1 NULL-14
b-1 NULL c-1 NULL-13
b-1 NULL c-1 NULL-12
b-1 NULL c-1 NULL-11
b-1 NULL c-1 NULL-10
b-1 NULL c-1 NULL-9
b-1 NULL c-1 NULL-8
b-1 NULL c-1 NULL-7
b-1 NULL c-1 NULL-6
b-1 NULL c-1 NULL-5
b-1 NULL c-1 NULL-4
b-1 NULL c-1 NULL-3
b-1 NULL c-1 NULL-2
b-1 NULL c-1 NULL-1
bb-1 NULL cc-2 NULL-15
bb-1 NULL cc-2 NULL-14
bb-1 NULL cc-2 NULL-13
bb-1 NULL cc-2 NULL-12
bb-1 NULL cc-2 NULL-11
bb-1 NULL cc-2 NULL-10
bb-1 NULL cc-2 NULL-9
bb-1 NULL cc-2 NULL-8
bb-1 NULL cc-2 NULL-7
bb-1 NULL cc-2 NULL-6
bb-1 NULL cc-2 NULL-5
bb-1 NULL cc-2 NULL-4
bb-1 NULL cc-2 NULL-3
bb-1 NULL cc-2 NULL-2
bb-1 NULL cc-2 NULL-1
select * from t4 ignore index(idx1) where (a ='b-1' or a='bb-1') and b IS NULL and (c='c-1' or c='cc-2');
a b c filler
b-1 NULL c-1 NULL-15
b-1 NULL c-1 NULL-14
b-1 NULL c-1 NULL-13
b-1 NULL c-1 NULL-12
b-1 NULL c-1 NULL-11
b-1 NULL c-1 NULL-10
b-1 NULL c-1 NULL-9
b-1 NULL c-1 NULL-8
b-1 NULL c-1 NULL-7
b-1 NULL c-1 NULL-6
b-1 NULL c-1 NULL-5
b-1 NULL c-1 NULL-4
b-1 NULL c-1 NULL-3
b-1 NULL c-1 NULL-2
b-1 NULL c-1 NULL-1
bb-1 NULL cc-2 NULL-15
bb-1 NULL cc-2 NULL-14
bb-1 NULL cc-2 NULL-13
bb-1 NULL cc-2 NULL-12
bb-1 NULL cc-2 NULL-11
bb-1 NULL cc-2 NULL-10
bb-1 NULL cc-2 NULL-9
bb-1 NULL cc-2 NULL-8
bb-1 NULL cc-2 NULL-7
bb-1 NULL cc-2 NULL-6
bb-1 NULL cc-2 NULL-5
bb-1 NULL cc-2 NULL-4
bb-1 NULL cc-2 NULL-3
bb-1 NULL cc-2 NULL-2
bb-1 NULL cc-2 NULL-1
drop table t1, t2, t3, t4;
create table t1 (a int, b int not null,unique key (a,b),index(b));
insert ignore into t1 values (1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(null,7),(9,9),(8,8),(7,7),(null,9),(null,9),(6,6);
create table t2 like t1;
insert into t2 select * from t1;
alter table t1 modify b blob not null, add c int not null, drop key a, add unique key (a,b(20),c), drop key b, add key (b(10));
select * from t1 where a is null;
a b c
NULL 7 0
NULL 9 0
NULL 9 0
select * from t1 where (a is null or a > 0 and a < 3) and b > 7 limit 3;
a b c
NULL 9 0
NULL 9 0
select * from t1 where a is null and b=9 or a is null and b=7 limit 3;
a b c
NULL 7 0
NULL 9 0
NULL 9 0
drop table t1, t2;
set storage_engine= @save_storage_engine;

View File

@@ -413,4 +413,52 @@ explain select * from t1 where a < 20;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range a a 5 NULL 20 Using index condition; Using MRR
set optimizer_switch=@save_optimizer_switch;
#
# BUG#629684: Unreachable code in multi_range_read.cc in maria-5.3-dsmrr-cpk
#
delete from t0 where a > 2;
insert into t0 values (NULL),(NULL);
insert into t1 values (NULL, 1234), (NULL, 5678);
set @save_join_cache_level=@@join_cache_level;
set @@join_cache_level=6;
explain
select * from t0, t1 where t0.a<=>t1.a;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t0 ALL NULL NULL NULL NULL 5
1 SIMPLE t1 ref a a 5 test.t0.a 1 Using index condition(BKA); Using join buffer
select * from t0, t1 where t0.a<=>t1.a;
a a b
0 0 0
1 1 1
2 2 2
NULL NULL 1234
NULL NULL 1234
NULL NULL 5678
NULL NULL 5678
set @@join_cache_level=@save_join_cache_level;
drop table t0, t1;
#
# BUG#625841: Assertion `!table || (!table->read_set || bitmap_is_set
# (table->read_set, field_index))' on REPLACE ... SELECT with MRR
#
create table t0 (a int);
insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
create table t1 (
key1 varchar(10),
col1 char(255), col2 char(255),
col3 char(244), col4 char(255),
key(key1)
);
create table t2 like t1;
insert into t1
select
1000+A.a+100*B.a + 10*C.a,
'col1val', 'col2val',
'col3val', 'col4val'
from t0 A, t0 B, t0 C;
REPLACE INTO t2(col2,col3,col4)
SELECT col2,col3,col4
FROM t1
WHERE `key1` LIKE CONCAT( LEFT( '1' , 7 ) , '%' )
ORDER BY col1 LIMIT 7;
drop table t0, t1, t2;

View File

@@ -4,19 +4,19 @@
#
select @@optimizer_switch;
@@optimizer_switch
index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on
index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr_sort_keys=on
set optimizer_switch='index_merge=off,index_merge_union=off';
select @@optimizer_switch;
@@optimizer_switch
index_merge=off,index_merge_union=off,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on
index_merge=off,index_merge_union=off,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr_sort_keys=on
set optimizer_switch='index_merge_union=on';
select @@optimizer_switch;
@@optimizer_switch
index_merge=off,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on
index_merge=off,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr_sort_keys=on
set optimizer_switch='default,index_merge_sort_union=off';
select @@optimizer_switch;
@@optimizer_switch
index_merge=on,index_merge_union=on,index_merge_sort_union=off,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on
index_merge=on,index_merge_union=on,index_merge_sort_union=off,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr_sort_keys=on
set optimizer_switch=4;
ERROR 42000: Variable 'optimizer_switch' can't be set to the value of '4'
set optimizer_switch=NULL;
@@ -43,57 +43,57 @@ set optimizer_switch=default;
set optimizer_switch='index_merge=off,index_merge_union=off,default';
select @@optimizer_switch;
@@optimizer_switch
index_merge=off,index_merge_union=off,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on
index_merge=off,index_merge_union=off,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr_sort_keys=on
set optimizer_switch=default;
select @@global.optimizer_switch;
@@global.optimizer_switch
index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on
index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr_sort_keys=on
set @@global.optimizer_switch=default;
select @@global.optimizer_switch;
@@global.optimizer_switch
index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on
index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr_sort_keys=on
#
# Check index_merge's @@optimizer_switch flags
#
select @@optimizer_switch;
@@optimizer_switch
index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on
index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr_sort_keys=on
BUG#37120 optimizer_switch allowable values not according to specification
select @@optimizer_switch;
@@optimizer_switch
index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on
index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr_sort_keys=on
set optimizer_switch='default,materialization=off';
select @@optimizer_switch;
@@optimizer_switch
index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=off,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on
index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=off,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr_sort_keys=on
set optimizer_switch='default,semijoin=off';
select @@optimizer_switch;
@@optimizer_switch
index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=on,semijoin=off,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on
index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=on,semijoin=off,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr_sort_keys=on
set optimizer_switch='default,loosescan=off';
select @@optimizer_switch;
@@optimizer_switch
index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=off,materialization=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on
index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=off,materialization=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr_sort_keys=on
set optimizer_switch='default,semijoin=off,materialization=off';
select @@optimizer_switch;
@@optimizer_switch
index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=off,semijoin=off,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on
index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=off,semijoin=off,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr_sort_keys=on
set optimizer_switch='default,materialization=off,semijoin=off';
select @@optimizer_switch;
@@optimizer_switch
index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=off,semijoin=off,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on
index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=off,semijoin=off,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr_sort_keys=on
set optimizer_switch='default,semijoin=off,materialization=off,loosescan=off';
select @@optimizer_switch;
@@optimizer_switch
index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=off,materialization=off,semijoin=off,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on
index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=off,materialization=off,semijoin=off,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr_sort_keys=on
set optimizer_switch='default,semijoin=off,loosescan=off';
select @@optimizer_switch;
@@optimizer_switch
index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=off,materialization=on,semijoin=off,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on
index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=off,materialization=on,semijoin=off,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr_sort_keys=on
set optimizer_switch='default,materialization=off,loosescan=off';
select @@optimizer_switch;
@@optimizer_switch
index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=off,materialization=off,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on
index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=off,materialization=off,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr_sort_keys=on
set optimizer_switch=default;

View File

@@ -1489,7 +1489,7 @@ SELECT d FROM t1, t2
WHERE t2.b=14 AND t2.a=t1.a AND 5.1<t2.c AND t1.b='DE'
ORDER BY t2.c LIMIT 1;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref a,b b 4 const 4 Using index condition; Using temporary; Using filesort
1 SIMPLE t1 ref a,b b 4 const 4 Using index condition; Using where; Using temporary; Using filesort
1 SIMPLE t2 ref a,b,c a 40 test.t1.a,const 11 Using index condition
SELECT d FROM t1, t2
WHERE t2.b=14 AND t2.a=t1.a AND 5.1<t2.c AND t1.b='DE'

View File

@@ -3562,19 +3562,19 @@ EXPLAIN SELECT t2.*
FROM t1 JOIN t2 ON t2.fk=t1.pk
WHERE t2.fk < 'c' AND t2.pk=t1.fk;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range PRIMARY PRIMARY 12 NULL 3 Using index condition; Using MRR
1 SIMPLE t1 range PRIMARY PRIMARY 12 NULL 3 Using index condition; Using where; Using MRR
1 SIMPLE t2 eq_ref PRIMARY PRIMARY 18 test.t1.fk 1 Using where
EXPLAIN SELECT t2.*
FROM t1 JOIN t2 ON t2.fk=t1.pk
WHERE t2.fk BETWEEN 'a' AND 'b' AND t2.pk=t1.fk;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range PRIMARY PRIMARY 12 NULL 2 Using index condition; Using MRR
1 SIMPLE t1 range PRIMARY PRIMARY 12 NULL 2 Using index condition; Using where; Using MRR
1 SIMPLE t2 eq_ref PRIMARY PRIMARY 18 test.t1.fk 1 Using where
EXPLAIN SELECT t2.*
FROM t1 JOIN t2 ON t2.fk=t1.pk
WHERE t2.fk IN ('a','b') AND t2.pk=t1.fk;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range PRIMARY PRIMARY 12 NULL 2 Using index condition; Using MRR
1 SIMPLE t1 range PRIMARY PRIMARY 12 NULL 2 Using index condition; Using where; Using MRR
1 SIMPLE t2 eq_ref PRIMARY PRIMARY 18 test.t1.fk 1 Using where
DROP TABLE t1,t2;
CREATE TABLE t1 (a int, b varchar(20) NOT NULL, PRIMARY KEY(a));
@@ -3608,7 +3608,7 @@ WHERE t1.id = 8 AND t2.i BETWEEN t1.b AND t1.e AND
t3.a=t2.a AND t3.c IN ('bb','ee');
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 const PRIMARY PRIMARY 4 const 1
1 SIMPLE t2 range si si 5 NULL 4 Using index condition; Using MRR
1 SIMPLE t2 range si si 5 NULL 4 Using index condition; Using where; Using MRR
1 SIMPLE t3 eq_ref PRIMARY,ci PRIMARY 4 test.t2.a 1 Using where
EXPLAIN
SELECT t3.a FROM t1,t2,t3
@@ -3616,7 +3616,7 @@ WHERE t1.id = 8 AND t2.i BETWEEN t1.b AND t1.e AND
t3.a=t2.a AND t3.c IN ('bb','ee') ;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 const PRIMARY PRIMARY 4 const 1
1 SIMPLE t2 range si,ai si 5 NULL 4 Using index condition; Using MRR
1 SIMPLE t2 range si,ai si 5 NULL 4 Using index condition; Using where; Using MRR
1 SIMPLE t3 eq_ref PRIMARY,ci PRIMARY 4 test.t2.a 1 Using where
EXPLAIN
SELECT t3.a FROM t1,t2 FORCE INDEX (si),t3
@@ -3624,7 +3624,7 @@ WHERE t1.id = 8 AND (t2.i=t1.b OR t2.i=t1.e) AND t3.a=t2.a AND
t3.c IN ('bb','ee');
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 const PRIMARY PRIMARY 4 const 1
1 SIMPLE t2 range si si 5 NULL 2 Using index condition; Using MRR
1 SIMPLE t2 range si si 5 NULL 2 Using index condition; Using where; Using MRR
1 SIMPLE t3 eq_ref PRIMARY,ci PRIMARY 4 test.t2.a 1 Using where
EXPLAIN
SELECT t3.a FROM t1,t2,t3
@@ -3632,7 +3632,7 @@ WHERE t1.id = 8 AND (t2.i=t1.b OR t2.i=t1.e) AND t3.a=t2.a AND
t3.c IN ('bb','ee');
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 const PRIMARY PRIMARY 4 const 1
1 SIMPLE t2 range si,ai si 5 NULL 2 Using index condition; Using MRR
1 SIMPLE t2 range si,ai si 5 NULL 2 Using index condition; Using where; Using MRR
1 SIMPLE t3 eq_ref PRIMARY,ci PRIMARY 4 test.t2.a 1 Using where
DROP TABLE t1,t2,t3;
CREATE TABLE t1 ( f1 int primary key, f2 int, f3 int, f4 int, f5 int, f6 int, checked_out int);

View File

@@ -3566,19 +3566,19 @@ EXPLAIN SELECT t2.*
FROM t1 JOIN t2 ON t2.fk=t1.pk
WHERE t2.fk < 'c' AND t2.pk=t1.fk;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range PRIMARY PRIMARY 12 NULL 3 Using index condition; Using MRR
1 SIMPLE t1 range PRIMARY PRIMARY 12 NULL 3 Using index condition; Using where; Using MRR
1 SIMPLE t2 eq_ref PRIMARY PRIMARY 18 test.t1.fk 1 Using where; Using join buffer
EXPLAIN SELECT t2.*
FROM t1 JOIN t2 ON t2.fk=t1.pk
WHERE t2.fk BETWEEN 'a' AND 'b' AND t2.pk=t1.fk;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range PRIMARY PRIMARY 12 NULL 2 Using index condition; Using MRR
1 SIMPLE t1 range PRIMARY PRIMARY 12 NULL 2 Using index condition; Using where; Using MRR
1 SIMPLE t2 eq_ref PRIMARY PRIMARY 18 test.t1.fk 1 Using where; Using join buffer
EXPLAIN SELECT t2.*
FROM t1 JOIN t2 ON t2.fk=t1.pk
WHERE t2.fk IN ('a','b') AND t2.pk=t1.fk;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range PRIMARY PRIMARY 12 NULL 2 Using index condition; Using MRR
1 SIMPLE t1 range PRIMARY PRIMARY 12 NULL 2 Using index condition; Using where; Using MRR
1 SIMPLE t2 eq_ref PRIMARY PRIMARY 18 test.t1.fk 1 Using where; Using join buffer
DROP TABLE t1,t2;
CREATE TABLE t1 (a int, b varchar(20) NOT NULL, PRIMARY KEY(a));
@@ -3612,7 +3612,7 @@ WHERE t1.id = 8 AND t2.i BETWEEN t1.b AND t1.e AND
t3.a=t2.a AND t3.c IN ('bb','ee');
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 const PRIMARY PRIMARY 4 const 1
1 SIMPLE t2 range si si 5 NULL 4 Using index condition; Using MRR
1 SIMPLE t2 range si si 5 NULL 4 Using index condition; Using where; Using MRR
1 SIMPLE t3 eq_ref PRIMARY,ci PRIMARY 4 test.t2.a 1 Using where; Using join buffer
EXPLAIN
SELECT t3.a FROM t1,t2,t3
@@ -3620,7 +3620,7 @@ WHERE t1.id = 8 AND t2.i BETWEEN t1.b AND t1.e AND
t3.a=t2.a AND t3.c IN ('bb','ee') ;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 const PRIMARY PRIMARY 4 const 1
1 SIMPLE t2 range si,ai si 5 NULL 4 Using index condition; Using MRR
1 SIMPLE t2 range si,ai si 5 NULL 4 Using index condition; Using where; Using MRR
1 SIMPLE t3 eq_ref PRIMARY,ci PRIMARY 4 test.t2.a 1 Using where; Using join buffer
EXPLAIN
SELECT t3.a FROM t1,t2 FORCE INDEX (si),t3
@@ -3628,7 +3628,7 @@ WHERE t1.id = 8 AND (t2.i=t1.b OR t2.i=t1.e) AND t3.a=t2.a AND
t3.c IN ('bb','ee');
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 const PRIMARY PRIMARY 4 const 1
1 SIMPLE t2 range si si 5 NULL 2 Using index condition; Using MRR
1 SIMPLE t2 range si si 5 NULL 2 Using index condition; Using where; Using MRR
1 SIMPLE t3 eq_ref PRIMARY,ci PRIMARY 4 test.t2.a 1 Using where; Using join buffer
EXPLAIN
SELECT t3.a FROM t1,t2,t3
@@ -3636,7 +3636,7 @@ WHERE t1.id = 8 AND (t2.i=t1.b OR t2.i=t1.e) AND t3.a=t2.a AND
t3.c IN ('bb','ee');
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 const PRIMARY PRIMARY 4 const 1
1 SIMPLE t2 range si,ai si 5 NULL 2 Using index condition; Using MRR
1 SIMPLE t2 range si,ai si 5 NULL 2 Using index condition; Using where; Using MRR
1 SIMPLE t3 eq_ref PRIMARY,ci PRIMARY 4 test.t2.a 1 Using where; Using join buffer
DROP TABLE t1,t2,t3;
CREATE TABLE t1 ( f1 int primary key, f2 int, f3 int, f4 int, f5 int, f6 int, checked_out int);

View File

@@ -3562,19 +3562,19 @@ EXPLAIN SELECT t2.*
FROM t1 JOIN t2 ON t2.fk=t1.pk
WHERE t2.fk < 'c' AND t2.pk=t1.fk;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range PRIMARY PRIMARY 12 NULL 3 Using index condition; Using MRR
1 SIMPLE t1 range PRIMARY PRIMARY 12 NULL 3 Using index condition; Using where; Using MRR
1 SIMPLE t2 eq_ref PRIMARY PRIMARY 18 test.t1.fk 1 Using where
EXPLAIN SELECT t2.*
FROM t1 JOIN t2 ON t2.fk=t1.pk
WHERE t2.fk BETWEEN 'a' AND 'b' AND t2.pk=t1.fk;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range PRIMARY PRIMARY 12 NULL 2 Using index condition; Using MRR
1 SIMPLE t1 range PRIMARY PRIMARY 12 NULL 2 Using index condition; Using where; Using MRR
1 SIMPLE t2 eq_ref PRIMARY PRIMARY 18 test.t1.fk 1 Using where
EXPLAIN SELECT t2.*
FROM t1 JOIN t2 ON t2.fk=t1.pk
WHERE t2.fk IN ('a','b') AND t2.pk=t1.fk;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range PRIMARY PRIMARY 12 NULL 2 Using index condition; Using MRR
1 SIMPLE t1 range PRIMARY PRIMARY 12 NULL 2 Using index condition; Using where; Using MRR
1 SIMPLE t2 eq_ref PRIMARY PRIMARY 18 test.t1.fk 1 Using where
DROP TABLE t1,t2;
CREATE TABLE t1 (a int, b varchar(20) NOT NULL, PRIMARY KEY(a));
@@ -3608,7 +3608,7 @@ WHERE t1.id = 8 AND t2.i BETWEEN t1.b AND t1.e AND
t3.a=t2.a AND t3.c IN ('bb','ee');
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 const PRIMARY PRIMARY 4 const 1
1 SIMPLE t2 range si si 5 NULL 4 Using index condition; Using MRR
1 SIMPLE t2 range si si 5 NULL 4 Using index condition; Using where; Using MRR
1 SIMPLE t3 eq_ref PRIMARY,ci PRIMARY 4 test.t2.a 1 Using where
EXPLAIN
SELECT t3.a FROM t1,t2,t3
@@ -3616,7 +3616,7 @@ WHERE t1.id = 8 AND t2.i BETWEEN t1.b AND t1.e AND
t3.a=t2.a AND t3.c IN ('bb','ee') ;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 const PRIMARY PRIMARY 4 const 1
1 SIMPLE t2 range si,ai si 5 NULL 4 Using index condition; Using MRR
1 SIMPLE t2 range si,ai si 5 NULL 4 Using index condition; Using where; Using MRR
1 SIMPLE t3 eq_ref PRIMARY,ci PRIMARY 4 test.t2.a 1 Using where
EXPLAIN
SELECT t3.a FROM t1,t2 FORCE INDEX (si),t3
@@ -3624,7 +3624,7 @@ WHERE t1.id = 8 AND (t2.i=t1.b OR t2.i=t1.e) AND t3.a=t2.a AND
t3.c IN ('bb','ee');
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 const PRIMARY PRIMARY 4 const 1
1 SIMPLE t2 range si si 5 NULL 2 Using index condition; Using MRR
1 SIMPLE t2 range si si 5 NULL 2 Using index condition; Using where; Using MRR
1 SIMPLE t3 eq_ref PRIMARY,ci PRIMARY 4 test.t2.a 1 Using where
EXPLAIN
SELECT t3.a FROM t1,t2,t3
@@ -3632,7 +3632,7 @@ WHERE t1.id = 8 AND (t2.i=t1.b OR t2.i=t1.e) AND t3.a=t2.a AND
t3.c IN ('bb','ee');
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 const PRIMARY PRIMARY 4 const 1
1 SIMPLE t2 range si,ai si 5 NULL 2 Using index condition; Using MRR
1 SIMPLE t2 range si,ai si 5 NULL 2 Using index condition; Using where; Using MRR
1 SIMPLE t3 eq_ref PRIMARY,ci PRIMARY 4 test.t2.a 1 Using where
DROP TABLE t1,t2,t3;
CREATE TABLE t1 ( f1 int primary key, f2 int, f3 int, f4 int, f5 int, f6 int, checked_out int);

View File

@@ -1130,7 +1130,7 @@ insert into t4 select a from t3;
explain select * from t3 where a in (select t1.kp1 from t1,t4 where kp1<20
and t4.pk=t1.c);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 range kp1 kp1 5 NULL 48 Using index condition; Using MRR; LooseScan
1 PRIMARY t1 range kp1 kp1 5 NULL 48 Using index condition; Using where; Using MRR; LooseScan
1 PRIMARY t4 eq_ref PRIMARY PRIMARY 4 test.t1.c 1 Using index; FirstMatch(t1)
1 PRIMARY t3 ALL NULL NULL NULL NULL 100 Using where; Using join buffer
drop table t1, t3, t4;

View File

@@ -1135,7 +1135,7 @@ insert into t4 select a from t3;
explain select * from t3 where a in (select t1.kp1 from t1,t4 where kp1<20
and t4.pk=t1.c);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 range kp1 kp1 5 NULL 48 Using index condition; Using MRR; LooseScan
1 PRIMARY t1 range kp1 kp1 5 NULL 48 Using index condition; Using where; Using MRR; LooseScan
1 PRIMARY t4 eq_ref PRIMARY PRIMARY 4 test.t1.c 1 Using index; FirstMatch(t1)
1 PRIMARY t3 ALL NULL NULL NULL NULL 100 Using where; Using join buffer
drop table t1, t3, t4;

View File

@@ -128,7 +128,7 @@ Note 1003 select `f`.`id` AS `id` from `test`.`t0` `f` where (`f`.`id` in (1,2,3
This should use facts and a1 tables:
explain extended select id from v1 where attr1 between 12 and 14;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY a1 range PRIMARY,attr1 attr1 5 NULL 2 100.00 Using index condition; Using MRR
1 PRIMARY a1 range PRIMARY,attr1 attr1 5 NULL 2 100.00 Using index condition; Using where; Using MRR
1 PRIMARY f eq_ref PRIMARY PRIMARY 4 test.a1.id 1 100.00 Using index
Warnings:
Note 1276 Field or reference 'test.a2.id' of SELECT #3 was resolved in SELECT #1
@@ -156,7 +156,7 @@ Note 1003 select `f`.`id` AS `id` from `test`.`t0` `f` where (`f`.`id` in (1,2,3
This should use facts and a1 tables:
explain extended select id from v2 where attr1 between 12 and 14;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY a1 range PRIMARY,attr1 attr1 5 NULL 2 100.00 Using index condition; Using MRR
1 PRIMARY a1 range PRIMARY,attr1 attr1 5 NULL 2 100.00 Using index condition; Using where; Using MRR
1 PRIMARY f eq_ref PRIMARY PRIMARY 4 test.a1.id 1 100.00 Using index
Warnings:
Note 1276 Field or reference 'test.f.id' of SELECT #3 was resolved in SELECT #1
@@ -164,7 +164,7 @@ Note 1003 select `f`.`id` AS `id` from `test`.`t0` `f` join `test`.`t1` `a1` whe
This should use facts, a2 and its subquery:
explain extended select id from v2 where attr2 between 12 and 14;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY a2 range PRIMARY,attr2 attr2 5 NULL 5 100.00 Using index condition; Using MRR
1 PRIMARY a2 range PRIMARY,attr2 attr2 5 NULL 5 100.00 Using index condition; Using where; Using MRR
1 PRIMARY f eq_ref PRIMARY PRIMARY 4 test.a2.id 1 100.00 Using where; Using index
3 DEPENDENT SUBQUERY t2 ref PRIMARY PRIMARY 4 test.f.id 2 100.00 Using index
Warnings:

View File

@@ -13,8 +13,8 @@ id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 ref idx idx 5 test.t1.b 2 Using where; Using join buffer
select * from t1,t2 where t1.b=t2.c and d <= 100;
a b c d v
4 20 20 100 101
1 20 20 100 101
3 30 30 100 101
4 20 20 100 101
set join_cache_level=default;
drop table t1, t2;

View File

@@ -17,6 +17,7 @@ set join_cache_level=6;
explain
select * from t1,t2 where t1.b=t2.c and d <= 100;
--sorted_result
select * from t1,t2 where t1.b=t2.c and d <= 100;
set join_cache_level=default;

View File

@@ -123,3 +123,34 @@ SELECT id FROM t1 WHERE parent_id IS NOT NULL ORDER BY id DESC LIMIT 1;
explain SELECT * FROM t1 FORCE INDEX (PRIMARY) WHERE parent_id IS NOT NULL ORDER BY id DESC LIMIT 1;
SELECT * FROM t1 WHERE parent_id IS NOT NULL ORDER BY id DESC LIMIT 1;
drop table t1;
-- echo #
-- echo # BUG#628785: multi_range_read.cc:430: int DsMrr_impl::dsmrr_init(): Assertion `do_sort_keys || do_rowid_fetch' failed
-- echo #
set @save_join_cache_level= @@join_cache_level;
set @save_optimizer_switch= @@optimizer_switch;
SET SESSION join_cache_level=9;
SET SESSION optimizer_switch='mrr_sort_keys=off';
CREATE TABLE `t1` (
`pk` int(11) NOT NULL AUTO_INCREMENT,
`col_int_nokey` int(11) DEFAULT NULL,
`col_int_key` int(11) DEFAULT NULL,
`col_varchar_key` varchar(1) DEFAULT NULL,
`col_varchar_nokey` varchar(1) DEFAULT NULL,
PRIMARY KEY (`pk`),
KEY `col_varchar_key` (`col_varchar_key`,`col_int_key`)
) ENGINE=InnoDB AUTO_INCREMENT=101 DEFAULT CHARSET=latin1;
INSERT INTO `t1` VALUES (1,6,NULL,'r','r');
INSERT INTO `t1` VALUES (2,8,0,'c','c');
INSERT INTO `t1` VALUES (97,7,0,'z','z');
INSERT INTO `t1` VALUES (98,1,1,'j','j');
INSERT INTO `t1` VALUES (99,7,8,'c','c');
INSERT INTO `t1` VALUES (100,2,5,'f','f');
SELECT table1 .`col_varchar_key`
FROM t1 table1 STRAIGHT_JOIN ( t1 table3 JOIN t1 table4 ON table4 .`pk` = table3 .`col_int_nokey` ) ON table4 .`col_varchar_nokey` ;
DROP TABLE t1;
set join_cache_level=@save_join_cache_level;
set optimizer_switch=@save_optimizer_switch;

View File

@@ -0,0 +1,137 @@
#
# Tests for DS-MRR over clustered primary key. The only engine that supports
# this is InnoDB/XtraDB.
#
# Basic idea about testing
# - DS-MRR/CPK works only with BKA
# - Should also test index condition pushdown
# - Should also test whatever uses RANGE_SEQ_IF::skip_record() for filtering
# - Also test access using prefix of primary key
#
# - Forget about cost model, BKA's multi_range_read_info() call passes 10 for
# #rows, the call is there at all only for applicability check
#
-- source include/have_innodb.inc
--disable_warnings
drop table if exists t0,t1,t2,t3;
--enable_warnings
set @save_join_cache_level=@@join_cache_level;
set join_cache_level=6;
set @save_storage_engine=@@storage_engine;
set storage_engine=innodb;
create table t0(a int);
insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
create table t1(a char(8), b char(8), filler char(100), primary key(a));
show create table t1;
insert into t1 select
concat('a-', 1000 + A.a + B.a*10 + C.a*100, '=A'),
concat('b-', 1000 + A.a + B.a*10 + C.a*100, '=B'),
'filler'
from t0 A, t0 B, t0 C;
create table t2 (a char(8));
insert into t2 values ('a-1010=A'), ('a-1030=A'), ('a-1020=A');
--echo This should use join buffer:
explain select * from t1, t2 where t1.a=t2.a;
--echo This output must be sorted by value of t1.a:
select * from t1, t2 where t1.a=t2.a;
drop table t1, t2;
# Try multi-column indexes
create table t1(
a char(8) character set utf8, b int, filler char(100),
primary key(a,b)
);
insert into t1 select
concat('a-', 1000 + A.a + B.a*10 + C.a*100, '=A'),
1000 + A.a + B.a*10 + C.a*100,
'filler'
from t0 A, t0 B, t0 C;
create table t2 (a char(8) character set utf8, b int);
insert into t2 values ('a-1010=A', 1010), ('a-1030=A', 1030), ('a-1020=A', 1020);
explain select * from t1, t2 where t1.a=t2.a and t1.b=t2.b;
select * from t1, t2 where t1.a=t2.a and t1.b=t2.b;
# Try with dataset that causes identical lookup keys:
insert into t2 values ('a-1030=A', 1030), ('a-1020=A', 1020);
explain select * from t1, t2 where t1.a=t2.a and t1.b=t2.b;
select * from t1, t2 where t1.a=t2.a and t1.b=t2.b;
drop table t1, t2;
create table t1(
a varchar(8) character set utf8, b int, filler char(100),
primary key(a,b)
);
insert into t1 select
concat('a-', 1000 + A.a + B.a*10 + C.a*100, '=A'),
1000 + A.a + B.a*10 + C.a*100,
'filler'
from t0 A, t0 B, t0 C;
create table t2 (a char(8) character set utf8, b int);
insert into t2 values ('a-1010=A', 1010), ('a-1030=A', 1030), ('a-1020=A', 1020);
explain select * from t1, t2 where t1.a=t2.a and t1.b=t2.b;
select * from t1, t2 where t1.a=t2.a and t1.b=t2.b;
#
# Try scanning on a CPK prefix
#
explain select * from t1, t2 where t1.a=t2.a;
select * from t1, t2 where t1.a=t2.a;
drop table t1, t2;
#
# The above example is not very interesting, as CPK prefix has
# only one match. Create a dataset where scan on CPK prefix
# would produce multiple matches:
#
create table t1 (a int, b int, c int, filler char(100), primary key(a,b,c));
insert into t1 select A.a, B.a, C.a, 'filler' from t0 A, t0 B, t0 C;
insert into t1 values (11, 11, 11, 'filler');
insert into t1 values (11, 11, 12, 'filler');
insert into t1 values (11, 11, 13, 'filler');
insert into t1 values (11, 22, 1234, 'filler');
insert into t1 values (11, 33, 124, 'filler');
insert into t1 values (11, 33, 125, 'filler');
create table t2 (a int, b int);
insert into t2 values (11,33), (11,22), (11,11);
explain select * from t1, t2 where t1.a=t2.a and t1.b=t2.b;
select * from t1, t2 where t1.a=t2.a and t1.b=t2.b;
# Check a real resultset for comaprison:
set join_cache_level=0;
select * from t1, t2 where t1.a=t2.a and t1.b=t2.b;
set join_cache_level=6;
#
# Check that Index Condition Pushdown (BKA) actually works:
#
explain select * from t1, t2 where t1.a=t2.a and t2.b + t1.b > 100;
select * from t1, t2 where t1.a=t2.a and t2.b + t1.b > 100;
set optimizer_switch='index_condition_pushdown=off';
explain select * from t1, t2 where t1.a=t2.a and t2.b + t1.b > 100;
select * from t1, t2 where t1.a=t2.a and t2.b + t1.b > 100;
set optimizer_switch='index_condition_pushdown=on';
drop table t1,t2;
set @@join_cache_level= @save_join_cache_level;
set storage_engine=@save_storage_engine;
drop table t0;

View File

@@ -462,7 +462,6 @@ SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b
LEFT JOIN
(t1,t2)
ON t3.a=1 AND t3.b=t2.b AND t2.b=t4.b;
SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b
FROM (t3,t4)
LEFT JOIN

View File

@@ -1,16 +1,51 @@
-- source include/have_maria.inc
#
# MRR/Maria tests.
#
--disable_warnings
drop table if exists t1,t2,t3,t4;
--enable_warnings
set @mrr_buffer_size_save= @@mrr_buffer_size;
set @save_storage_engine= @@storage_engine;
set storage_engine=aria;
--source include/mrr_tests.inc
set storage_engine= @save_storage_engine;
set @@mrr_buffer_size= @mrr_buffer_size_save;
--echo #
--echo # Crash in quick_range_seq_next() in maria-5.3-dsmrr-cpk with join_cache_level = {8,1}
--echo #
set @save_join_cache_level= @@join_cache_level;
SET SESSION join_cache_level = 8;
CREATE TABLE `t1` (
`col_int_key` int(11) DEFAULT NULL,
`col_datetime_key` datetime DEFAULT NULL,
`col_varchar_key` varchar(1) DEFAULT NULL,
`col_varchar_nokey` varchar(1) DEFAULT NULL,
KEY `col_varchar_key` (`col_varchar_key`,`col_int_key`)
) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1;
INSERT INTO `t1` VALUES (6,'2005-10-07 00:00:00','e','e');
INSERT INTO `t1` VALUES (51,'2000-07-15 05:00:34','f','f');
CREATE TABLE `t2` (
`col_int_key` int(11) DEFAULT NULL,
`col_datetime_key` datetime DEFAULT NULL,
`col_varchar_key` varchar(1) DEFAULT NULL,
`col_varchar_nokey` varchar(1) DEFAULT NULL,
KEY `col_varchar_key` (`col_varchar_key`,`col_int_key`)
) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1;
INSERT INTO `t2` VALUES (2,'2004-10-11 18:13:16','w','w');
INSERT INTO `t2` VALUES (2,'1900-01-01 00:00:00','d','d');
SELECT table2 .`col_datetime_key`
FROM t2 JOIN ( t1 table2 JOIN t2 table3 ON table3 .`col_varchar_key` < table2 .`col_varchar_key` ) ON table3 .`col_varchar_nokey` ;
drop table t1, t2;
set join_cache_level=@save_join_cache_level;
#
# Bug #665049: index condition pushdown with Maria
#
@@ -55,3 +90,4 @@ DROP TABLE t1,t2,t3;

View File

@@ -0,0 +1,13 @@
-- source include/have_maria.inc
--disable_warnings
drop table if exists t1,t2,t3,t4;
--enable_warnings
set @save_storage_engine= @@storage_engine;
set storage_engine=aria;
--source include/mrr_tests.inc
set storage_engine= @save_storage_engine;

View File

@@ -123,4 +123,49 @@ explain select * from t1 where a < 20;
set optimizer_switch=@save_optimizer_switch;
--echo #
--echo # BUG#629684: Unreachable code in multi_range_read.cc in maria-5.3-dsmrr-cpk
--echo #
delete from t0 where a > 2;
insert into t0 values (NULL),(NULL);
insert into t1 values (NULL, 1234), (NULL, 5678);
set @save_join_cache_level=@@join_cache_level;
set @@join_cache_level=6;
explain
select * from t0, t1 where t0.a<=>t1.a;
select * from t0, t1 where t0.a<=>t1.a;
set @@join_cache_level=@save_join_cache_level;
drop table t0, t1;
--echo #
--echo # BUG#625841: Assertion `!table || (!table->read_set || bitmap_is_set
--echo # (table->read_set, field_index))' on REPLACE ... SELECT with MRR
--echo #
create table t0 (a int);
insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
create table t1 (
key1 varchar(10),
col1 char(255), col2 char(255),
col3 char(244), col4 char(255),
key(key1)
);
create table t2 like t1;
insert into t1
select
1000+A.a+100*B.a + 10*C.a,
'col1val', 'col2val',
'col3val', 'col4val'
from t0 A, t0 B, t0 C;
REPLACE INTO t2(col2,col3,col4)
SELECT col2,col3,col4
FROM t1
WHERE `key1` LIKE CONCAT( LEFT( '1' , 7 ) , '%' )
ORDER BY col1 LIMIT 7;
drop table t0, t1, t2;

View File

@@ -586,6 +586,7 @@ if (`select @@join_cache_level=6`)
--echo # Not anymore:
--echo # The following query gives wrong result due to Bug#49129
}
select * from t0 where t0.a in
(select t1.a from t1, t2 where t2.a=t0.a and t1.b=t2.b);

View File

@@ -63,6 +63,7 @@ SET (SQL_SOURCE
sql_cache.cc sql_class.cc sql_client.cc sql_crypt.cc sql_crypt.h
sql_cursor.cc sql_db.cc sql_delete.cc sql_derived.cc sql_do.cc
sql_error.cc sql_handler.cc sql_help.cc sql_insert.cc
sql_lifo_buffer.h
sql_join_cache.cc sql_lex.cc sql_list.cc sql_load.cc sql_manager.cc
sql_map.cc sql_parse.cc sql_partition.cc sql_plugin.cc
sql_prepare.cc sql_rename.cc

View File

@@ -66,6 +66,7 @@ noinst_HEADERS = item.h item_func.h item_sum.h item_cmpfunc.h \
log.h log_slow.h sql_show.h rpl_rli.h rpl_mi.h \
sql_select.h structs.h table.h sql_udf.h hash_filo.h \
lex.h lex_symbol.h sql_acl.h sql_crypt.h \
sql_lifo_buffer.h \
sql_repl.h slave.h rpl_filter.h rpl_injector.h \
log_event.h rpl_record.h \
log_event_old.h rpl_record_old.h \

View File

@@ -543,11 +543,6 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select,
current_thd->variables.read_buff_size);
}
if (quick_select)
{
if (select->quick->reset())
DBUG_RETURN(HA_POS_ERROR);
}
/* Remember original bitmaps */
save_read_set= sort_form->read_set;
@@ -561,9 +556,19 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select,
if (select && select->cond)
select->cond->walk(&Item::register_field_in_read_map, 1,
(uchar*) sort_form);
if (select && select->pre_idx_push_select_cond)
select->pre_idx_push_select_cond->walk(&Item::register_field_in_read_map,
1, (uchar*) sort_form);
sort_form->column_bitmaps_set(&sort_form->tmp_set, &sort_form->tmp_set,
&sort_form->tmp_set);
if (quick_select)
{
if (select->quick->reset())
DBUG_RETURN(HA_POS_ERROR);
}
for (;;)
{
if (quick_select)

View File

@@ -1281,9 +1281,9 @@ void get_sweep_read_cost(TABLE *table, ha_rows nrows, bool interrupted,
COST_VECT *cost);
/*
The below two are not used (and not handled) in this milestone of this WL
entry because there seems to be no use for them at this stage of
implementation.
Indicates that all scanned ranges will be singlepoint (aka equality) ranges.
The ranges may not use the full key but all of them will use the same number
of key parts.
*/
#define HA_MRR_SINGLE_POINT 1
#define HA_MRR_FIXED_KEY 2
@@ -1325,6 +1325,16 @@ void get_sweep_read_cost(TABLE *table, ha_rows nrows, bool interrupted,
*/
#define HA_MRR_NO_NULL_ENDPOINTS 128
/*
The MRR user has materialized range keys somewhere in the user's buffer.
This can be used for optimization of the procedure that sorts these keys
since in this case key values don't have to be copied into the MRR buffer.
In other words, it is guaranteed that after RANGE_SEQ_IF::next() call the
pointer in range->start_key.key will point to a key value that will remain
there until the end of the MRR scan.
*/
#define HA_MRR_MATERIALIZED_KEYS 256
/*
@@ -1815,12 +1825,17 @@ public:
inline int ha_index_first(uchar * buf);
inline int ha_index_last(uchar * buf);
inline int ha_index_next_same(uchar *buf, const uchar *key, uint keylen);
/*
TODO: should we make for those functions non-virtual ha_func_name wrappers,
too?
*/
virtual ha_rows multi_range_read_info_const(uint keyno, RANGE_SEQ_IF *seq,
void *seq_init_param,
uint n_ranges, uint *bufsz,
uint *flags, COST_VECT *cost);
virtual ha_rows multi_range_read_info(uint keyno, uint n_ranges, uint keys,
uint *bufsz, uint *flags, COST_VECT *cost);
uint key_parts, uint *bufsz,
uint *flags, COST_VECT *cost);
virtual int multi_range_read_init(RANGE_SEQ_IF *seq, void *seq_init_param,
uint n_ranges, uint mode,
HANDLER_BUFFER *buf);
@@ -2182,6 +2197,7 @@ public:
*/
virtual bool check_if_supported_virtual_columns(void) { return FALSE;}
TABLE* get_table() { return table; }
protected:
/* deprecated, don't use in new engines */
inline void ha_statistic_increment(ulong SSV::*offset) const { }
@@ -2374,7 +2390,6 @@ private:
virtual int rename_partitions(const char *path)
{ return HA_ERR_WRONG_COMMAND; }
friend class ha_partition;
friend class DsMrr_impl;
public:
/* XXX to be removed, see ha_partition::partition_ht() */
virtual handlerton *partition_ht() const

File diff suppressed because it is too large Load Diff

View File

@@ -1,19 +1,423 @@
/*
This file contains declarations for
- Disk-Sweep MultiRangeRead (DS-MRR) implementation
/**
@defgroup DS-MRR declarations
@{
*/
/**
A Disk-Sweep MRR interface implementation
A Disk-Sweep implementation of MRR Interface (DS-MRR for short)
This implementation makes range (and, in the future, 'ref') scans to read
table rows in disk sweeps.
This is a "plugin"(*) for storage engines that allows to
1. When doing index scans, read table rows in rowid order;
2. when making many index lookups, do them in key order and don't
lookup the same key value multiple times;
3. Do both #1 and #2, when applicable.
These changes are expected to speed up query execution for disk-based
storage engines running io-bound loads and "big" queries (ie. queries that
do joins and enumerate lots of records).
Currently it is used by MyISAM and InnoDB. Potentially it can be used with
any table handler that has non-clustered indexes and on-disk rows.
(*) - only conceptually. No dynamic loading or binary compatibility of any
kind.
General scheme of things:
SQL Layer code
| | |
v v v
-|---|---|---- handler->multi_range_read_XXX() function calls
| | |
_____________________________________
/ DS-MRR module \
| (order/de-duplicate lookup keys, |
| scan indexes in key order, |
| order/de-duplicate rowids, |
| retrieve full record reads in rowid |
| order) |
\_____________________________________/
| | |
-|---|---|----- handler->read_range_first()/read_range_next(),
| | | handler->index_read(), handler->rnd_pos() calls.
| | |
v v v
Storage engine internals
Currently DS-MRR is used by MyISAM, InnoDB/XtraDB and Maria storage engines.
Potentially it can be used with any table handler that has disk-based data
storage and has better performance when reading data in rowid order.
*/
class DsMrr_impl
#include "sql_lifo_buffer.h"
class DsMrr_impl;
class Key_parameters
{
public:
/* TRUE <=> We can get at most one index tuple for a lookup key */
bool index_ranges_unique;
uint key_tuple_length; /* Length of index lookup tuple, in bytes */
key_part_map key_tuple_map; /* keyparts used in index lookup tuples */
/*
This is
= key_tuple_length if we copy keys to buffer
= sizeof(void*) if we're using pointers to materialized keys.
*/
uint key_size_in_keybuf;
/* TRUE <=> don't copy key values, use pointers to them instead. */
bool use_key_pointers;
};
/**
Iterator over (record, range_id) pairs that match given key value.
We may need to scan multiple (key_val, range_id) pairs with the same
key value. A key value may have multiple matching records, so we'll need to
produce a cross-product of sets of matching records and range_id-s.
*/
class Mrr_ordered_index_reader;
class Key_value_records_iterator
{
/* Scan parameters */
Key_parameters *param;
Lifo_buffer_iterator identical_key_it;
uchar *last_identical_key_ptr;
bool get_next_row;
//handler *h;
/* TRUE <=> We can get at most one index tuple for a lookup key */
//bool index_ranges_unique;
Mrr_ordered_index_reader *owner;
/* key_buffer.read() reads to here */
uchar *cur_index_tuple;
public:
bool init(Mrr_ordered_index_reader *owner_arg);
/*
Get next (key_val, range_id) pair.
*/
int get_next();
void close();
friend class Mrr_ordered_index_reader;
};
/*
Something that will manage buffers for those that call it
*/
class Buffer_manager
{
public:
virtual void reset_buffer_sizes()= 0;
virtual void setup_buffer_sizes(uint key_size_in_keybuf,
key_part_map key_tuple_map)=0;
virtual Lifo_buffer* get_key_buffer()= 0;
virtual ~Buffer_manager(){}
};
/*
Abstract MRR execution strategy
An object of this class produces (R, range_info) pairs where R can be an
index tuple or a table record.
Getting HA_ERR_END_OF_FILE from get_next() means that the source should be
re-filled.
Was:
if eof() returns true after refill attempt, then the end of
stream has been reached and get_next() must not be called anymore.
Now:
if refill_buffer() returns HA_ERR_END_OF_FILE that means the stream is
really exhausted.
*/
class Mrr_reader
{
public:
virtual int get_next(char **range_info) = 0;
virtual int refill_buffer()=0;
virtual ~Mrr_reader() {}; /* just to remove compiler warning */
};
/* A common base for strategies that do index scans and produce index tuples */
class Mrr_index_reader : public Mrr_reader
{
public:
handler *h;
virtual int init(handler *h_arg, RANGE_SEQ_IF *seq_funcs,
void *seq_init_param, uint n_ranges,
uint mode, Buffer_manager *buf_manager_arg) = 0;
virtual bool eof() = 0;
virtual uchar *get_rowid_ptr()= 0;
virtual bool skip_record(char *range_id, uchar *rowid)=0;
};
/*
A "bypass" strategy that uses default MRR implementation (i.e.
handler::multi_range_read_XXX() calls) to produce rows.
*/
class Mrr_simple_index_reader : public Mrr_index_reader
{
int res;
public:
int init(handler *h_arg, RANGE_SEQ_IF *seq_funcs,
void *seq_init_param, uint n_ranges,
uint mode, Buffer_manager *buf_manager_arg);
int get_next(char **range_info);
int refill_buffer() { return HA_ERR_END_OF_FILE; }
bool eof() { return test(res); }
uchar *get_rowid_ptr() { return h->ref; }
bool skip_record(char *range_id, uchar *rowid)
{
return (h->mrr_funcs.skip_record &&
h->mrr_funcs.skip_record(h->mrr_iter, range_id, rowid));
}
};
/*
A strategy that sorts index lookup keys before scanning the index
*/
class Mrr_ordered_index_reader : public Mrr_index_reader
{
public:
int init(handler *h_arg, RANGE_SEQ_IF *seq_funcs,
void *seq_init_param, uint n_ranges,
uint mode, Buffer_manager *buf_manager_arg);
int get_next(char **range_info);
int refill_buffer();
bool eof() { return index_scan_eof; }
uchar *get_rowid_ptr() { return h->ref; }
bool skip_record(char *range_info, uchar *rowid)
{
return (mrr_funcs.skip_record &&
mrr_funcs.skip_record(mrr_iter, range_info, rowid));
}
private:
Key_value_records_iterator kv_it;
bool scanning_key_val_iter;
char *cur_range_info;
/* Buffer to store (key, range_id) pairs */
Lifo_buffer *key_buffer;
Buffer_manager *buf_manager;
/* Initially FALSE, becomes TRUE when we've set key_tuple_xxx members */
bool know_key_tuple_params;
// bool use_key_pointers;
Key_parameters keypar;
/* TRUE <=> need range association, buffers hold {rowid, range_id} pairs */
bool is_mrr_assoc;
bool no_more_keys;
RANGE_SEQ_IF mrr_funcs;
range_seq_t mrr_iter;
//bool auto_refill;
bool index_scan_eof;
static int key_tuple_cmp(void* arg, uchar* key1, uchar* key2);
static int key_tuple_cmp_reverse(void* arg, uchar* key1, uchar* key2);
//void cleanup();
friend class Key_value_records_iterator;
friend class DsMrr_impl;
friend class Mrr_ordered_rndpos_reader;
};
/* MRR strategy that fetches rowids */
class Mrr_ordered_rndpos_reader : public Mrr_reader
{
public:
int init(handler *h, Mrr_index_reader *index_reader, uint mode,
Lifo_buffer *buf);
int get_next(char **range_info);
int refill_buffer();
int refill2();
void cleanup();
private:
handler *h;
DsMrr_impl *dsmrr;
/* This what we get (rowid, range_info) pairs from */
Mrr_index_reader *index_reader;
uchar *index_rowid;
bool index_reader_exhausted;
/* TRUE <=> need range association, buffers hold {rowid, range_id} pairs */
bool is_mrr_assoc;
uchar *last_identical_rowid;
Lifo_buffer *rowid_buffer;
/* = h->ref_length [ + sizeof(range_assoc_info) ] */
//uint rowid_buff_elem_size;
/* rowid_buffer.read() will set the following: */
uchar *rowid;
uchar *rowids_range_id;
};
class Mrr_reader_factory
{
public:
Mrr_ordered_rndpos_reader ordered_rndpos_reader;
Mrr_ordered_index_reader ordered_index_reader;
Mrr_simple_index_reader simple_index_reader;
};
/*
DS-MRR implementation for one table. Create/use one object of this class for
each ha_{myisam/innobase/etc} object. That object will be further referred to
as "the handler"
DsMrr_impl supports has the following execution strategies:
- Bypass DS-MRR, pass all calls to default MRR implementation, which is
an MRR-to-non-MRR call converter.
- Key-Ordered Retrieval
- Rowid-Ordered Retrieval
DsMrr_impl will use one of the above strategies, or a combination of them,
according to the following diagram:
(mrr function calls)
|
+----------------->-----------------+
| |
___________v______________ _______________v________________
/ default: use lookup keys \ / KEY-ORDERED RETRIEVAL: \
| (or ranges) in whatever | | sort lookup keys and then make |
| order they are supplied | | index lookups in index order |
\__________________________/ \________________________________/
| | | | |
+---<---+ | +--------------->-----------|----+
| | | |
| | +---------------+ |
| ______v___ ______ | _______________v_______________
| / default: read \ | / ROWID-ORDERED RETRIEVAL: \
| | table records | | | Before reading table records, |
v | in random order | v | sort their rowids and then |
| \_________________/ | | read them in rowid order |
| | | \_______________________________/
| | | |
| | | |
+-->---+ | +----<------+-----------<--------+
| | |
v v v
(table records and range_ids)
The choice of strategy depends on MRR scan properties, table properties
(whether we're scanning clustered primary key), and @@optimizer_switch
settings.
Key-Ordered Retrieval
---------------------
The idea is: if MRR scan is essentially a series of lookups on
tbl.key=value1 OR tbl.key=value2 OR ... OR tbl.key=valueN
then it makes sense to collect and order the set of lookup values, i.e.
sort(value1, value2, .. valueN)
and then do index lookups in index order. This results in fewer index page
fetch operations, and we also can avoid making multiple index lookups for the
same value. That is, if value1=valueN we can easily discover that after
sorting and make one index lookup for them instead of two.
Rowid-Ordered Retrieval
-----------------------
If we do a regular index scan or a series of index lookups, we'll be hitting
table records at random. For disk-based engines, this is much slower than
reading the same records in disk order. We assume that disk ordering of
rows is the same as ordering of their rowids (which is provided by
handler::cmp_ref())
In order to retrieve records in different order, we must separate index
scanning and record fetching, that is, MRR scan uses the following steps:
1. Scan the index (and only index, that is, with HA_EXTRA_KEYREAD on) and
fill a buffer with {rowid, range_id} pairs
2. Sort the buffer by rowid value
3. for each {rowid, range_id} pair in the buffer
get record by rowid and return the {record, range_id} pair
4. Repeat the above steps until we've exhausted the list of ranges we're
scanning.
Buffer space management considerations
--------------------------------------
With regards to buffer/memory management, MRR interface specifies that
- SQL layer provides multi_range_read_init() with buffer of certain size.
- MRR implementation may use (i.e. have at its disposal till the end of
the MRR scan) all of the buffer, or return the unused end of the buffer
to SQL layer.
DS-MRR needs buffer in order to accumulate and sort rowids and/or keys. When
we need to accumulate/sort only keys (or only rowids), it is fairly trivial.
When we need to accumulate/sort both keys and rowids, efficient buffer use
gets complicated. We need to:
- First, accumulate keys and sort them
- Then use the keys (smaller values go first) to obtain rowids. A key is not
needed after we've got matching rowids for it.
- Make sure that rowids are accumulated at the front of the buffer, so that we
can return the end part of the buffer to SQL layer, should there be too
few rowid values to occupy the buffer.
All of these goals are achieved by using the following scheme:
| | We get an empty buffer from SQL layer.
| *-|
| *----| First, we fill the buffer with keys. Key_buffer
| *-------| part grows from end of the buffer space to start
| *----------| (In this picture, the buffer is big enough to
| *-------------| accomodate all keys and even have some space left)
| *=============| We want to do key-ordered index scan, so we sort
the keys
|-x *===========| Then we use the keys get rowids. Rowids are
|----x *========| stored from start of buffer space towards the end.
|--------x *=====| The part of the buffer occupied with keys
|------------x *===| gradually frees up space for rowids. In this
|--------------x *=| picture we run out of keys before we've ran out
|----------------x | of buffer space (it can be other way as well).
|================x | Then we sort the rowids.
| |~~~| The unused part of the buffer is at the end, so
we can return it to the SQL layer.
|================* Sorted rowids are then used to read table records
in disk order
*/
class DsMrr_impl : public Buffer_manager
{
public:
typedef void (handler::*range_check_toggle_func_t)(bool on);
@@ -21,29 +425,6 @@ public:
DsMrr_impl()
: h2(NULL) {};
/*
The "owner" handler object (the one that calls dsmrr_XXX functions.
It is used to retrieve full table rows by calling rnd_pos().
*/
handler *h;
TABLE *table; /* Always equal to h->table */
private:
/* Secondary handler object. It is used for scanning the index */
handler *h2;
/* Buffer to store rowids, or (rowid, range_id) pairs */
uchar *rowids_buf;
uchar *rowids_buf_cur; /* Current position when reading/writing */
uchar *rowids_buf_last; /* When reading: end of used buffer space */
uchar *rowids_buf_end; /* End of the buffer */
bool dsmrr_eof; /* TRUE <=> We have reached EOF when reading index tuples */
/* TRUE <=> need range association, buffer holds {rowid, range_id} pairs */
bool is_mrr_assoc;
bool use_default_impl; /* TRUE <=> shortcut all calls to default MRR impl */
public:
void init(handler *h_arg, TABLE *table_arg)
{
h= h_arg;
@@ -52,19 +433,102 @@ public:
int dsmrr_init(handler *h, RANGE_SEQ_IF *seq_funcs, void *seq_init_param,
uint n_ranges, uint mode, HANDLER_BUFFER *buf);
void dsmrr_close();
int dsmrr_fill_buffer();
int dsmrr_next(char **range_info);
ha_rows dsmrr_info(uint keyno, uint n_ranges, uint keys, uint *bufsz,
uint *flags, COST_VECT *cost);
ha_rows dsmrr_info(uint keyno, uint n_ranges, uint keys, uint key_parts,
uint *bufsz, uint *flags, COST_VECT *cost);
ha_rows dsmrr_info_const(uint keyno, RANGE_SEQ_IF *seq,
void *seq_init_param, uint n_ranges, uint *bufsz,
uint *flags, COST_VECT *cost);
private:
/* Buffer to store (key, range_id) pairs */
Lifo_buffer *key_buffer;
/*
The "owner" handler object (the one that is expected to "own" this object
and call its functions).
*/
handler *h;
TABLE *table; /* Always equal to h->table */
/*
Secondary handler object. (created when needed, we need it when we need
to run both index scan and rnd_pos() scan at the same time)
*/
handler *h2;
/** Properties of current MRR scan **/
uint keyno; /* index we're running the scan on */
/* TRUE <=> need range association, buffers hold {rowid, range_id} pairs */
bool is_mrr_assoc;
/* TRUE <=> sort the keys before making index lookups */
//bool do_sort_keys;
/* TRUE <=> sort rowids and use rnd_pos() to get and return full records */
//bool do_rndpos_scan;
Mrr_reader_factory strategy_factory;
Mrr_reader *strategy;
Mrr_index_reader *index_strategy;
/* The whole buffer space that we're using */
uchar *full_buf;
uchar *full_buf_end;
/*
When using both rowid and key buffers: the boundary between key and rowid
parts of the buffer. This is the "original" value, actual memory ranges
used by key and rowid parts may be different because of dynamic space
reallocation between them.
*/
uchar *rowid_buffer_end;
/** Index scaning and key buffer-related members **/
/*
One of the following two is used for key buffer: forward is used when
we only need key buffer, backward is used when we need both key and rowid
buffers.
*/
Forward_lifo_buffer forward_key_buf;
Backward_lifo_buffer backward_key_buf;
Forward_lifo_buffer rowid_buffer;
/* = key_size_in_keybuf [ + sizeof(range_assoc_info) ] */
//uint key_buff_elem_size_;
/** rnd_pos() scan and rowid buffer-related members **/
/*
Buffer to store (rowid, range_id) pairs, or just rowids if
is_mrr_assoc==FALSE
*/
//Forward_lifo_buffer rowid_buffer;
bool choose_mrr_impl(uint keyno, ha_rows rows, uint *flags, uint *bufsz,
COST_VECT *cost);
bool get_disk_sweep_mrr_cost(uint keynr, ha_rows rows, uint flags,
uint *buffer_size, COST_VECT *cost);
bool check_cpk_scan(THD *thd, uint keyno, uint mrr_flags);
void reallocate_buffer_space();
/* Buffer_manager implementation */
void setup_buffer_sizes(uint key_size_in_keybuf, key_part_map key_tuple_map);
void reset_buffer_sizes();
Lifo_buffer* get_key_buffer() { return key_buffer; }
friend class Key_value_records_iterator;
friend class Mrr_ordered_index_reader;
friend class Mrr_ordered_rndpos_reader;
int setup_two_handlers();
void close_second_handler();
};
/**
@} (end of group DS-MRR declarations)
*/

View File

@@ -571,12 +571,13 @@ protected:
#define OPTIMIZER_SWITCH_PARTIAL_MATCH_ROWID_MERGE 512
#define OPTIMIZER_SWITCH_PARTIAL_MATCH_TABLE_SCAN 1024
#define OPTIMIZER_SWITCH_SUBQUERY_CACHE (1<<11)
#define OPTIMIZER_SWITCH_MRR_SORT_KEYS (1<<12)
#ifdef DBUG_OFF
# define OPTIMIZER_SWITCH_LAST (1<<12)
#else
# define OPTIMIZER_SWITCH_TABLE_ELIMINATION (1<<12)
# define OPTIMIZER_SWITCH_LAST (1<<13)
#else
# define OPTIMIZER_SWITCH_TABLE_ELIMINATION (1<<13)
# define OPTIMIZER_SWITCH_LAST (1<<14)
#endif
#ifdef DBUG_OFF
@@ -592,7 +593,8 @@ protected:
OPTIMIZER_SWITCH_SEMIJOIN | \
OPTIMIZER_SWITCH_PARTIAL_MATCH_ROWID_MERGE|\
OPTIMIZER_SWITCH_PARTIAL_MATCH_TABLE_SCAN|\
OPTIMIZER_SWITCH_SUBQUERY_CACHE)
OPTIMIZER_SWITCH_SUBQUERY_CACHE|\
OPTIMIZER_SWITCH_MRR_SORT_KEYS)
#else
# define OPTIMIZER_SWITCH_DEFAULT (OPTIMIZER_SWITCH_INDEX_MERGE | \
OPTIMIZER_SWITCH_INDEX_MERGE_UNION | \
@@ -606,7 +608,8 @@ protected:
OPTIMIZER_SWITCH_SEMIJOIN | \
OPTIMIZER_SWITCH_PARTIAL_MATCH_ROWID_MERGE|\
OPTIMIZER_SWITCH_PARTIAL_MATCH_TABLE_SCAN|\
OPTIMIZER_SWITCH_SUBQUERY_CACHE)
OPTIMIZER_SWITCH_SUBQUERY_CACHE|\
OPTIMIZER_SWITCH_MRR_SORT_KEYS)
#endif
/*

View File

@@ -345,6 +345,7 @@ static const char *optimizer_switch_names[]=
"partial_match_rowid_merge",
"partial_match_table_scan",
"subquery_cache",
"mrr_sort_keys",
#ifndef DBUG_OFF
"table_elimination",
#endif
@@ -366,6 +367,7 @@ static const unsigned int optimizer_switch_names_len[]=
sizeof("partial_match_rowid_merge") - 1,
sizeof("partial_match_table_scan") - 1,
sizeof("subquery_cache") - 1,
sizeof("mrr_sort_keys") - 1,
#ifndef DBUG_OFF
sizeof("table_elimination") - 1,
#endif
@@ -464,7 +466,8 @@ static const char *optimizer_switch_str="index_merge=on,index_merge_union=on,"
"semijoin=on,"
"partial_match_rowid_merge=on,"
"partial_match_table_scan=on,"
"subquery_cache=on"
"subquery_cache=on,"
"mrr_sort_keys=on"
#ifndef DBUG_OFF
",table_elimination=on";
#else

View File

@@ -378,6 +378,7 @@ void push_index_cond(JOIN_TAB *tab, uint keyno, bool other_tbls_ok)
QT_ORDINARY););
tab->select->cond= tab->select_cond;
tab->select->pre_idx_push_select_cond= tab->pre_idx_push_select_cond;
}
}
}

View File

@@ -1119,7 +1119,7 @@ SQL_SELECT *make_select(TABLE *head, table_map const_tables,
}
SQL_SELECT::SQL_SELECT() :quick(0),cond(0),free_cond(0)
SQL_SELECT::SQL_SELECT() :quick(0),cond(0),pre_idx_push_select_cond(NULL),free_cond(0)
{
quick_keys.clear_all(); needed_reg.clear_all();
my_b_clear(&file);
@@ -8006,6 +8006,7 @@ QUICK_RANGE_SELECT *get_quick_select_for_ref(THD *thd, TABLE *table,
quick->mrr_buf_size= thd->variables.mrr_buff_size;
if (table->file->multi_range_read_info(quick->index, 1, (uint)records,
uint(-1),
&quick->mrr_buf_size,
&quick->mrr_flags, &cost))
goto err;

View File

@@ -818,6 +818,13 @@ class SQL_SELECT :public Sql_alloc {
public:
QUICK_SELECT_I *quick; // If quick-select used
COND *cond; // where condition
/*
When using Index Condition Pushdown: condition that we've had before
extracting and pushing index condition.
In other cases, NULL.
*/
Item *pre_idx_push_select_cond;
TABLE *head;
IO_CACHE file; // Positions to used records
ha_rows records; // Records in use if read from file

View File

@@ -651,6 +651,9 @@ int JOIN_CACHE_BKA::init()
use_emb_key= check_emb_key_usage();
if (use_emb_key)
mrr_mode|= HA_MRR_MATERIALIZED_KEYS;
create_remaining_fields(FALSE);
set_constants();
@@ -2627,6 +2630,8 @@ int JOIN_CACHE_BKA_UNIQUE::init()
data_fields_offset+= copy->length;
}
mrr_mode|= HA_MRR_MATERIALIZED_KEYS;
DBUG_RETURN(rc);
}

339
sql/sql_lifo_buffer.h Normal file
View File

@@ -0,0 +1,339 @@
/**
@defgroup Bi-directional LIFO buffers used by DS-MRR implementation
@{
*/
class Forward_lifo_buffer;
class Backward_lifo_buffer;
/*
A base class for in-memory buffer used by DS-MRR implementation. Common
properties:
- The buffer is last-in-first-out, i.e. elements that are written last are
read first.
- The buffer contains fixed-size elements. The elements are either atomic
byte sequences or pairs of them.
- The buffer resides in the memory provided by the user. It is possible to
= dynamically (ie. between write operations) add ajacent memory space to
the buffer
= dynamically remove unused space from the buffer.
The intent of this is to allow to have two buffers on adjacent memory
space, one is being read from (and so its space shrinks), while the other
is being written to (and so it needs more and more space).
There are two concrete classes, Forward_lifo_buffer and Backward_lifo_buffer.
*/
class Lifo_buffer
{
protected:
/**
Pointers to data to be written. write() call will assume that
(*write_ptr1) points to size1 bytes of data to be written.
If write_ptr2 != NULL then the buffer stores pairs, and (*write_ptr2)
points to size2 bytes of data that form the second component.
*/
uchar **write_ptr1;
size_t size1;
uchar **write_ptr2;
size_t size2;
/**
read() will do reading by storing pointer to read data into *read_ptr1 (if
the buffer stores atomic elements), or into {*read_ptr1, *read_ptr2} (if
the buffer stores pairs).
*/
uchar **read_ptr1;
uchar **read_ptr2;
uchar *start; /**< points to start of buffer space */
uchar *end; /**< points to just beyond the end of buffer space */
public:
enum enum_direction {
BACKWARD=-1, /**< buffer is filled/read from bigger to smaller memory addresses */
FORWARD=1 /**< buffer is filled/read from smaller to bigger memory addresses */
};
virtual enum_direction type() = 0;
/* Buffer space control functions */
/** Let the buffer store data in the given space. */
void set_buffer_space(uchar *start_arg, uchar *end_arg)
{
start= start_arg;
end= end_arg;
TRASH(start, end - start);
reset();
}
/**
Specify where write() should get the source data from, as well as source
data size.
*/
void setup_writing(uchar **data1, size_t len1, uchar **data2, size_t len2)
{
write_ptr1= data1;
size1= len1;
write_ptr2= data2;
size2= len2;
}
/**
Specify where read() should store pointers to read data, as well as read
data size. The sizes must match those passed to setup_writing().
*/
void setup_reading(uchar **data1, size_t len1, uchar **data2, size_t len2)
{
read_ptr1= data1;
DBUG_ASSERT(len1 == size1);
read_ptr2= data2;
DBUG_ASSERT(len2 == size2);
}
bool can_write()
{
return have_space_for(size1 + (write_ptr2 ? size2 : 0));
}
virtual void write() = 0;
bool is_empty() { return used_size() == 0; }
virtual bool read() = 0;
void sort(qsort2_cmp cmp_func, void *cmp_func_arg)
{
uint elem_size= size1 + (write_ptr2 ? size2 : 0);
uint n_elements= used_size() / elem_size;
my_qsort2(used_area(), n_elements, elem_size, cmp_func, cmp_func_arg);
}
virtual void reset() = 0;
virtual uchar *end_of_space() = 0;
protected:
virtual bool have_space_for(size_t bytes) = 0;
virtual size_t used_size() = 0;
/* To be used only by iterator class: */
virtual uchar *get_pos()= 0;
virtual bool read(uchar **position)= 0;
friend class Lifo_buffer_iterator;
public:
virtual void remove_unused_space(uchar **unused_start, uchar **unused_end)=0;
virtual uchar *used_area() = 0;
virtual ~Lifo_buffer() {};
};
/**
Forward LIFO buffer
The buffer that is being written to from start to end and read in the
reverse. 'pos' points to just beyond the end of used space.
It is possible to grow/shink the buffer at the end bound
used space unused space
*==============*-----------------*
^ ^ ^
| | +--- end
| +---- pos
+--- start
*/
class Forward_lifo_buffer: public Lifo_buffer
{
uchar *pos;
public:
enum_direction type() { return FORWARD; }
size_t used_size()
{
return pos - start;
}
void reset()
{
pos= start;
}
uchar *end_of_space() { return pos; }
bool have_space_for(size_t bytes)
{
return (pos + bytes < end);
}
void write()
{
write_bytes(*write_ptr1, size1);
if (write_ptr2)
write_bytes(*write_ptr2, size2);
}
void write_bytes(const uchar *data, size_t bytes)
{
DBUG_ASSERT(have_space_for(bytes));
memcpy(pos, data, bytes);
pos += bytes;
}
bool have_data(uchar *position, size_t bytes)
{
return ((position - start) >= (ptrdiff_t)bytes);
}
uchar *read_bytes(uchar **position, size_t bytes)
{
DBUG_ASSERT(have_data(*position, bytes));
*position= (*position) - bytes;
return *position;
}
bool read() { return read(&pos); }
bool read(uchar **position)
{
if (!have_data(*position, size1 + (read_ptr2 ? size2 : 0)))
return TRUE;
if (read_ptr2)
*read_ptr2= read_bytes(position, size2);
*read_ptr1= read_bytes(position, size1);
return FALSE;
}
void remove_unused_space(uchar **unused_start, uchar **unused_end)
{
DBUG_ASSERT(0); /* Don't need this yet */
}
/**
Add more space to the buffer. The caller is responsible that the space
being added is adjacent to the end of the buffer.
@param unused_start Start of space
@param unused_end End of space
*/
void grow(uchar *unused_start, uchar *unused_end)
{
DBUG_ASSERT(unused_end >= unused_start);
DBUG_ASSERT(end == unused_start);
TRASH(unused_start, unused_end - unused_start);
end= unused_end;
}
/* Return pointer to start of the memory area that is occupied by the data */
uchar *used_area() { return start; }
friend class Lifo_buffer_iterator;
uchar *get_pos() { return pos; }
};
/**
Backward LIFO buffer
The buffer that is being written to from start to end and read in the
reverse. 'pos' points to the start of used space.
It is possible to grow/shink the buffer at the start.
unused space used space
*--------------*=================*
^ ^ ^
| | +--- end
| +---- pos
+--- start
*/
class Backward_lifo_buffer: public Lifo_buffer
{
uchar *pos;
public:
enum_direction type() { return BACKWARD; }
size_t used_size()
{
return end - pos;
}
void reset()
{
pos= end;
}
uchar *end_of_space() { return end; }
bool have_space_for(size_t bytes)
{
return (pos - bytes >= start);
}
void write()
{
if (write_ptr2)
write_bytes(*write_ptr2, size2);
write_bytes(*write_ptr1, size1);
}
void write_bytes(const uchar *data, size_t bytes)
{
DBUG_ASSERT(have_space_for(bytes));
pos -= bytes;
memcpy(pos, data, bytes);
}
bool read()
{
return read(&pos);
}
bool read(uchar **position)
{
if (!have_data(*position, size1 + (read_ptr2 ? size2 : 0)))
return TRUE;
*read_ptr1= read_bytes(position, size1);
if (read_ptr2)
*read_ptr2= read_bytes(position, size2);
return FALSE;
}
bool have_data(uchar *position, size_t bytes)
{
return ((end - position) >= (ptrdiff_t)bytes);
}
uchar *read_bytes(uchar **position, size_t bytes)
{
DBUG_ASSERT(have_data(*position, bytes));
uchar *ret= *position;
*position= *position + bytes;
return ret;
}
/**
Stop using/return the unused part of the space
@param unused_start OUT Start of the unused space
@param unused_end OUT End of the unused space
*/
void remove_unused_space(uchar **unused_start, uchar **unused_end)
{
*unused_start= start;
*unused_end= pos;
start= pos;
}
void grow(uchar *unused_start, uchar *unused_end)
{
DBUG_ASSERT(0); /* Not used for backward buffers */
}
/* Return pointer to start of the memory area that is occupied by the data */
uchar *used_area() { return pos; }
friend class Lifo_buffer_iterator;
uchar *get_pos() { return pos; }
};
/** Iterator to walk over contents of the buffer without reading it. */
class Lifo_buffer_iterator
{
uchar *pos;
Lifo_buffer *buf;
public:
void init(Lifo_buffer *buf_arg)
{
buf= buf_arg;
pos= buf->get_pos();
}
/*
Read the next value. The calling convention is the same as buf->read()
has.
@retval FALSE - ok
@retval TRUE - EOF, reached the end of the buffer
*/
bool read()
{
return buf->read(&pos);
}
};

View File

@@ -6623,7 +6623,6 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
DBUG_ENTER("make_join_select");
if (select)
{
add_not_null_conds(join);
table_map used_tables;
/*
Step #1: Extract constant condition
@@ -7068,6 +7067,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
}
}
add_not_null_conds(join);
}
DBUG_RETURN(0);
}
@@ -7494,10 +7494,11 @@ uint check_join_cache_usage(JOIN_TAB *tab,
case JT_EQ_REF:
if (cache_level <= 4)
return 0;
flags= HA_MRR_NO_NULL_ENDPOINTS;
flags= HA_MRR_NO_NULL_ENDPOINTS | HA_MRR_SINGLE_POINT;
if (tab->table->covering_keys.is_set(tab->ref.key))
flags|= HA_MRR_INDEX_ONLY;
rows= tab->table->file->multi_range_read_info(tab->ref.key, 10, 20,
tab->ref.key_parts,
&bufsz, &flags, &cost);
if ((rows != HA_POS_ERROR) && !(flags & HA_MRR_USE_DEFAULT_IMPL) &&
(!(flags & HA_MRR_NO_ASSOCIATION) || cache_level > 6) &&

View File

@@ -3636,11 +3636,11 @@ ha_rows ha_maria::multi_range_read_info_const(uint keyno, RANGE_SEQ_IF *seq,
}
ha_rows ha_maria::multi_range_read_info(uint keyno, uint n_ranges, uint keys,
uint *bufsz, uint *flags,
COST_VECT *cost)
uint key_parts, uint *bufsz,
uint *flags, COST_VECT *cost)
{
ds_mrr.init(this, table);
return ds_mrr.dsmrr_info(keyno, n_ranges, keys, bufsz, flags, cost);
return ds_mrr.dsmrr_info(keyno, n_ranges, keys, key_parts, bufsz, flags, cost);
}
/* MyISAM MRR implementation ends */

View File

@@ -185,7 +185,8 @@ public:
uint n_ranges, uint *bufsz,
uint *flags, COST_VECT *cost);
ha_rows multi_range_read_info(uint keyno, uint n_ranges, uint keys,
uint *bufsz, uint *flags, COST_VECT *cost);
uint key_parts, uint *bufsz,
uint *flags, COST_VECT *cost);
/* Index condition pushdown implementation */
Item *idx_cond_push(uint keyno, Item* idx_cond);

View File

@@ -2224,11 +2224,11 @@ ha_rows ha_myisam::multi_range_read_info_const(uint keyno, RANGE_SEQ_IF *seq,
}
ha_rows ha_myisam::multi_range_read_info(uint keyno, uint n_ranges, uint keys,
uint *bufsz, uint *flags,
COST_VECT *cost)
uint key_parts, uint *bufsz,
uint *flags, COST_VECT *cost)
{
ds_mrr.init(this, table);
return ds_mrr.dsmrr_info(keyno, n_ranges, keys, bufsz, flags, cost);
return ds_mrr.dsmrr_info(keyno, n_ranges, keys, key_parts, bufsz, flags, cost);
}
/* MyISAM MRR implementation ends */

View File

@@ -168,7 +168,8 @@ public:
uint n_ranges, uint *bufsz,
uint *flags, COST_VECT *cost);
ha_rows multi_range_read_info(uint keyno, uint n_ranges, uint keys,
uint *bufsz, uint *flags, COST_VECT *cost);
uint key_parts, uint *bufsz,
uint *flags, COST_VECT *cost);
/* Index condition pushdown implementation */
Item *idx_cond_push(uint keyno, Item* idx_cond);

View File

@@ -12032,7 +12032,8 @@ test_innobase_convert_name()
*/
int ha_innobase::multi_range_read_init(RANGE_SEQ_IF *seq, void *seq_init_param,
uint n_ranges, uint mode, HANDLER_BUFFER *buf)
uint n_ranges, uint mode,
HANDLER_BUFFER *buf)
{
return ds_mrr.dsmrr_init(this, seq, seq_init_param, n_ranges, mode, buf);
}
@@ -12059,12 +12060,13 @@ ha_rows ha_innobase::multi_range_read_info_const(uint keyno, RANGE_SEQ_IF *seq,
return res;
}
ha_rows ha_innobase::multi_range_read_info(uint keyno, uint n_ranges,
uint keys, uint *bufsz,
ha_rows ha_innobase::multi_range_read_info(uint keyno, uint n_ranges, uint keys,
uint key_parts, uint *bufsz,
uint *flags, COST_VECT *cost)
{
ds_mrr.init(this, table);
ha_rows res= ds_mrr.dsmrr_info(keyno, n_ranges, keys, bufsz, flags, cost);
ha_rows res= ds_mrr.dsmrr_info(keyno, n_ranges, keys, key_parts, bufsz,
flags, cost);
return res;
}

View File

@@ -234,7 +234,8 @@ public:
uint n_ranges, uint *bufsz,
uint *flags, COST_VECT *cost);
ha_rows multi_range_read_info(uint keyno, uint n_ranges, uint keys,
uint *bufsz, uint *flags, COST_VECT *cost);
uint key_parts, uint *bufsz,
uint *flags, COST_VECT *cost);
DsMrr_impl ds_mrr;
Item *idx_cond_push(uint keyno, Item* idx_cond);