mirror of
https://github.com/MariaDB/server.git
synced 2025-07-30 16:24:05 +03:00
Merge in MWL#68: Subquery optimization: Efficient NOT IN execution with NULLs
This commit is contained in:
@ -1177,8 +1177,11 @@ DROP TABLE t1;
|
||||
|
||||
create table t1 (a bit(1) not null,b int) engine=myisam;
|
||||
create table t2 (c int) engine=innodb;
|
||||
set @save_optimizer_switch=@@optimizer_switch;
|
||||
set @@optimizer_switch='partial_match_rowid_merge=off,partial_match_table_scan=off';
|
||||
explain
|
||||
select b from t1 where a not in (select b from t1,t2 group by a) group by a;
|
||||
set optimizer_switch=@save_optimizer_switch;
|
||||
DROP TABLE t1,t2;
|
||||
|
||||
--echo End of 5.0 tests
|
||||
|
@ -1419,19 +1419,19 @@ drop table t1;
|
||||
#
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
set optimizer_switch=4;
|
||||
ERROR 42000: Variable 'optimizer_switch' can't be set to the value of '4'
|
||||
set optimizer_switch=NULL;
|
||||
@ -1458,21 +1458,21 @@ 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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
#
|
||||
# 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
|
||||
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
|
||||
create table t0 (a int);
|
||||
insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
|
||||
create table t1 (a int, b int, c int, filler char(100),
|
||||
@ -1582,5 +1582,5 @@ id select_type table type possible_keys key key_len ref rows Extra
|
||||
set optimizer_switch=default;
|
||||
show variables like 'optimizer_switch';
|
||||
Variable_name Value
|
||||
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
|
||||
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
|
||||
drop table t0, t1;
|
||||
|
@ -1425,12 +1425,15 @@ DROP TABLE t1;
|
||||
#
|
||||
create table t1 (a bit(1) not null,b int) engine=myisam;
|
||||
create table t2 (c int) engine=innodb;
|
||||
set @save_optimizer_switch=@@optimizer_switch;
|
||||
set @@optimizer_switch='partial_match_rowid_merge=off,partial_match_table_scan=off';
|
||||
explain
|
||||
select b from t1 where a not in (select b from t1,t2 group by a) group by a;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
|
||||
2 DEPENDENT SUBQUERY t1 system NULL NULL NULL NULL 0 const row not found
|
||||
2 DEPENDENT SUBQUERY t2 ALL NULL NULL NULL NULL 1
|
||||
set optimizer_switch=@save_optimizer_switch;
|
||||
DROP TABLE t1,t2;
|
||||
End of 5.0 tests
|
||||
CREATE TABLE `t2` (
|
||||
|
@ -394,7 +394,7 @@ drop table t0, t1;
|
||||
# - engine_condition_pushdown does not affect ICP
|
||||
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
|
||||
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
|
||||
create table t0 (a int);
|
||||
insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
|
||||
create table t1 (a int, b int, key(a));
|
||||
|
@ -149,6 +149,8 @@ c29 longblob, c30 longtext, c31 enum('one', 'two', 'three'),
|
||||
c32 set('monday', 'tuesday', 'wednesday')
|
||||
) engine = MYISAM ;
|
||||
create table t2 like t1;
|
||||
set @save_optimizer_switch=@@optimizer_switch;
|
||||
set @@optimizer_switch="partial_match_rowid_merge=off,partial_match_table_scan=off";
|
||||
set @stmt= ' explain SELECT (SELECT SUM(c1 + c12 + 0.0) FROM t2 where (t1.c2 - 0e-3) = t2.c2 GROUP BY t1.c15 LIMIT 1) as scalar_s, exists (select 1.0e+0 from t2 where t2.c3 * 9.0000000000 = t1.c4) as exists_s, c5 * 4 in (select c6 + 0.3e+1 from t2) as in_s, (c7 - 4, c8 - 4) in (select c9 + 4.0, c10 + 40e-1 from t2) as in_row_s FROM t1, (select c25 x, c32 y from t2) tt WHERE x * 1 = c25 ' ;
|
||||
prepare stmt1 from @stmt ;
|
||||
execute stmt1 ;
|
||||
@ -177,6 +179,7 @@ id select_type table type possible_keys key key_len ref rows Extra
|
||||
2 DEPENDENT SUBQUERY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
|
||||
deallocate prepare stmt1;
|
||||
drop tables t1,t2;
|
||||
set @@optimizer_switch=@save_optimizer_switch;
|
||||
set @arg00=1;
|
||||
prepare stmt1 from ' create table t1 (m int) as select 1 as m ' ;
|
||||
execute stmt1 ;
|
||||
|
@ -1,4 +1,6 @@
|
||||
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t11,t12;
|
||||
set @save_optimizer_switch=@@optimizer_switch;
|
||||
set @@optimizer_switch="partial_match_rowid_merge=off,partial_match_table_scan=off";
|
||||
select (select 2);
|
||||
(select 2)
|
||||
2
|
||||
@ -4803,4 +4805,5 @@ SELECT 1 FROM t1 GROUP BY
|
||||
1
|
||||
1
|
||||
DROP TABLE t1;
|
||||
set @@optimizer_switch=@save_optimizer_switch;
|
||||
End of 5.1 tests.
|
||||
|
@ -63,12 +63,15 @@ Handler_read_rnd_next 11
|
||||
select ' ^ This must show 11' Z;
|
||||
Z
|
||||
^ This must show 11
|
||||
set @save_optimizer_switch=@@optimizer_switch;
|
||||
set @@optimizer_switch="partial_match_rowid_merge=off,partial_match_table_scan=off";
|
||||
explain extended select a in (select max(ie) from t1 where oref=4 group by grp) from t3;
|
||||
id select_type table type possible_keys key key_len ref rows filtered Extra
|
||||
1 PRIMARY t3 ALL NULL NULL NULL NULL 2 100.00
|
||||
2 DEPENDENT SUBQUERY t1 ALL NULL NULL NULL NULL 6 100.00 Using where; Using temporary; Using filesort
|
||||
Warnings:
|
||||
Note 1003 select <in_optimizer>(`test`.`t3`.`a`,<exists>(select max(`test`.`t1`.`ie`) AS `max(ie)` from `test`.`t1` where (`test`.`t1`.`oref` = 4) group by `test`.`t1`.`grp` having trigcond((<cache>(`test`.`t3`.`a`) = <ref_null_helper>(max(`test`.`t1`.`ie`)))))) AS `a in (select max(ie) from t1 where oref=4 group by grp)` from `test`.`t3`
|
||||
set @@optimizer_switch=@save_optimizer_switch;
|
||||
drop table t1, t2, t3;
|
||||
create table t1 (a int, oref int, key(a));
|
||||
insert into t1 values
|
||||
@ -692,6 +695,8 @@ a MAX(b) test
|
||||
2 3 h
|
||||
3 4 i
|
||||
DROP TABLE t1, t2;
|
||||
set @save_optimizer_switch=@@optimizer_switch;
|
||||
set @@optimizer_switch="partial_match_rowid_merge=off,partial_match_table_scan=off";
|
||||
CREATE TABLE t1 (a int);
|
||||
CREATE TABLE t2 (b int, PRIMARY KEY(b));
|
||||
INSERT INTO t1 VALUES (1), (NULL), (4);
|
||||
@ -759,6 +764,7 @@ id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 PRIMARY t1 ALL NULL NULL NULL NULL 4 Using where
|
||||
2 DEPENDENT SUBQUERY t2 unique_subquery PRIMARY PRIMARY 4 func 1 Using index; Using where
|
||||
DROP TABLE t1, t2;
|
||||
set @@optimizer_switch=@save_optimizer_switch;
|
||||
CREATE TABLE t1 (a INT);
|
||||
INSERT INTO t1 VALUES(1);
|
||||
CREATE TABLE t2 (placeholder CHAR(11));
|
||||
@ -960,7 +966,7 @@ i1 i2
|
||||
# Baseline:
|
||||
SHOW STATUS LIKE '%Handler_read_rnd_next';
|
||||
Variable_name Value
|
||||
Handler_read_rnd_next 17
|
||||
Handler_read_rnd_next 18
|
||||
|
||||
INSERT INTO t1 VALUES (NULL, NULL);
|
||||
FLUSH STATUS;
|
||||
@ -977,7 +983,7 @@ i1 i2
|
||||
# (read record from t1, but do not read from t2)
|
||||
SHOW STATUS LIKE '%Handler_read_rnd_next';
|
||||
Variable_name Value
|
||||
Handler_read_rnd_next 18
|
||||
Handler_read_rnd_next 19
|
||||
DROP TABLE t1,t2;
|
||||
End of 5.1 tests
|
||||
CREATE TABLE t1 (
|
||||
|
@ -67,12 +67,15 @@ Handler_read_rnd_next 11
|
||||
select ' ^ This must show 11' Z;
|
||||
Z
|
||||
^ This must show 11
|
||||
set @save_optimizer_switch=@@optimizer_switch;
|
||||
set @@optimizer_switch="partial_match_rowid_merge=off,partial_match_table_scan=off";
|
||||
explain extended select a in (select max(ie) from t1 where oref=4 group by grp) from t3;
|
||||
id select_type table type possible_keys key key_len ref rows filtered Extra
|
||||
1 PRIMARY t3 ALL NULL NULL NULL NULL 2 100.00
|
||||
2 DEPENDENT SUBQUERY t1 ALL NULL NULL NULL NULL 6 100.00 Using where; Using temporary; Using filesort
|
||||
Warnings:
|
||||
Note 1003 select <in_optimizer>(`test`.`t3`.`a`,<exists>(select max(`test`.`t1`.`ie`) AS `max(ie)` from `test`.`t1` where (`test`.`t1`.`oref` = 4) group by `test`.`t1`.`grp` having trigcond((<cache>(`test`.`t3`.`a`) = <ref_null_helper>(max(`test`.`t1`.`ie`)))))) AS `a in (select max(ie) from t1 where oref=4 group by grp)` from `test`.`t3`
|
||||
set @@optimizer_switch=@save_optimizer_switch;
|
||||
drop table t1, t2, t3;
|
||||
create table t1 (a int, oref int, key(a));
|
||||
insert into t1 values
|
||||
@ -696,6 +699,8 @@ a MAX(b) test
|
||||
2 3 h
|
||||
3 4 i
|
||||
DROP TABLE t1, t2;
|
||||
set @save_optimizer_switch=@@optimizer_switch;
|
||||
set @@optimizer_switch="partial_match_rowid_merge=off,partial_match_table_scan=off";
|
||||
CREATE TABLE t1 (a int);
|
||||
CREATE TABLE t2 (b int, PRIMARY KEY(b));
|
||||
INSERT INTO t1 VALUES (1), (NULL), (4);
|
||||
@ -763,6 +768,7 @@ id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 PRIMARY t1 ALL NULL NULL NULL NULL 4 Using where
|
||||
2 DEPENDENT SUBQUERY t2 unique_subquery PRIMARY PRIMARY 4 func 1 Using index; Using where
|
||||
DROP TABLE t1, t2;
|
||||
set @@optimizer_switch=@save_optimizer_switch;
|
||||
CREATE TABLE t1 (a INT);
|
||||
INSERT INTO t1 VALUES(1);
|
||||
CREATE TABLE t2 (placeholder CHAR(11));
|
||||
@ -964,7 +970,7 @@ i1 i2
|
||||
# Baseline:
|
||||
SHOW STATUS LIKE '%Handler_read_rnd_next';
|
||||
Variable_name Value
|
||||
Handler_read_rnd_next 17
|
||||
Handler_read_rnd_next 18
|
||||
|
||||
INSERT INTO t1 VALUES (NULL, NULL);
|
||||
FLUSH STATUS;
|
||||
@ -981,7 +987,7 @@ i1 i2
|
||||
# (read record from t1, but do not read from t2)
|
||||
SHOW STATUS LIKE '%Handler_read_rnd_next';
|
||||
Variable_name Value
|
||||
Handler_read_rnd_next 18
|
||||
Handler_read_rnd_next 19
|
||||
DROP TABLE t1,t2;
|
||||
End of 5.1 tests
|
||||
CREATE TABLE t1 (
|
||||
|
@ -1,8 +1,10 @@
|
||||
show variables like 'optimizer_switch';
|
||||
Variable_name Value
|
||||
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
|
||||
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
|
||||
set optimizer_switch='materialization=off';
|
||||
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t11,t12;
|
||||
set @save_optimizer_switch=@@optimizer_switch;
|
||||
set @@optimizer_switch="partial_match_rowid_merge=off,partial_match_table_scan=off";
|
||||
select (select 2);
|
||||
(select 2)
|
||||
2
|
||||
@ -4807,8 +4809,9 @@ SELECT 1 FROM t1 GROUP BY
|
||||
1
|
||||
1
|
||||
DROP TABLE t1;
|
||||
set @@optimizer_switch=@save_optimizer_switch;
|
||||
End of 5.1 tests.
|
||||
set optimizer_switch=default;
|
||||
show variables like 'optimizer_switch';
|
||||
Variable_name Value
|
||||
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
|
||||
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
|
||||
|
@ -1,8 +1,10 @@
|
||||
show variables like 'optimizer_switch';
|
||||
Variable_name Value
|
||||
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
|
||||
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
|
||||
set optimizer_switch='materialization=off,semijoin=off';
|
||||
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t11,t12;
|
||||
set @save_optimizer_switch=@@optimizer_switch;
|
||||
set @@optimizer_switch="partial_match_rowid_merge=off,partial_match_table_scan=off";
|
||||
select (select 2);
|
||||
(select 2)
|
||||
2
|
||||
@ -4807,8 +4809,9 @@ SELECT 1 FROM t1 GROUP BY
|
||||
1
|
||||
1
|
||||
DROP TABLE t1;
|
||||
set @@optimizer_switch=@save_optimizer_switch;
|
||||
End of 5.1 tests.
|
||||
set optimizer_switch=default;
|
||||
show variables like 'optimizer_switch';
|
||||
Variable_name Value
|
||||
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
|
||||
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
|
||||
|
@ -1,8 +1,10 @@
|
||||
show variables like 'optimizer_switch';
|
||||
Variable_name Value
|
||||
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
|
||||
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
|
||||
set optimizer_switch='semijoin=off';
|
||||
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t11,t12;
|
||||
set @save_optimizer_switch=@@optimizer_switch;
|
||||
set @@optimizer_switch="partial_match_rowid_merge=off,partial_match_table_scan=off";
|
||||
select (select 2);
|
||||
(select 2)
|
||||
2
|
||||
@ -4807,8 +4809,9 @@ SELECT 1 FROM t1 GROUP BY
|
||||
1
|
||||
1
|
||||
DROP TABLE t1;
|
||||
set @@optimizer_switch=@save_optimizer_switch;
|
||||
End of 5.1 tests.
|
||||
set optimizer_switch=default;
|
||||
show variables like 'optimizer_switch';
|
||||
Variable_name Value
|
||||
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
|
||||
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
|
||||
|
@ -202,39 +202,39 @@ 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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
set optimizer_switch=default;
|
||||
drop table t0, t1, t2;
|
||||
drop table t10, t11, t12;
|
||||
|
@ -206,39 +206,39 @@ 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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
set optimizer_switch=default;
|
||||
drop table t0, t1, t2;
|
||||
drop table t10, t11, t12;
|
||||
|
@ -163,6 +163,9 @@ create table t1
|
||||
) engine = MYISAM ;
|
||||
create table t2 like t1;
|
||||
|
||||
set @save_optimizer_switch=@@optimizer_switch;
|
||||
set @@optimizer_switch="partial_match_rowid_merge=off,partial_match_table_scan=off";
|
||||
|
||||
set @stmt= ' explain SELECT (SELECT SUM(c1 + c12 + 0.0) FROM t2 where (t1.c2 - 0e-3) = t2.c2 GROUP BY t1.c15 LIMIT 1) as scalar_s, exists (select 1.0e+0 from t2 where t2.c3 * 9.0000000000 = t1.c4) as exists_s, c5 * 4 in (select c6 + 0.3e+1 from t2) as in_s, (c7 - 4, c8 - 4) in (select c9 + 4.0, c10 + 40e-1 from t2) as in_row_s FROM t1, (select c25 x, c32 y from t2) tt WHERE x * 1 = c25 ' ;
|
||||
prepare stmt1 from @stmt ;
|
||||
execute stmt1 ;
|
||||
@ -171,6 +174,8 @@ explain SELECT (SELECT SUM(c1 + c12 + 0.0) FROM t2 where (t1.c2 - 0e-3) = t2.c2
|
||||
deallocate prepare stmt1;
|
||||
drop tables t1,t2;
|
||||
|
||||
set @@optimizer_switch=@save_optimizer_switch;
|
||||
|
||||
#
|
||||
# parameters from variables (for field creation)
|
||||
#
|
||||
|
@ -11,6 +11,9 @@
|
||||
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t11,t12;
|
||||
--enable_warnings
|
||||
|
||||
set @save_optimizer_switch=@@optimizer_switch;
|
||||
set @@optimizer_switch="partial_match_rowid_merge=off,partial_match_table_scan=off";
|
||||
|
||||
select (select 2);
|
||||
explain extended select (select 2);
|
||||
SELECT (SELECT 1) UNION SELECT (SELECT 2);
|
||||
@ -4061,4 +4064,6 @@ SELECT 1 FROM t1 GROUP BY
|
||||
(SELECT LAST_INSERT_ID() FROM t1 ORDER BY MIN(a) ASC LIMIT 1);
|
||||
DROP TABLE t1;
|
||||
|
||||
set @@optimizer_switch=@save_optimizer_switch;
|
||||
|
||||
--echo End of 5.1 tests.
|
||||
|
@ -59,9 +59,13 @@ select a in (select max(ie) from t1 where oref=4 group by grp) from t3;
|
||||
show status like 'Handler_read_rnd_next';
|
||||
select ' ^ This must show 11' Z;
|
||||
|
||||
set @save_optimizer_switch=@@optimizer_switch;
|
||||
set @@optimizer_switch="partial_match_rowid_merge=off,partial_match_table_scan=off";
|
||||
|
||||
# This must show trigcond:
|
||||
explain extended select a in (select max(ie) from t1 where oref=4 group by grp) from t3;
|
||||
|
||||
set @@optimizer_switch=@save_optimizer_switch;
|
||||
drop table t1, t2, t3;
|
||||
|
||||
#
|
||||
@ -529,6 +533,9 @@ SELECT a, MAX(b),
|
||||
|
||||
DROP TABLE t1, t2;
|
||||
|
||||
# The next three test cases must be executed with the IN=>EXISTS strategy
|
||||
set @save_optimizer_switch=@@optimizer_switch;
|
||||
set @@optimizer_switch="partial_match_rowid_merge=off,partial_match_table_scan=off";
|
||||
|
||||
#
|
||||
# Bug #27870: crash of an equijoin query with WHERE condition containing
|
||||
@ -588,6 +595,8 @@ EXPLAIN SELECT a FROM t1 WHERE a NOT IN (SELECT a FROM t2);
|
||||
|
||||
DROP TABLE t1, t2;
|
||||
|
||||
set @@optimizer_switch=@save_optimizer_switch;
|
||||
|
||||
#
|
||||
# Bug #34763: item_subselect.cc:1235:Item_in_subselect::row_value_transformer:
|
||||
# Assertion failed, unexpected error message:
|
||||
|
@ -350,6 +350,7 @@ public:
|
||||
CHARSET_INFO *compare_collation() { return cmp.cmp_collation.collation; }
|
||||
uint decimal_precision() const { return 1; }
|
||||
void top_level_item() { abort_on_null= TRUE; }
|
||||
Arg_comparator *get_comparator() { return &cmp; }
|
||||
|
||||
friend class Arg_comparator;
|
||||
};
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -297,7 +297,7 @@ public:
|
||||
Representation of IN subquery predicates of the form
|
||||
"left_expr IN (SELECT ...)".
|
||||
|
||||
@detail
|
||||
@details
|
||||
This class has:
|
||||
- A "subquery execution engine" (as a subclass of Item_subselect) that allows
|
||||
it to evaluate subqueries. (and this class participates in execution by
|
||||
@ -319,6 +319,12 @@ protected:
|
||||
*/
|
||||
List<Cached_item> *left_expr_cache;
|
||||
bool first_execution;
|
||||
/*
|
||||
Set to TRUE if at query execution time we determine that this item's
|
||||
value is a constant during this execution. We need this member because
|
||||
it is not possible to substitute 'this' with a constant item.
|
||||
*/
|
||||
bool is_constant;
|
||||
|
||||
/*
|
||||
expr & optimizer used in subselect rewriting to store Item for
|
||||
@ -387,8 +393,8 @@ public:
|
||||
Item_in_subselect(Item * left_expr, st_select_lex *select_lex);
|
||||
Item_in_subselect()
|
||||
:Item_exists_subselect(), left_expr_cache(0), first_execution(TRUE),
|
||||
optimizer(0), abort_on_null(0), pushed_cond_guards(NULL),
|
||||
exec_method(NOT_TRANSFORMED), upper_item(0)
|
||||
is_constant(FALSE), optimizer(0), abort_on_null(0),
|
||||
pushed_cond_guards(NULL), exec_method(NOT_TRANSFORMED), upper_item(0)
|
||||
{}
|
||||
void cleanup();
|
||||
subs_type substype() { return IN_SUBS; }
|
||||
@ -421,6 +427,8 @@ public:
|
||||
void update_used_tables();
|
||||
bool setup_engine();
|
||||
bool init_left_expr_cache();
|
||||
/* Inform 'this' that it was computed, and contains a valid result. */
|
||||
void set_first_execution() { if (first_execution) first_execution= FALSE; }
|
||||
bool is_expensive_processor(uchar *arg);
|
||||
|
||||
friend class Item_ref_null_helper;
|
||||
@ -428,6 +436,7 @@ public:
|
||||
friend class Item_in_optimizer;
|
||||
friend class subselect_indexsubquery_engine;
|
||||
friend class subselect_hash_sj_engine;
|
||||
friend class subselect_partial_match_engine;
|
||||
};
|
||||
|
||||
|
||||
@ -462,7 +471,8 @@ public:
|
||||
|
||||
enum enum_engine_type {ABSTRACT_ENGINE, SINGLE_SELECT_ENGINE,
|
||||
UNION_ENGINE, UNIQUESUBQUERY_ENGINE,
|
||||
INDEXSUBQUERY_ENGINE, HASH_SJ_ENGINE};
|
||||
INDEXSUBQUERY_ENGINE, HASH_SJ_ENGINE,
|
||||
ROWID_MERGE_ENGINE, TABLE_SCAN_ENGINE};
|
||||
|
||||
subselect_engine(Item_subselect *si, select_result_interceptor *res)
|
||||
:thd(0)
|
||||
@ -635,8 +645,10 @@ public:
|
||||
virtual void print (String *str, enum_query_type query_type);
|
||||
bool change_result(Item_subselect *si, select_result_interceptor *result);
|
||||
bool no_tables();
|
||||
int index_lookup(); /* TIMOUR: this method needs refactoring. */
|
||||
int scan_table();
|
||||
bool copy_ref_key();
|
||||
int copy_ref_key_simple(); /* TIMOUR: this method needs refactoring. */
|
||||
bool no_rows() { return empty_result_set; }
|
||||
virtual enum_engine_type engine_type() { return UNIQUESUBQUERY_ENGINE; }
|
||||
};
|
||||
@ -705,50 +717,439 @@ inline bool Item_subselect::is_uncacheable() const
|
||||
|
||||
|
||||
/**
|
||||
Compute an IN predicate via a hash semi-join. The subquery is materialized
|
||||
during the first evaluation of the IN predicate. The IN predicate is executed
|
||||
via the functionality inherited from subselect_uniquesubquery_engine.
|
||||
Compute an IN predicate via a hash semi-join. This class is responsible for
|
||||
the materialization of the subquery, and the selection of the correct and
|
||||
optimal execution method (e.g. direct index lookup, or partial matching) for
|
||||
the IN predicate.
|
||||
*/
|
||||
|
||||
class subselect_hash_sj_engine: public subselect_uniquesubquery_engine
|
||||
class subselect_hash_sj_engine : public subselect_engine
|
||||
{
|
||||
protected:
|
||||
/* The table into which the subquery is materialized. */
|
||||
TABLE *tmp_table;
|
||||
/* TRUE if the subquery was materialized into a temp table. */
|
||||
bool is_materialized;
|
||||
/*
|
||||
The old engine already chosen at parse time and stored in permanent memory.
|
||||
Through this member we can re-create and re-prepare materialize_join for
|
||||
each execution of a prepared statement. We akso resuse the functionality
|
||||
each execution of a prepared statement. We also reuse the functionality
|
||||
of subselect_single_select_engine::[prepare | cols].
|
||||
*/
|
||||
subselect_single_select_engine *materialize_engine;
|
||||
/* The engine used to compute the IN predicate. */
|
||||
subselect_engine *lookup_engine;
|
||||
/*
|
||||
QEP to execute the subquery and materialize its result into a
|
||||
temporary table. Created during the first call to exec().
|
||||
*/
|
||||
JOIN *materialize_join;
|
||||
/* Temp table context of the outer select's JOIN. */
|
||||
TMP_TABLE_PARAM *tmp_param;
|
||||
|
||||
/* Keyparts of the only non-NULL composite index in a rowid merge. */
|
||||
MY_BITMAP non_null_key_parts;
|
||||
/* Keyparts of the single column indexes with NULL, one keypart per index. */
|
||||
MY_BITMAP partial_match_key_parts;
|
||||
uint count_partial_match_columns;
|
||||
uint count_null_only_columns;
|
||||
/*
|
||||
A conjunction of all the equality condtions between all pairs of expressions
|
||||
that are arguments of an IN predicate. We need these to post-filter some
|
||||
IN results because index lookups sometimes match values that are actually
|
||||
not equal to the search key in SQL terms.
|
||||
*/
|
||||
Item_cond_and *semi_join_conds;
|
||||
/* Possible execution strategies that can be used to compute hash semi-join.*/
|
||||
enum exec_strategy {
|
||||
UNDEFINED,
|
||||
COMPLETE_MATCH, /* Use regular index lookups. */
|
||||
PARTIAL_MATCH, /* Use some partial matching strategy. */
|
||||
PARTIAL_MATCH_MERGE, /* Use partial matching through index merging. */
|
||||
PARTIAL_MATCH_SCAN, /* Use partial matching through table scan. */
|
||||
IMPOSSIBLE /* Subquery materialization is not applicable. */
|
||||
};
|
||||
/* The chosen execution strategy. Computed after materialization. */
|
||||
exec_strategy strategy;
|
||||
protected:
|
||||
exec_strategy get_strategy_using_schema();
|
||||
exec_strategy get_strategy_using_data();
|
||||
size_t rowid_merge_buff_size(bool has_non_null_key,
|
||||
bool has_covering_null_row,
|
||||
MY_BITMAP *partial_match_key_parts);
|
||||
void choose_partial_match_strategy(bool has_non_null_key,
|
||||
bool has_covering_null_row,
|
||||
MY_BITMAP *partial_match_key_parts);
|
||||
bool make_semi_join_conds();
|
||||
subselect_uniquesubquery_engine* make_unique_engine();
|
||||
|
||||
public:
|
||||
subselect_hash_sj_engine(THD *thd, Item_subselect *in_predicate,
|
||||
subselect_single_select_engine *old_engine)
|
||||
:subselect_uniquesubquery_engine(thd, NULL, in_predicate, NULL),
|
||||
is_materialized(FALSE), materialize_engine(old_engine),
|
||||
materialize_join(NULL), tmp_param(NULL)
|
||||
{}
|
||||
subselect_single_select_engine *old_engine)
|
||||
:subselect_engine(in_predicate, NULL), tmp_table(NULL),
|
||||
is_materialized(FALSE), materialize_engine(old_engine), lookup_engine(NULL),
|
||||
materialize_join(NULL), count_partial_match_columns(0),
|
||||
count_null_only_columns(0), semi_join_conds(NULL), strategy(UNDEFINED)
|
||||
{
|
||||
set_thd(thd);
|
||||
}
|
||||
~subselect_hash_sj_engine();
|
||||
|
||||
bool init_permanent(List<Item> *tmp_columns);
|
||||
bool init_runtime();
|
||||
void cleanup();
|
||||
int prepare() { return 0; }
|
||||
int prepare() { return 0; } /* Override virtual function in base class. */
|
||||
int exec();
|
||||
virtual void print (String *str, enum_query_type query_type);
|
||||
virtual void print(String *str, enum_query_type query_type);
|
||||
uint cols()
|
||||
{
|
||||
return materialize_engine->cols();
|
||||
}
|
||||
uint8 uncacheable() { return UNCACHEABLE_DEPENDENT; }
|
||||
table_map upper_select_const_tables() { return 0; }
|
||||
bool no_rows() { return !tmp_table->file->stats.records; }
|
||||
virtual enum_engine_type engine_type() { return HASH_SJ_ENGINE; }
|
||||
/*
|
||||
TODO: factor out all these methods in a base subselect_index_engine class
|
||||
because all of them have dummy implementations and should never be called.
|
||||
*/
|
||||
void fix_length_and_dec(Item_cache** row);//=>base class
|
||||
void exclude(); //=>base class
|
||||
//=>base class
|
||||
bool change_result(Item_subselect *si, select_result_interceptor *result);
|
||||
bool no_tables();//=>base class
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
Distinguish the type od (0-based) row numbers from the type of the index into
|
||||
an array of row numbers.
|
||||
*/
|
||||
typedef ha_rows rownum_t;
|
||||
|
||||
|
||||
/*
|
||||
An Ordered_key is an in-memory table index that allows O(log(N)) time
|
||||
lookups of a multi-part key.
|
||||
|
||||
If the index is over a single column, then this column may contain NULLs, and
|
||||
the NULLs are stored and tested separately for NULL in O(1) via is_null().
|
||||
Multi-part indexes assume that the indexed columns do not contain NULLs.
|
||||
|
||||
TODO:
|
||||
= Due to the unnatural assymetry between single and multi-part indexes, it
|
||||
makes sense to somehow refactor or extend the class.
|
||||
|
||||
= This class can be refactored into a base abstract interface, and two
|
||||
subclasses:
|
||||
- one to represent single-column indexes, and
|
||||
- another to represent multi-column indexes.
|
||||
Such separation would allow slightly more efficient implementation of
|
||||
the single-column indexes.
|
||||
= The current design requires such indexes to be fully recreated for each
|
||||
PS (re)execution, however most of the comprising objects can be reused.
|
||||
*/
|
||||
|
||||
class Ordered_key : public Sql_alloc
|
||||
{
|
||||
protected:
|
||||
/*
|
||||
Index of the key in an array of keys. This index allows to
|
||||
construct (sub)sets of keys represented by bitmaps.
|
||||
*/
|
||||
uint keyid;
|
||||
/* The table being indexed. */
|
||||
TABLE *tbl;
|
||||
/* The columns being indexed. */
|
||||
Item_field **key_columns;
|
||||
/* Number of elements in 'key_columns' (number of key parts). */
|
||||
uint key_column_count;
|
||||
/*
|
||||
An expression, or sequence of expressions that forms the search key.
|
||||
The search key is a sequence when it is Item_row. Each element of the
|
||||
sequence is accessible via Item::element_index(int i).
|
||||
*/
|
||||
Item *search_key;
|
||||
|
||||
/* Value index related members. */
|
||||
/*
|
||||
The actual value index, consists of a sorted sequence of row numbers.
|
||||
*/
|
||||
rownum_t *key_buff;
|
||||
/* Number of elements in key_buff. */
|
||||
ha_rows key_buff_elements;
|
||||
/* Current element in 'key_buff'. */
|
||||
ha_rows cur_key_idx;
|
||||
/*
|
||||
Mapping from row numbers to row ids. The element row_num_to_rowid[i]
|
||||
contains a buffer with the rowid for the row numbered 'i'.
|
||||
The memory for this member is not maintanined by this class because
|
||||
all Ordered_key indexes of the same table share the same mapping.
|
||||
*/
|
||||
uchar *row_num_to_rowid;
|
||||
/*
|
||||
A sequence of predicates to compare the search key with the corresponding
|
||||
columns of a table row from the index.
|
||||
*/
|
||||
Item_func_lt **compare_pred;
|
||||
|
||||
/* Null index related members. */
|
||||
MY_BITMAP null_key;
|
||||
/* Count of NULLs per column. */
|
||||
ha_rows null_count;
|
||||
/* The row number that contains the first NULL in a column. */
|
||||
ha_rows min_null_row;
|
||||
/* The row number that contains the last NULL in a column. */
|
||||
ha_rows max_null_row;
|
||||
|
||||
protected:
|
||||
bool alloc_keys_buffers();
|
||||
/*
|
||||
Quick sort comparison function that compares two rows of the same table
|
||||
indentfied with their row numbers.
|
||||
*/
|
||||
int cmp_keys_by_row_data(rownum_t a, rownum_t b);
|
||||
static int cmp_keys_by_row_data_and_rownum(Ordered_key *key,
|
||||
rownum_t* a, rownum_t* b);
|
||||
|
||||
int cmp_key_with_search_key(rownum_t row_num);
|
||||
|
||||
public:
|
||||
Ordered_key(uint keyid_arg, TABLE *tbl_arg,
|
||||
Item *search_key_arg, ha_rows null_count_arg,
|
||||
ha_rows min_null_row_arg, ha_rows max_null_row_arg,
|
||||
uchar *row_num_to_rowid_arg);
|
||||
~Ordered_key();
|
||||
void cleanup();
|
||||
/* Initialize a multi-column index. */
|
||||
bool init(MY_BITMAP *columns_to_index);
|
||||
/* Initialize a single-column index. */
|
||||
bool init(int col_idx);
|
||||
|
||||
uint get_column_count() { return key_column_count; }
|
||||
uint get_keyid() { return keyid; }
|
||||
uint get_field_idx(uint i)
|
||||
{
|
||||
DBUG_ASSERT(i < key_column_count);
|
||||
return key_columns[i]->field->field_index;
|
||||
}
|
||||
/*
|
||||
Get the search key element that corresponds to the i-th key part of this
|
||||
index.
|
||||
*/
|
||||
Item *get_search_key(uint i)
|
||||
{
|
||||
return search_key->element_index(key_columns[i]->field->field_index);
|
||||
}
|
||||
void add_key(rownum_t row_num)
|
||||
{
|
||||
/* The caller must know how many elements to add. */
|
||||
DBUG_ASSERT(key_buff_elements && cur_key_idx < key_buff_elements);
|
||||
key_buff[cur_key_idx]= row_num;
|
||||
++cur_key_idx;
|
||||
}
|
||||
|
||||
void sort_keys();
|
||||
double null_selectivity();
|
||||
|
||||
/*
|
||||
Position the current element at the first row that matches the key.
|
||||
The key itself is propagated by evaluating the current value(s) of
|
||||
this->search_key.
|
||||
*/
|
||||
bool lookup();
|
||||
/* Move the current index cursor to the first key. */
|
||||
void first()
|
||||
{
|
||||
DBUG_ASSERT(key_buff_elements);
|
||||
cur_key_idx= 0;
|
||||
}
|
||||
/* TODO */
|
||||
bool next_same();
|
||||
/* Move the current index cursor to the next key. */
|
||||
bool next()
|
||||
{
|
||||
DBUG_ASSERT(key_buff_elements);
|
||||
if (cur_key_idx < key_buff_elements - 1)
|
||||
{
|
||||
++cur_key_idx;
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
};
|
||||
/* Return the current index element. */
|
||||
rownum_t current()
|
||||
{
|
||||
DBUG_ASSERT(key_buff_elements && cur_key_idx < key_buff_elements);
|
||||
return key_buff[cur_key_idx];
|
||||
}
|
||||
|
||||
void set_null(rownum_t row_num)
|
||||
{
|
||||
bitmap_set_bit(&null_key, row_num);
|
||||
}
|
||||
bool is_null(rownum_t row_num)
|
||||
{
|
||||
/*
|
||||
Indexes consisting of only NULLs do not have a bitmap buffer at all.
|
||||
Their only initialized member is 'n_bits', which is equal to the number
|
||||
of temp table rows.
|
||||
*/
|
||||
if (null_count == tbl->file->stats.records)
|
||||
{
|
||||
DBUG_ASSERT(tbl->file->stats.records == null_key.n_bits);
|
||||
return TRUE;
|
||||
}
|
||||
if (row_num > max_null_row || row_num < min_null_row)
|
||||
return FALSE;
|
||||
return bitmap_is_set(&null_key, row_num);
|
||||
}
|
||||
void print(String *str);
|
||||
};
|
||||
|
||||
|
||||
class subselect_partial_match_engine : public subselect_engine
|
||||
{
|
||||
protected:
|
||||
/* The temporary table that contains a materialized subquery. */
|
||||
TABLE *tmp_table;
|
||||
/*
|
||||
The engine used to check whether an IN predicate is TRUE or not. If not
|
||||
TRUE, then subselect_rowid_merge_engine further distinguishes between
|
||||
FALSE and UNKNOWN.
|
||||
*/
|
||||
subselect_uniquesubquery_engine *lookup_engine;
|
||||
/* A list of equalities between each pair of IN operands. */
|
||||
List<Item> *equi_join_conds;
|
||||
/*
|
||||
If there is a row, such that all its NULL-able components are NULL, this
|
||||
member is set to the number of covered columns. If there is no covering
|
||||
row, then this is 0.
|
||||
*/
|
||||
uint covering_null_row_width;
|
||||
protected:
|
||||
virtual bool partial_match()= 0;
|
||||
public:
|
||||
subselect_partial_match_engine(subselect_uniquesubquery_engine *engine_arg,
|
||||
TABLE *tmp_table_arg, Item_subselect *item_arg,
|
||||
select_result_interceptor *result_arg,
|
||||
List<Item> *equi_join_conds_arg,
|
||||
uint covering_null_row_width_arg);
|
||||
int prepare() { return 0; }
|
||||
int exec();
|
||||
void fix_length_and_dec(Item_cache**) {}
|
||||
uint cols() { /* TODO: what is the correct value? */ return 1; }
|
||||
uint8 uncacheable() { return UNCACHEABLE_DEPENDENT; }
|
||||
void exclude() {}
|
||||
table_map upper_select_const_tables() { return 0; }
|
||||
bool change_result(Item_subselect*, select_result_interceptor*)
|
||||
{ DBUG_ASSERT(FALSE); return false; }
|
||||
bool no_tables() { return false; }
|
||||
bool no_rows()
|
||||
{
|
||||
/*
|
||||
TODO: It is completely unclear what is the semantics of this
|
||||
method. The current result is computed so that the call to no_rows()
|
||||
from Item_in_optimizer::val_int() sets Item_in_optimizer::null_value
|
||||
correctly.
|
||||
*/
|
||||
return !(((Item_in_subselect *) item)->null_value);
|
||||
}
|
||||
void print(String*, enum_query_type);
|
||||
|
||||
friend void subselect_hash_sj_engine::cleanup();
|
||||
};
|
||||
|
||||
|
||||
class subselect_rowid_merge_engine: public subselect_partial_match_engine
|
||||
{
|
||||
protected:
|
||||
/*
|
||||
Mapping from row numbers to row ids. The rowids are stored sequentially
|
||||
in the array - rowid[i] is located in row_num_to_rowid + i * rowid_length.
|
||||
*/
|
||||
uchar *row_num_to_rowid;
|
||||
/*
|
||||
A subset of all the keys for which there is a match for the same row.
|
||||
Used during execution. Computed for each outer reference
|
||||
*/
|
||||
MY_BITMAP matching_keys;
|
||||
/*
|
||||
The columns of the outer reference that are NULL. Computed for each
|
||||
outer reference.
|
||||
*/
|
||||
MY_BITMAP matching_outer_cols;
|
||||
/*
|
||||
Columns that consist of only NULLs. Such columns match any value.
|
||||
Computed once per query execution.
|
||||
*/
|
||||
MY_BITMAP null_only_columns;
|
||||
/*
|
||||
Indexes of row numbers, sorted by <column_value, row_number>. If an
|
||||
index may contain NULLs, the NULLs are stored efficiently in a bitmap.
|
||||
|
||||
The indexes are sorted by the selectivity of their NULL sub-indexes, the
|
||||
one with the fewer NULLs is first. Thus, if there is any index on
|
||||
non-NULL columns, it is contained in keys[0].
|
||||
*/
|
||||
Ordered_key **merge_keys;
|
||||
/* The number of elements in keys. */
|
||||
uint keys_count;
|
||||
/*
|
||||
An index on all non-NULL columns of 'tmp_table'. The index has the
|
||||
logical form: <[v_i1 | ... | v_ik], rownum>. It allows to find the row
|
||||
number where the columns c_i1,...,c1_k contain the values v_i1,...,v_ik.
|
||||
If such an index exists, it is always the first element of 'keys'.
|
||||
*/
|
||||
Ordered_key *non_null_key;
|
||||
/*
|
||||
Priority queue of Ordered_key indexes, one per NULLable column.
|
||||
This queue is used by the partial match algorithm in method exec().
|
||||
*/
|
||||
QUEUE pq;
|
||||
protected:
|
||||
/*
|
||||
Comparison function to compare keys in order of decreasing bitmap
|
||||
selectivity.
|
||||
*/
|
||||
static int cmp_keys_by_null_selectivity(Ordered_key **k1, Ordered_key **k2);
|
||||
/*
|
||||
Comparison function used by the priority queue pq, the 'smaller' key
|
||||
is the one with the smaller current row number.
|
||||
*/
|
||||
static int cmp_keys_by_cur_rownum(void *arg, uchar *k1, uchar *k2);
|
||||
|
||||
bool test_null_row(rownum_t row_num);
|
||||
bool partial_match();
|
||||
public:
|
||||
subselect_rowid_merge_engine(subselect_uniquesubquery_engine *engine_arg,
|
||||
TABLE *tmp_table_arg, uint keys_count_arg,
|
||||
uint covering_null_row_width_arg,
|
||||
Item_subselect *item_arg,
|
||||
select_result_interceptor *result_arg,
|
||||
List<Item> *equi_join_conds_arg)
|
||||
:subselect_partial_match_engine(engine_arg, tmp_table_arg, item_arg,
|
||||
result_arg, equi_join_conds_arg,
|
||||
covering_null_row_width_arg),
|
||||
keys_count(keys_count_arg), non_null_key(NULL)
|
||||
{
|
||||
thd= lookup_engine->get_thd();
|
||||
}
|
||||
~subselect_rowid_merge_engine();
|
||||
bool init(MY_BITMAP *non_null_key_parts, MY_BITMAP *partial_match_key_parts);
|
||||
void cleanup();
|
||||
virtual enum_engine_type engine_type() { return ROWID_MERGE_ENGINE; }
|
||||
};
|
||||
|
||||
|
||||
class subselect_table_scan_engine: public subselect_partial_match_engine
|
||||
{
|
||||
protected:
|
||||
bool partial_match();
|
||||
public:
|
||||
subselect_table_scan_engine(subselect_uniquesubquery_engine *engine_arg,
|
||||
TABLE *tmp_table_arg, Item_subselect *item_arg,
|
||||
select_result_interceptor *result_arg,
|
||||
List<Item> *equi_join_conds_arg,
|
||||
uint covering_null_row_width_arg);
|
||||
void cleanup();
|
||||
virtual enum_engine_type engine_type() { return TABLE_SCAN_ENGINE; }
|
||||
};
|
||||
|
@ -552,12 +552,14 @@ protected:
|
||||
#define OPTIMIZER_SWITCH_LOOSE_SCAN 64
|
||||
#define OPTIMIZER_SWITCH_MATERIALIZATION 128
|
||||
#define OPTIMIZER_SWITCH_SEMIJOIN 256
|
||||
#define OPTIMIZER_SWITCH_PARTIAL_MATCH_ROWID_MERGE 512
|
||||
#define OPTIMIZER_SWITCH_PARTIAL_MATCH_TABLE_SCAN 1024
|
||||
|
||||
#ifdef DBUG_OFF
|
||||
# define OPTIMIZER_SWITCH_LAST 512
|
||||
# define OPTIMIZER_SWITCH_LAST 2048
|
||||
#else
|
||||
# define OPTIMIZER_SWITCH_TABLE_ELIMINATION 512
|
||||
# define OPTIMIZER_SWITCH_LAST 1024
|
||||
# define OPTIMIZER_SWITCH_TABLE_ELIMINATION 2048
|
||||
# define OPTIMIZER_SWITCH_LAST 4096
|
||||
#endif
|
||||
|
||||
#ifdef DBUG_OFF
|
||||
@ -570,8 +572,10 @@ protected:
|
||||
OPTIMIZER_SWITCH_FIRSTMATCH | \
|
||||
OPTIMIZER_SWITCH_LOOSE_SCAN | \
|
||||
OPTIMIZER_SWITCH_MATERIALIZATION | \
|
||||
OPTIMIZER_SWITCH_SEMIJOIN)
|
||||
#else
|
||||
OPTIMIZER_SWITCH_SEMIJOIN | \
|
||||
OPTIMIZER_SWITCH_PARTIAL_MATCH_ROWID_MERGE|\
|
||||
OPTIMIZER_SWITCH_PARTIAL_MATCH_TABLE_SCAN)
|
||||
#else
|
||||
# define OPTIMIZER_SWITCH_DEFAULT (OPTIMIZER_SWITCH_INDEX_MERGE | \
|
||||
OPTIMIZER_SWITCH_INDEX_MERGE_UNION | \
|
||||
OPTIMIZER_SWITCH_INDEX_MERGE_SORT_UNION | \
|
||||
@ -581,7 +585,9 @@ protected:
|
||||
OPTIMIZER_SWITCH_FIRSTMATCH | \
|
||||
OPTIMIZER_SWITCH_LOOSE_SCAN | \
|
||||
OPTIMIZER_SWITCH_MATERIALIZATION | \
|
||||
OPTIMIZER_SWITCH_SEMIJOIN)
|
||||
OPTIMIZER_SWITCH_SEMIJOIN | \
|
||||
OPTIMIZER_SWITCH_PARTIAL_MATCH_ROWID_MERGE|\
|
||||
OPTIMIZER_SWITCH_PARTIAL_MATCH_TABLE_SCAN)
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
@ -301,7 +301,9 @@ static const char *optimizer_switch_names[]=
|
||||
"index_merge","index_merge_union","index_merge_sort_union",
|
||||
"index_merge_intersection",
|
||||
"index_condition_pushdown",
|
||||
"firstmatch","loosescan","materialization", "semijoin",
|
||||
"firstmatch","loosescan","materialization", "semijoin",
|
||||
"partial_match_rowid_merge",
|
||||
"partial_match_table_scan",
|
||||
#ifndef DBUG_OFF
|
||||
"table_elimination",
|
||||
#endif
|
||||
@ -320,6 +322,8 @@ static const unsigned int optimizer_switch_names_len[]=
|
||||
sizeof("loosescan") - 1,
|
||||
sizeof("materialization") - 1,
|
||||
sizeof("semijoin") - 1,
|
||||
sizeof("partial_match_rowid_merge") - 1,
|
||||
sizeof("partial_match_table_scan") - 1,
|
||||
#ifndef DBUG_OFF
|
||||
sizeof("table_elimination") - 1,
|
||||
#endif
|
||||
@ -5794,7 +5798,8 @@ enum options_mysqld
|
||||
OPT_RECORD_RND_BUFFER, OPT_DIV_PRECINCREMENT, OPT_RELAY_LOG_SPACE_LIMIT,
|
||||
OPT_RELAY_LOG_PURGE,
|
||||
OPT_SLAVE_NET_TIMEOUT, OPT_SLAVE_COMPRESSED_PROTOCOL, OPT_SLOW_LAUNCH_TIME,
|
||||
OPT_SLAVE_TRANS_RETRIES, OPT_READONLY, OPT_DEBUGGING, OPT_DEBUG_FLUSH,
|
||||
OPT_SLAVE_TRANS_RETRIES, OPT_READONLY, OPT_ROWID_MERGE_BUFF_SIZE,
|
||||
OPT_DEBUGGING, OPT_DEBUG_FLUSH,
|
||||
OPT_SORT_BUFFER, OPT_TABLE_OPEN_CACHE, OPT_TABLE_DEF_CACHE,
|
||||
OPT_THREAD_CONCURRENCY, OPT_THREAD_CACHE_SIZE,
|
||||
OPT_TMP_TABLE_SIZE, OPT_THREAD_STACK,
|
||||
@ -7130,6 +7135,11 @@ The minimum value for this variable is 4096.",
|
||||
(uchar**) &max_system_variables.range_alloc_block_size, 0, GET_ULONG,
|
||||
REQUIRED_ARG, RANGE_ALLOC_BLOCK_SIZE, RANGE_ALLOC_BLOCK_SIZE,
|
||||
(longlong) ULONG_MAX, 0, 1024, 0},
|
||||
{"rowid_merge_buff_size", OPT_ROWID_MERGE_BUFF_SIZE,
|
||||
"The size of the buffers used [NOT] IN evaluation via partial matching.",
|
||||
(uchar**) &global_system_variables.rowid_merge_buff_size,
|
||||
(uchar**) &max_system_variables.rowid_merge_buff_size, 0, GET_ULONG,
|
||||
REQUIRED_ARG, 8*1024*1024L, 0, MAX_MEM_TABLE_SIZE/2, 0, 1, 0},
|
||||
{"read_buffer_size", OPT_RECORD_BUFFER,
|
||||
"Each thread that does a sequential scan allocates a buffer of this size for each table it scans. If you do many sequential scans, you may want to increase this value.",
|
||||
(uchar**) &global_system_variables.read_buff_size,
|
||||
|
@ -187,10 +187,10 @@ int check_and_do_in_subquery_rewrites(JOIN *join)
|
||||
does not call setup_subquery_materialization(). We could make
|
||||
SELECT ... FROM DUAL call that function but that doesn't seem
|
||||
to be the case that is worth handling.
|
||||
4. Subquery predicate is a top-level predicate
|
||||
(this implies it is not negated)
|
||||
TODO: this is a limitation that should be lifted once we
|
||||
implement correct NULL semantics (WL#3830)
|
||||
4. Either the subquery predicate is a top-level predicate, or at
|
||||
least one partial match strategy is enabled. If no partial match
|
||||
strategy is enabled, then materialization cannot be used for
|
||||
non-top-level queries because it cannot handle NULLs correctly.
|
||||
5. Subquery is non-correlated
|
||||
TODO:
|
||||
This is an overly restrictive condition. It can be extended to:
|
||||
@ -204,8 +204,8 @@ int check_and_do_in_subquery_rewrites(JOIN *join)
|
||||
(*) The subquery must be part of a SELECT statement. The current
|
||||
condition also excludes multi-table update statements.
|
||||
|
||||
We have to determine whether we will perform subquery materialization
|
||||
before calling the IN=>EXISTS transformation, so that we know whether to
|
||||
Determine whether we will perform subquery materialization before
|
||||
calling the IN=>EXISTS transformation, so that we know whether to
|
||||
perform the whole transformation or only that part of it which wraps
|
||||
Item_in_subselect in an Item_in_optimizer.
|
||||
*/
|
||||
@ -215,12 +215,14 @@ int check_and_do_in_subquery_rewrites(JOIN *join)
|
||||
select_lex->master_unit()->first_select()->leaf_tables && // 3
|
||||
thd->lex->sql_command == SQLCOM_SELECT && // *
|
||||
select_lex->outer_select()->leaf_tables && // 3A
|
||||
subquery_types_allow_materialization(in_subs))
|
||||
subquery_types_allow_materialization(in_subs) &&
|
||||
// psergey-todo: duplicated_subselect_card_check: where it's done?
|
||||
(in_subs->is_top_level_item() ||
|
||||
optimizer_flag(thd, OPTIMIZER_SWITCH_PARTIAL_MATCH_ROWID_MERGE) ||
|
||||
optimizer_flag(thd, OPTIMIZER_SWITCH_PARTIAL_MATCH_TABLE_SCAN)) &&//4
|
||||
!in_subs->is_correlated && // 5
|
||||
in_subs->exec_method == Item_in_subselect::NOT_TRANSFORMED) // 6
|
||||
{
|
||||
// psergey-todo: duplicated_subselect_card_check: where it's done?
|
||||
if (in_subs->is_top_level_item() && // 4
|
||||
!in_subs->is_correlated && // 5
|
||||
in_subs->exec_method == Item_in_subselect::NOT_TRANSFORMED) // 6
|
||||
in_subs->exec_method= Item_in_subselect::MATERIALIZATION;
|
||||
}
|
||||
|
||||
|
@ -540,6 +540,9 @@ static sys_var_long_ptr sys_query_cache_size(&vars, "query_cache_size",
|
||||
|
||||
static sys_var_thd_ulong sys_range_alloc_block_size(&vars, "range_alloc_block_size",
|
||||
&SV::range_alloc_block_size);
|
||||
static sys_var_thd_ulong sys_rowid_merge_buff_size(&vars, "rowid_merge_buff_size",
|
||||
&SV::rowid_merge_buff_size);
|
||||
|
||||
static sys_var_thd_ulong sys_query_alloc_block_size(&vars, "query_alloc_block_size",
|
||||
&SV::query_alloc_block_size,
|
||||
0, fix_thd_mem_root);
|
||||
|
@ -42,6 +42,7 @@
|
||||
|
||||
#include "sp_rcontext.h"
|
||||
#include "sp_cache.h"
|
||||
#include "sql_select.h" /* declares create_tmp_table() */
|
||||
|
||||
/*
|
||||
The following is used to initialise Table_ident with a internal
|
||||
@ -2877,6 +2878,71 @@ bool select_dumpvar::send_eof()
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
select_materialize_with_stats::
|
||||
create_result_table(THD *thd_arg, List<Item> *column_types,
|
||||
bool is_union_distinct, ulonglong options,
|
||||
const char *table_alias, bool bit_fields_as_long)
|
||||
{
|
||||
DBUG_ASSERT(table == 0);
|
||||
tmp_table_param.field_count= column_types->elements;
|
||||
tmp_table_param.bit_fields_as_long= bit_fields_as_long;
|
||||
|
||||
if (! (table= create_tmp_table(thd_arg, &tmp_table_param, *column_types,
|
||||
(ORDER*) 0, is_union_distinct, 1,
|
||||
options, HA_POS_ERROR, (char*) table_alias)))
|
||||
return TRUE;
|
||||
|
||||
col_stat= (Column_statistics*) table->in_use->alloc(table->s->fields *
|
||||
sizeof(Column_statistics));
|
||||
if (!stat)
|
||||
return TRUE;
|
||||
|
||||
cleanup();
|
||||
|
||||
table->file->extra(HA_EXTRA_WRITE_CACHE);
|
||||
table->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Override select_union::send_data to analyze each row for NULLs and to
|
||||
update null_statistics before sending data to the client.
|
||||
|
||||
@return TRUE if fatal error when sending data to the client
|
||||
@return FALSE on success
|
||||
*/
|
||||
|
||||
bool select_materialize_with_stats::send_data(List<Item> &items)
|
||||
{
|
||||
List_iterator_fast<Item> item_it(items);
|
||||
Item *cur_item;
|
||||
Column_statistics *cur_col_stat= col_stat;
|
||||
uint nulls_in_row= 0;
|
||||
|
||||
++count_rows;
|
||||
|
||||
while ((cur_item= item_it++))
|
||||
{
|
||||
if (cur_item->is_null())
|
||||
{
|
||||
++cur_col_stat->null_count;
|
||||
cur_col_stat->max_null_row= count_rows;
|
||||
if (!cur_col_stat->min_null_row)
|
||||
cur_col_stat->min_null_row= count_rows;
|
||||
++nulls_in_row;
|
||||
}
|
||||
++cur_col_stat;
|
||||
}
|
||||
if (nulls_in_row > max_nulls_in_row)
|
||||
max_nulls_in_row= nulls_in_row;
|
||||
|
||||
return select_union::send_data(items);
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
TMP_TABLE_PARAM
|
||||
****************************************************************************/
|
||||
|
@ -343,6 +343,8 @@ struct system_variables
|
||||
ulong mrr_buff_size;
|
||||
ulong div_precincrement;
|
||||
ulong sortbuff_size;
|
||||
/* Total size of all buffers used by the subselect_rowid_merge_engine. */
|
||||
ulong rowid_merge_buff_size;
|
||||
ulong thread_handling;
|
||||
ulong tx_isolation;
|
||||
ulong completion_type;
|
||||
@ -2740,19 +2742,20 @@ public:
|
||||
|
||||
class select_union :public select_result_interceptor
|
||||
{
|
||||
protected:
|
||||
TMP_TABLE_PARAM tmp_table_param;
|
||||
public:
|
||||
TABLE *table;
|
||||
|
||||
select_union() :table(0) {}
|
||||
select_union() :table(0) { tmp_table_param.init(); }
|
||||
int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
|
||||
bool send_data(List<Item> &items);
|
||||
bool send_eof();
|
||||
bool flush();
|
||||
|
||||
bool create_result_table(THD *thd, List<Item> *column_types,
|
||||
bool is_distinct, ulonglong options,
|
||||
const char *alias, bool bit_fields_as_long);
|
||||
virtual bool create_result_table(THD *thd, List<Item> *column_types,
|
||||
bool is_distinct, ulonglong options,
|
||||
const char *alias, bool bit_fields_as_long);
|
||||
};
|
||||
|
||||
/* Base subselect interface class */
|
||||
@ -2776,6 +2779,74 @@ public:
|
||||
bool send_data(List<Item> &items);
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
This class specializes select_union to collect statistics about the
|
||||
data stored in the temp table. Currently the class collects statistcs
|
||||
about NULLs.
|
||||
*/
|
||||
|
||||
class select_materialize_with_stats : public select_union
|
||||
{
|
||||
protected:
|
||||
class Column_statistics
|
||||
{
|
||||
public:
|
||||
/* Count of NULLs per column. */
|
||||
ha_rows null_count;
|
||||
/* The row number that contains the first NULL in a column. */
|
||||
ha_rows min_null_row;
|
||||
/* The row number that contains the last NULL in a column. */
|
||||
ha_rows max_null_row;
|
||||
};
|
||||
|
||||
/* Array of statistics data per column. */
|
||||
Column_statistics* col_stat;
|
||||
|
||||
/*
|
||||
The number of columns in the biggest sub-row that consists of only
|
||||
NULL values.
|
||||
*/
|
||||
ha_rows max_nulls_in_row;
|
||||
/*
|
||||
Count of rows writtent to the temp table. This is redundant as it is
|
||||
already stored in handler::stats.records, however that one is relatively
|
||||
expensive to compute (given we need that for evry row).
|
||||
*/
|
||||
ha_rows count_rows;
|
||||
|
||||
public:
|
||||
select_materialize_with_stats() {}
|
||||
virtual bool create_result_table(THD *thd, List<Item> *column_types,
|
||||
bool is_distinct, ulonglong options,
|
||||
const char *alias, bool bit_fields_as_long);
|
||||
bool init_result_table(ulonglong select_options);
|
||||
bool send_data(List<Item> &items);
|
||||
void cleanup()
|
||||
{
|
||||
memset(col_stat, 0, table->s->fields * sizeof(Column_statistics));
|
||||
max_nulls_in_row= 0;
|
||||
count_rows= 0;
|
||||
}
|
||||
ha_rows get_null_count_of_col(uint idx)
|
||||
{
|
||||
DBUG_ASSERT(idx < table->s->fields);
|
||||
return col_stat[idx].null_count;
|
||||
}
|
||||
ha_rows get_max_null_of_col(uint idx)
|
||||
{
|
||||
DBUG_ASSERT(idx < table->s->fields);
|
||||
return col_stat[idx].max_null_row;
|
||||
}
|
||||
ha_rows get_min_null_of_col(uint idx)
|
||||
{
|
||||
DBUG_ASSERT(idx < table->s->fields);
|
||||
return col_stat[idx].min_null_row;
|
||||
}
|
||||
ha_rows get_max_nulls_in_row() { return max_nulls_in_row; }
|
||||
};
|
||||
|
||||
|
||||
/* used in independent ALL/ANY optimisation */
|
||||
class select_max_min_finder_subselect :public select_subselect
|
||||
{
|
||||
|
@ -874,6 +874,9 @@ JOIN::optimize()
|
||||
{
|
||||
DBUG_PRINT("info",("No tables"));
|
||||
error= 0;
|
||||
/* Create all structures needed for materialized subquery execution. */
|
||||
if (setup_subquery_materialization())
|
||||
DBUG_RETURN(1);
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
error= -1; // Error is sent to client
|
||||
@ -11258,7 +11261,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
|
||||
param->group_buff=group_buff;
|
||||
share->keys=1;
|
||||
share->uniques= test(using_unique_constraint);
|
||||
table->key_info=keyinfo;
|
||||
table->key_info= table->s->key_info= keyinfo;
|
||||
keyinfo->key_part=key_part_info;
|
||||
keyinfo->flags=HA_NOSAME;
|
||||
keyinfo->usable_key_parts=keyinfo->key_parts= param->group_parts;
|
||||
@ -11344,7 +11347,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
|
||||
keyinfo->key_parts * sizeof(KEY_PART_INFO))))
|
||||
goto err;
|
||||
bzero((void*) key_part_info, keyinfo->key_parts * sizeof(KEY_PART_INFO));
|
||||
table->key_info=keyinfo;
|
||||
table->key_info= table->s->key_info= keyinfo;
|
||||
keyinfo->key_part=key_part_info;
|
||||
keyinfo->flags=HA_NOSAME | HA_NULL_ARE_EQUAL;
|
||||
keyinfo->key_length= 0; // Will compute the sum of the parts below.
|
||||
|
Reference in New Issue
Block a user