Browse Source
Subquery cache (MWL#66) added.
Subquery cache (MWL#66) added.
libmysqld/Makefile.am: The new file added. mysql-test/r/index_merge_myisam.result: subquery_cache optimization option added. mysql-test/r/myisam_mrr.result: subquery_cache optimization option added. mysql-test/r/subquery_cache.result: The subquery cache tests added. mysql-test/r/subselect3.result: Subquery cache switched off to avoid changing read statistics. mysql-test/r/subselect3_jcl6.result: Subquery cache switched off to avoid changing read statistics. mysql-test/r/subselect_no_mat.result: subquery_cache optimization option added. mysql-test/r/subselect_no_opts.result: subquery_cache optimization option added. mysql-test/r/subselect_no_semijoin.result: subquery_cache optimization option added. mysql-test/r/subselect_sj.result: subquery_cache optimization option added. mysql-test/r/subselect_sj_jcl6.result: subquery_cache optimization option added. mysql-test/t/subquery_cache.test: The subquery cache tests added. mysql-test/t/subselect3.test: Subquery cache switched off to avoid changing read statistics. sql/CMakeLists.txt: The new file added. sql/Makefile.am: The new files added. sql/item.cc: Expression cache item (Item_cache_wrapper) added. Item_ref and Item_field fixed for correct usage of result field and fast resolwing in SP. sql/item.h: Expression cache item (Item_cache_wrapper) added. Item_ref and Item_field fixed for correct usage of result field and fast resolwing in SP. sql/item_cmpfunc.cc: Subquery cache added. sql/item_cmpfunc.h: Subquery cache added. sql/item_subselect.cc: Subquery cache added. sql/item_subselect.h: Subquery cache added. sql/item_sum.cc: Registration of subquery parameters added. sql/mysql_priv.h: subquery_cache optimization option added. sql/mysqld.cc: subquery_cache optimization option added. sql/opt_range.cc: Fix due to subquery cache. sql/opt_subselect.cc: Parameters of the function cahnged. sql/procedure.h: .h file guard added. sql/sql_base.cc: Registration of subquery parameters added. sql/sql_class.cc: Option to allow add indeces to temporary table. sql/sql_class.h: Item iterators added. Option to allow add indeces to temporary table. sql/sql_expression_cache.cc: Expression cache for caching subqueries added. sql/sql_expression_cache.h: Expression cache for caching subqueries added. sql/sql_lex.cc: Registration of subquery parameters added. sql/sql_lex.h: Registration of subqueries and subquery parameters added. sql/sql_select.cc: Subquery cache added. sql/sql_select.h: Subquery cache added. sql/sql_union.cc: A new parameter to the function added. sql/sql_update.cc: A new parameter to the function added. sql/table.cc: Procedures to manage temporarty tables index added. sql/table.h: Procedures to manage temporarty tables index added. storage/maria/ha_maria.cc: Fix of handler to allow destoy a table in case of error during the table creation. storage/maria/ha_maria.h: .h file guard added. storage/myisam/ha_myisam.cc: Fix of handler to allow destoy a table in case of error during the table creation.pull/374/head
43 changed files with 4255 additions and 164 deletions
-
3libmysqld/Makefile.am
-
18mysql-test/r/index_merge_myisam.result
-
2mysql-test/r/myisam_mrr.result
-
1840mysql-test/r/subquery_cache.result
-
5mysql-test/r/subselect3.result
-
5mysql-test/r/subselect3_jcl6.result
-
4mysql-test/r/subselect_no_mat.result
-
4mysql-test/r/subselect_no_opts.result
-
4mysql-test/r/subselect_no_semijoin.result
-
18mysql-test/r/subselect_sj.result
-
18mysql-test/r/subselect_sj_jcl6.result
-
509mysql-test/t/subquery_cache.test
-
6mysql-test/t/subselect3.test
-
1sql/CMakeLists.txt
-
5sql/Makefile.am
-
554sql/item.cc
-
170sql/item.h
-
39sql/item_cmpfunc.cc
-
1sql/item_cmpfunc.h
-
150sql/item_subselect.cc
-
22sql/item_subselect.h
-
1sql/item_sum.cc
-
23sql/mysql_priv.h
-
20sql/mysqld.cc
-
4sql/opt_range.cc
-
3sql/opt_subselect.cc
-
4sql/procedure.h
-
30sql/sql_base.cc
-
1sql/sql_class.cc
-
77sql/sql_class.h
-
314sql/sql_expression_cache.cc
-
80sql/sql_expression_cache.h
-
51sql/sql_lex.cc
-
6sql/sql_lex.h
-
260sql/sql_select.cc
-
29sql/sql_select.h
-
2sql/sql_union.cc
-
2sql/sql_update.cc
-
122sql/table.cc
-
4sql/table.h
-
2storage/maria/ha_maria.cc
-
4storage/maria/ha_maria.h
-
2storage/myisam/ha_myisam.cc
1840
mysql-test/r/subquery_cache.result
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -0,0 +1,509 @@ |
|||
|
|||
set optimizer_switch='subquery_cache=on'; |
|||
|
|||
create table t1 (a int, b int); |
|||
insert into t1 values (1,2),(3,4),(1,2),(3,4),(3,4),(4,5),(4,5),(5,6),(5,6),(4,5); |
|||
create table t2 (c int, d int); |
|||
insert into t2 values (2,3),(3,4),(5,6),(4,1); |
|||
|
|||
--echo * |
|||
--echo * Test subquery as top item in different clauses |
|||
--echo * |
|||
--echo #single value subquery test (SELECT list) |
|||
flush status; |
|||
select a, (select d from t2 where b=c) from t1; |
|||
|
|||
show status like "subquery_cache%"; |
|||
show status like '%Handler_read%'; |
|||
|
|||
set optimizer_switch='subquery_cache=off'; |
|||
flush status; |
|||
|
|||
select a, (select d from t2 where b=c) from t1; |
|||
|
|||
show status like "subquery_cache%"; |
|||
show status like '%Handler_read%'; |
|||
set optimizer_switch='subquery_cache=on'; |
|||
|
|||
|
|||
--echo #single value subquery test (where) |
|||
flush status; |
|||
select a from t1 where (select d from t2 where b=c); |
|||
|
|||
show status like "subquery_cache%"; |
|||
show status like '%Handler_read%'; |
|||
|
|||
set optimizer_switch='subquery_cache=off'; |
|||
flush status; |
|||
|
|||
select a from t1 where (select d from t2 where b=c); |
|||
|
|||
show status like "subquery_cache%"; |
|||
show status like '%Handler_read%'; |
|||
set optimizer_switch='subquery_cache=on'; |
|||
|
|||
--echo #single value subquery test (having) |
|||
flush status; |
|||
select a from t1 where a > 0 having (select d from t2 where b=c); |
|||
|
|||
show status like "subquery_cache%"; |
|||
show status like '%Handler_read%'; |
|||
|
|||
set optimizer_switch='subquery_cache=off'; |
|||
flush status; |
|||
|
|||
select a from t1 where a > 0 having (select d from t2 where b=c); |
|||
|
|||
show status like "subquery_cache%"; |
|||
show status like '%Handler_read%'; |
|||
set optimizer_switch='subquery_cache=on'; |
|||
|
|||
--echo #single value subquery test (OUTER JOIN ON) |
|||
flush status; |
|||
select ta.a, tb.a from t1 ta join t1 tb on (select d from t2 where tb.b=c); |
|||
|
|||
show status like "subquery_cache%"; |
|||
show status like '%Handler_read%'; |
|||
|
|||
set optimizer_switch='subquery_cache=off'; |
|||
flush status; |
|||
|
|||
select ta.a, tb.a from t1 ta join t1 tb on (select d from t2 where tb.b=c); |
|||
|
|||
show status like "subquery_cache%"; |
|||
show status like '%Handler_read%'; |
|||
set optimizer_switch='subquery_cache=on'; |
|||
|
|||
--echo #single value subquery test (GROUP BY) |
|||
flush status; |
|||
select max(a) from t1 GROUP BY (select d from t2 where b=c); |
|||
|
|||
show status like "subquery_cache%"; |
|||
show status like '%Handler_read%'; |
|||
set optimizer_switch='subquery_cache=off'; |
|||
|
|||
flush status; |
|||
select max(a) from t1 GROUP BY (select d from t2 where b=c); |
|||
|
|||
show status like "subquery_cache%"; |
|||
show status like '%Handler_read%'; |
|||
set optimizer_switch='subquery_cache=on'; |
|||
|
|||
--echo #single value subquery test (distinct GROUP BY) |
|||
flush status; |
|||
select distinct max(a) from t1 GROUP BY (select d from t2 where b=c); |
|||
|
|||
show status like "subquery_cache%"; |
|||
show status like '%Handler_read%'; |
|||
set optimizer_switch='subquery_cache=off'; |
|||
|
|||
flush status; |
|||
select distinct max(a) from t1 GROUP BY (select d from t2 where b=c); |
|||
|
|||
show status like "subquery_cache%"; |
|||
show status like '%Handler_read%'; |
|||
set optimizer_switch='subquery_cache=on'; |
|||
|
|||
--echo #single value subquery test (ORDER BY) |
|||
flush status; |
|||
select a from t1 ORDER BY (select d from t2 where b=c); |
|||
|
|||
show status like "subquery_cache%"; |
|||
show status like '%Handler_read%'; |
|||
set optimizer_switch='subquery_cache=off'; |
|||
|
|||
flush status; |
|||
select a from t1 ORDER BY (select d from t2 where b=c); |
|||
|
|||
show status like "subquery_cache%"; |
|||
show status like '%Handler_read%'; |
|||
set optimizer_switch='subquery_cache=on'; |
|||
|
|||
--echo #single value subquery test (distinct ORDER BY) |
|||
flush status; |
|||
select distinct a from t1 ORDER BY (select d from t2 where b=c); |
|||
|
|||
show status like "subquery_cache%"; |
|||
show status like '%Handler_read%'; |
|||
set optimizer_switch='subquery_cache=off'; |
|||
|
|||
flush status; |
|||
select distinct a from t1 ORDER BY (select d from t2 where b=c); |
|||
|
|||
show status like "subquery_cache%"; |
|||
show status like '%Handler_read%'; |
|||
set optimizer_switch='subquery_cache=on'; |
|||
|
|||
--echo #single value subquery test (LEFT JOIN ON) |
|||
flush status; |
|||
select ta.a, tb.a from t1 ta left join t1 tb on (select d from t2 where tb.b=c); |
|||
|
|||
show status like "subquery_cache%"; |
|||
show status like '%Handler_read%'; |
|||
|
|||
set optimizer_switch='subquery_cache=off'; |
|||
flush status; |
|||
|
|||
select ta.a, tb.a from t1 ta left join t1 tb on (select d from t2 where tb.b=c); |
|||
|
|||
show status like "subquery_cache%"; |
|||
show status like '%Handler_read%'; |
|||
set optimizer_switch='subquery_cache=on'; |
|||
|
|||
--echo #single value subquery test (PS) |
|||
prepare stmt1 from 'select a, (select d from t2 where b=c) + 1 from t1'; |
|||
execute stmt1; |
|||
show status like "subquery_cache%"; |
|||
execute stmt1; |
|||
show status like "subquery_cache%"; |
|||
deallocate prepare stmt1; |
|||
|
|||
--echo #single value subquery test (SP) |
|||
CREATE PROCEDURE p1() select a, (select d from t2 where b=c) + 1 from t1; |
|||
|
|||
call p1; |
|||
call p1; |
|||
|
|||
drop procedure p1; |
|||
|
|||
--echo #IN subquery test |
|||
flush status; |
|||
|
|||
show status like "subquery_cache%"; |
|||
select a, b , b in (select d from t2) as SUBS from t1; |
|||
show status like "subquery_cache%"; |
|||
|
|||
insert into t1 values (7,8),(9,NULL); |
|||
select a, b , b in (select d from t2) as SUBS from t1; |
|||
show status like "subquery_cache%"; |
|||
|
|||
insert into t2 values (8,NULL); |
|||
select a, b , b in (select d from t2) as SUBS from t1; |
|||
show status like "subquery_cache%"; |
|||
|
|||
--echo # multicolumn NOT IN with NULLs |
|||
flush status; |
|||
set optimizer_switch='subquery_cache=off'; |
|||
select a, b, (b, a) not in (select d, c from t2) as SUBS from t1; |
|||
show status like "subquery_cache%"; |
|||
|
|||
set optimizer_switch='subquery_cache=on'; |
|||
select a, b, (b, a) not in (select d, c from t2) as SUBS from t1; |
|||
show status like "subquery_cache%"; |
|||
|
|||
--echo # multicolumn NOT IN with NULLs (other order) |
|||
flush status; |
|||
set optimizer_switch='subquery_cache=off'; |
|||
select a, b, (a, b) not in (select d, c from t2) as SUBS from t1; |
|||
show status like "subquery_cache%"; |
|||
|
|||
set optimizer_switch='subquery_cache=on'; |
|||
select a, b, (a, b) not in (select d, c from t2) as SUBS from t1; |
|||
show status like "subquery_cache%"; |
|||
|
|||
--echo # multicolumn IN with NULLs |
|||
flush status; |
|||
set optimizer_switch='subquery_cache=off'; |
|||
select a, b, (b, a) in (select d, c from t2) as SUBS from t1; |
|||
show status like "subquery_cache%"; |
|||
|
|||
set optimizer_switch='subquery_cache=on'; |
|||
select a, b, (b, a) in (select d, c from t2) as SUBS from t1; |
|||
show status like "subquery_cache%"; |
|||
|
|||
--echo # multicolumn IN with NULLs (other order) |
|||
flush status; |
|||
set optimizer_switch='subquery_cache=off'; |
|||
select a, b, (a, b) in (select d, c from t2) as SUBS from t1; |
|||
show status like "subquery_cache%"; |
|||
|
|||
set optimizer_switch='subquery_cache=on'; |
|||
select a, b, (a, b) in (select d, c from t2) as SUBS from t1; |
|||
show status like "subquery_cache%"; |
|||
|
|||
--echo #IN subquery test (PS) |
|||
delete from t1 where a > 6; |
|||
delete from t2 where c > 6; |
|||
|
|||
prepare stmt1 from 'select a, b , b in (select d from t2) as SUBS from t1'; |
|||
execute stmt1; |
|||
show status like "subquery_cache%"; |
|||
execute stmt1; |
|||
show status like "subquery_cache%"; |
|||
|
|||
insert into t1 values (7,8),(9,NULL); |
|||
execute stmt1; |
|||
show status like "subquery_cache%"; |
|||
execute stmt1; |
|||
show status like "subquery_cache%"; |
|||
|
|||
insert into t2 values (8,NULL); |
|||
execute stmt1; |
|||
show status like "subquery_cache%"; |
|||
execute stmt1; |
|||
show status like "subquery_cache%"; |
|||
|
|||
deallocate prepare stmt1; |
|||
|
|||
|
|||
--echo #IN subquery test (SP) |
|||
delete from t1 where a > 6; |
|||
delete from t2 where c > 6; |
|||
|
|||
CREATE PROCEDURE p1() select a, b , b in (select d from t2) as SUBS from t1; |
|||
|
|||
call p1(); |
|||
show status like "subquery_cache%"; |
|||
call p1(); |
|||
show status like "subquery_cache%"; |
|||
|
|||
insert into t1 values (7,8),(9,NULL); |
|||
call p1(); |
|||
show status like "subquery_cache%"; |
|||
call p1(); |
|||
show status like "subquery_cache%"; |
|||
|
|||
insert into t2 values (8,NULL); |
|||
call p1(); |
|||
show status like "subquery_cache%"; |
|||
call p1(); |
|||
show status like "subquery_cache%"; |
|||
|
|||
drop procedure p1; |
|||
|
|||
|
|||
--echo # test of simple exists |
|||
select a, b , exists (select * from t2 where b=d) as SUBS from t1; |
|||
|
|||
--echo # test of prepared statement exists |
|||
show status like "subquery_cache%"; |
|||
prepare stmt1 from 'select a, b , exists (select * from t2 where b=d) as SUBS from t1'; |
|||
execute stmt1; |
|||
show status like "subquery_cache%"; |
|||
execute stmt1; |
|||
show status like "subquery_cache%"; |
|||
deallocate prepare stmt1; |
|||
|
|||
--echo # test of stored procedure exists |
|||
CREATE PROCEDURE p1() select a, b , exists (select * from t2 where b=d) as SUBS from t1; |
|||
call p1; |
|||
call p1; |
|||
drop procedure p1; |
|||
|
|||
--echo #several subqueries |
|||
set optimizer_switch='subquery_cache=off'; |
|||
flush status; |
|||
select a, b , exists (select * from t2 where b=d) as SUBSE, b in (select d from t2) as SUBSI, (select d from t2 where b=c) SUBSR from t1; |
|||
show status like "subquery_cache%"; |
|||
show status like '%Handler_read%'; |
|||
|
|||
set optimizer_switch='subquery_cache=on'; |
|||
flush status; |
|||
select a, b , exists (select * from t2 where b=d) as SUBSE, b in (select d from t2) as SUBSI, (select d from t2 where b=c) SUBSR from t1; |
|||
show status like "subquery_cache%"; |
|||
show status like '%Handler_read%'; |
|||
|
|||
--echo #several subqueries (several levels) |
|||
set optimizer_switch='subquery_cache=off'; |
|||
flush status; |
|||
|
|||
set optimizer_switch='subquery_cache=off'; |
|||
flush status; |
|||
select a, b, (select exists (select * from t2 where b=d) from t2 where b=c) as SUNS1 from t1; |
|||
show status like "subquery_cache%"; |
|||
show status like '%Handler_read%'; |
|||
|
|||
|
|||
set optimizer_switch='subquery_cache=on'; |
|||
flush status; |
|||
select a, b, (select exists (select * from t2 where b=d) from t2 where b=c) as SUNS1 from t1; |
|||
show status like "subquery_cache%"; |
|||
show status like '%Handler_read%'; |
|||
|
|||
|
|||
--echo #clean up |
|||
drop table t1,t2; |
|||
|
|||
--echo test different types |
|||
--echo #int |
|||
CREATE TABLE t1 ( a int, b int); |
|||
INSERT INTO t1 VALUES(1,1),(2,2),(3,3); |
|||
SELECT a FROM t1 WHERE NOT a IN (SELECT a FROM t1 WHERE b = 2); |
|||
DROP TABLE t1; |
|||
|
|||
--echo #char |
|||
CREATE TABLE t1 ( a char(1), b char (1)); |
|||
INSERT INTO t1 VALUES('1','1'),('2','2'),('3','3'); |
|||
SELECT a FROM t1 WHERE NOT a IN (SELECT a FROM t1 WHERE b = '2'); |
|||
DROP TABLE t1; |
|||
|
|||
--echo #decimal |
|||
CREATE TABLE t1 ( a decimal(3,1), b decimal(3,1)); |
|||
INSERT INTO t1 VALUES(1,1),(2,2),(3,3); |
|||
SELECT a FROM t1 WHERE NOT a IN (SELECT a FROM t1 WHERE b = 2); |
|||
DROP TABLE t1; |
|||
|
|||
--echo #date |
|||
CREATE TABLE t1 ( a date, b date); |
|||
INSERT INTO t1 VALUES('1000-01-01','1000-01-01'),('2000-02-01','2000-02-01'),('3000-03-03','3000-03-03'); |
|||
SELECT a FROM t1 WHERE NOT a IN (SELECT a FROM t1 WHERE b = '2000-02-01'); |
|||
DROP TABLE t1; |
|||
|
|||
--echo #datetime |
|||
CREATE TABLE t1 ( a datetime, b datetime); |
|||
INSERT INTO t1 VALUES('1000-01-01 01:01:01','1000-01-01 01:01:01'),('2000-02-02 02:02:02','2000-02-02 02:02:02'),('3000-03-03 03:03:03','3000-03-03 03:03:03'); |
|||
SELECT a FROM t1 WHERE NOT a IN (SELECT a FROM t1 WHERE b = '2000-02-02 02:02:02'); |
|||
DROP TABLE t1; |
|||
|
|||
--echo #time |
|||
CREATE TABLE t1 ( a time, b time); |
|||
INSERT INTO t1 VALUES('01:01:01','01:01:01'),('02:02:02','02:02:02'),('03:03:03','03:03:03'); |
|||
SELECT a FROM t1 WHERE NOT a IN (SELECT a FROM t1 WHERE b = '02:02:02'); |
|||
DROP TABLE t1; |
|||
|
|||
--echo #timestamp |
|||
CREATE TABLE t1 ( a timestamp, b timestamp); |
|||
INSERT INTO t1 VALUES('2000-02-02 01:01:01','2000-02-02 01:01:01'),('2000-02-02 02:02:02','2000-02-02 02:02:02'),('2000-02-02 03:03:03','2000-02-02 03:03:03'); |
|||
SELECT a FROM t1 WHERE NOT a IN (SELECT a FROM t1 WHERE b = '2000-02-02 02:02:02'); |
|||
DROP TABLE t1; |
|||
|
|||
--echo #bit |
|||
CREATE TABLE t1 ( a bit(20), b bit(20)); |
|||
INSERT INTO t1 VALUES(1,1),(2,2),(3,3); |
|||
SELECT a+0 FROM t1 WHERE NOT a IN (SELECT a FROM t1 WHERE b = 2); |
|||
DROP TABLE t1; |
|||
|
|||
--echo #enum |
|||
CREATE TABLE t1 ( a enum('1','2','3'), b enum('1','2','3')); |
|||
INSERT INTO t1 VALUES('1','1'),('2','2'),('3','3'); |
|||
SELECT a FROM t1 WHERE NOT a IN (SELECT a FROM t1 WHERE b = '2'); |
|||
DROP TABLE t1; |
|||
|
|||
--echo #set |
|||
CREATE TABLE t1 ( a set('1','2','3'), b set('1','2','3')); |
|||
INSERT INTO t1 VALUES('1','1'),('2','2'),('3','3'); |
|||
SELECT a FROM t1 WHERE NOT a IN (SELECT a FROM t1 WHERE b = '2'); |
|||
DROP TABLE t1; |
|||
|
|||
--echo #blob |
|||
CREATE TABLE t1 ( a blob, b blob); |
|||
INSERT INTO t1 VALUES('1','1'),('2','2'),('3','3'); |
|||
SELECT a FROM t1 WHERE NOT a IN (SELECT a FROM t1 WHERE b = '2'); |
|||
DROP TABLE t1; |
|||
|
|||
--echo #geometry |
|||
CREATE TABLE t1 ( a geometry, b geometry); |
|||
INSERT INTO t1 VALUES(POINT(1,1),POINT(1,1)),(POINT(2,2),POINT(2,2)),(POINT(3,3),POINT(3,3)); |
|||
SELECT astext(a) FROM t1 WHERE NOT a IN (SELECT a FROM t1 WHERE b = POINT(2,2)); |
|||
DROP TABLE t1; |
|||
|
|||
|
|||
--echo #uncacheable queries test (random and side effect) |
|||
flush status; |
|||
CREATE TABLE t1 (a int); |
|||
INSERT INTO t1 VALUES (2), (4), (1), (3); |
|||
select a, a in (select a from t1) from t1 as ext; |
|||
show status like "subquery_cache%"; |
|||
select a, a in (select a from t1 where -1 < rand()) from t1 as ext; |
|||
show status like "subquery_cache%"; |
|||
select a, a in (select a from t1 where -1 < benchmark(a,100)) from t1 as ext; |
|||
show status like "subquery_cache%"; |
|||
drop table t1; |
|||
|
|||
--echo #test of sql_big_tables switch and outer table reference in subquery with grouping |
|||
set option sql_big_tables=1; |
|||
CREATE TABLE t1 (a INT PRIMARY KEY, b INT); |
|||
INSERT INTO t1 VALUES (1,1),(2,1),(3,2),(4,2),(5,3),(6,3); |
|||
SELECT (SELECT t1_outer.a FROM t1 AS t1_inner GROUP BY b LIMIT 1) FROM t1 AS t1_outer; |
|||
drop table t1; |
|||
set option sql_big_tables=0; |
|||
|
|||
--echo #test of function reference to outer query |
|||
set local group_concat_max_len=400; |
|||
create table t2 (a int, b int); |
|||
insert into t2 values (1,1), (2,2); |
|||
select b x, (select group_concat(x) from t2) from t2; |
|||
drop table t2; |
|||
set local group_concat_max_len=default; |
|||
|
|||
--echo #aggregate functions |
|||
CREATE TABLE t1 (a int, b INT); |
|||
CREATE TABLE t2 (c int, d INT); |
|||
|
|||
insert into t1 values (2,1), (3,1), (2,4), (3,4), (10,2), (20,2), (2,5), |
|||
(3,5), (100,3), (200,3), (10,6), (20,6), (20,7), (100,8), (200,8); |
|||
insert into t2 values (1,1),(3,3),(20,20); |
|||
|
|||
--echo aggregate function as parameter of subquery |
|||
set optimizer_switch='subquery_cache=off'; |
|||
flush status; |
|||
select max(a), (select max(a) from t2 where max(a)=c) from t1 group by b; |
|||
show status like "subquery_cache%"; |
|||
show status like '%Handler_read%'; |
|||
set optimizer_switch='subquery_cache=on'; |
|||
flush status; |
|||
select max(a), (select max(a) from t2 where max(a)=c) from t1 group by b; |
|||
show status like "subquery_cache%"; |
|||
show status like '%Handler_read%'; |
|||
|
|||
--echo argument of aggregate function as parameter of subquery (illegal use) |
|||
set optimizer_switch='subquery_cache=off'; |
|||
flush status; |
|||
select max(a), (select a from t2 where a=c) from t1 group by b; |
|||
show status like "subquery_cache%"; |
|||
show status like '%Handler_read%'; |
|||
|
|||
set optimizer_switch='subquery_cache=on'; |
|||
flush status; |
|||
select max(a), (select a from t2 where a=c) from t1 group by b; |
|||
show status like "subquery_cache%"; |
|||
show status like '%Handler_read%'; |
|||
|
|||
drop table t1,t2; |
|||
|
|||
--echo #test of flattening subquery optimisations and cache |
|||
create table t0 (a int); |
|||
insert into t0 values (9),(8),(7),(6),(5),(4),(3),(2),(1),(0); |
|||
|
|||
create table t1(a int, b int); |
|||
insert into t1 values |
|||
(0,0),(1,1),(2,2),(0,0),(1,1),(2,2),(0,0),(1,1),(2,2),(0,0),(1,1),(2,2),(0,0),(1,1),(2,2); |
|||
|
|||
create table t2 (pk int, a int, primary key(pk)); |
|||
insert into t2 select a,a from t0; |
|||
|
|||
set optimizer_switch='default,semijoin=on,materialization=on,subquery_cache=on'; |
|||
flush status; |
|||
select * from t1 where a in (select pk from t2); |
|||
show status like "subquery_cache%"; |
|||
show status like '%Handler_read%'; |
|||
|
|||
alter table t2 drop primary key; |
|||
set optimizer_switch='default,semijoin=off,materialization=off,subquery_cache=off'; |
|||
|
|||
explain select * from t1 where a in (select pk from t2); |
|||
flush status; |
|||
select * from t1 where a in (select pk from t2); |
|||
show status like "subquery_cache%"; |
|||
show status like '%Handler_read%'; |
|||
|
|||
set optimizer_switch='default,semijoin=off,materialization=off,subquery_cache=on'; |
|||
|
|||
explain select * from t1 where a in (select pk from t2); |
|||
flush status; |
|||
select * from t1 where a in (select pk from t2); |
|||
show status like "subquery_cache%"; |
|||
show status like '%Handler_read%'; |
|||
|
|||
#TODO: switch off cache if materialization used |
|||
set optimizer_switch='default,semijoin=off,materialization=on,subquery_cache=on'; |
|||
|
|||
explain select * from t1 where a in (select pk from t2); |
|||
flush status; |
|||
select * from t1 where a in (select pk from t2); |
|||
show status like "subquery_cache%"; |
|||
show status like '%Handler_read%'; |
|||
|
|||
drop table t0,t1,t2; |
|||
|
|||
set optimizer_switch='default'; |
|||
@ -0,0 +1,314 @@ |
|||
|
|||
#include "mysql_priv.h"
|
|||
#include "sql_select.h"
|
|||
|
|||
/*
|
|||
Expression cache is used only for caching subqueries now, so its statistic |
|||
variables we call subquery_cache*. |
|||
*/ |
|||
ulonglong subquery_cache_miss, subquery_cache_hit; |
|||
|
|||
Expression_cache_tmptable::Expression_cache_tmptable(THD *thd, |
|||
List<Item*> &dependants, |
|||
Item *value) |
|||
:cache_table(NULL), table_thd(thd), list(&dependants), val(value), |
|||
equalities(NULL), inited (0) |
|||
{ |
|||
DBUG_ENTER("Expression_cache_tmptable::Expression_cache_tmptable"); |
|||
DBUG_VOID_RETURN; |
|||
}; |
|||
|
|||
|
|||
/**
|
|||
Build and of equalities for the expression's parameters of certain types |
|||
|
|||
@details |
|||
If the temporary table used as an expression cache contains fields of |
|||
certain types then it's not enough to perform a lookup into the table to |
|||
verify that there is no row in the table for a given set of parameters. |
|||
Additionally for those fields we have to check equalities of the form |
|||
fld=val, where val is the value of the parameter stored in the column |
|||
fld. |
|||
The function generates a conjunction of all such equality predicates |
|||
and saves a pointer to it in the field 'equalities'. |
|||
|
|||
@retval FALSE OK |
|||
@retval TRUE Error |
|||
*/ |
|||
|
|||
bool Expression_cache_tmptable::make_equalities() |
|||
{ |
|||
List<Item> args; |
|||
List_iterator_fast<Item*> li(*list); |
|||
Item **ref; |
|||
Name_resolution_context *cn= NULL; |
|||
DBUG_ENTER("Expression_cache_tmptable::make_equalities"); |
|||
|
|||
for (uint i= 1 /* skip result filed */; (ref= li++); i++) |
|||
{ |
|||
Field *fld= cache_table->field[i]; |
|||
/* Only some field types should be checked after lookup */ |
|||
if (fld->type() == MYSQL_TYPE_VARCHAR || |
|||
fld->type() == MYSQL_TYPE_TINY_BLOB || |
|||
fld->type() == MYSQL_TYPE_MEDIUM_BLOB || |
|||
fld->type() == MYSQL_TYPE_LONG_BLOB || |
|||
fld->type() == MYSQL_TYPE_BLOB || |
|||
fld->type() == MYSQL_TYPE_VAR_STRING || |
|||
fld->type() == MYSQL_TYPE_STRING || |
|||
fld->type() == MYSQL_TYPE_NEWDECIMAL || |
|||
fld->type() == MYSQL_TYPE_DECIMAL) |
|||
{ |
|||
if (!cn) |
|||
{ |
|||
// dummy resolution context
|
|||
cn= new Name_resolution_context(); |
|||
cn->init(); |
|||
} |
|||
args.push_front(new Item_func_eq(new Item_ref(cn, ref, "", "", FALSE), |
|||
new Item_field(fld))); |
|||
} |
|||
} |
|||
if (args.elements == 1) |
|||
equalities= args.head(); |
|||
else |
|||
equalities= new Item_cond_and(args); |
|||
|
|||
DBUG_RETURN(equalities->fix_fields(table_thd, &equalities)); |
|||
} |
|||
|
|||
|
|||
/**
|
|||
Field enumerator for TABLE::add_tmp_key |
|||
|
|||
@param arg reference variable with current field number |
|||
|
|||
@return field number |
|||
*/ |
|||
|
|||
static uint field_enumerator(uchar *arg) |
|||
{ |
|||
return ((uint*)arg)[0]++; |
|||
} |
|||
|
|||
|
|||
/**
|
|||
Initialize temporary table and auxiliary structures for the expression |
|||
cache |
|||
|
|||
@details |
|||
The function creates a temporary table for the expression cache, defines |
|||
the search index and initializes auxiliary search structures used to check |
|||
whether a given set of of values of the expression parameters is in some |
|||
cache entry. |
|||
*/ |
|||
|
|||
void Expression_cache_tmptable::init() |
|||
{ |
|||
List_iterator_fast<Item*> li(*list); |
|||
Item_iterator_ref_list it(li); |
|||
Item **item; |
|||
uint field_counter; |
|||
DBUG_ENTER("Expression_cache_tmptable::init"); |
|||
DBUG_ASSERT(!inited); |
|||
inited= TRUE; |
|||
|
|||
if (!(ULONGLONG_MAX >> (list->elements + 1))) |
|||
{ |
|||
DBUG_PRINT("info", ("Too many dependencies")); |
|||
DBUG_VOID_RETURN; |
|||
} |
|||
|
|||
cache_table= NULL; |
|||
|
|||
cache_table_param.init(); |
|||
/* dependent items and result */ |
|||
cache_table_param.field_count= list->elements + 1; |
|||
/* postpone table creation to index description */ |
|||
cache_table_param.skip_create_table= 1; |
|||
cache_table= NULL; |
|||
|
|||
while ((item= li++)) |
|||
{ |
|||
DBUG_ASSERT(item); |
|||
DBUG_ASSERT(*item); |
|||
DBUG_ASSERT((*item)->fixed); |
|||
items.push_back((*item)); |
|||
} |
|||
items.push_front(val); |
|||
|
|||
if (!(cache_table= create_tmp_table(table_thd, &cache_table_param, |
|||
items, (ORDER*) NULL, |
|||
FALSE, FALSE, |
|||
((table_thd->options | |
|||
TMP_TABLE_ALL_COLUMNS) & |
|||
~(OPTION_BIG_TABLES | |
|||
TMP_TABLE_FORCE_MYISAM)), |
|||
HA_POS_ERROR, |
|||
(char *)"subquery-cache-table"))) |
|||
{ |
|||
DBUG_PRINT("error", ("create_tmp_table failed, caching switched off")); |
|||
DBUG_VOID_RETURN; |
|||
} |
|||
|
|||
if (cache_table->s->db_type() != heap_hton) |
|||
{ |
|||
DBUG_PRINT("error", ("we need only heap table")); |
|||
goto error; |
|||
} |
|||
|
|||
/* This list do not contain result field */ |
|||
it.open(); |
|||
|
|||
field_counter=1; |
|||
|
|||
if (cache_table->alloc_keys(1) || |
|||
(cache_table->add_tmp_key(0, items.elements - 1, |
|||
&field_enumerator, |
|||
(uchar*)&field_counter) < 0) || |
|||
ref.tmp_table_index_lookup_init(table_thd, cache_table->key_info, it, |
|||
TRUE)) |
|||
{ |
|||
DBUG_PRINT("error", ("creating index failed")); |
|||
goto error; |
|||
} |
|||
cache_table->s->keys= 1; |
|||
cache_table->s->uniques= 1; |
|||
ref.null_rejecting= 1; |
|||
ref.disable_cache= FALSE; |
|||
ref.has_record= 0; |
|||
ref.use_count= 0; |
|||
|
|||
|
|||
if (open_tmp_table(cache_table)) |
|||
{ |
|||
DBUG_PRINT("error", ("Opening (creating) temporary table failed")); |
|||
goto error; |
|||
} |
|||
|
|||
if (!(cached_result= new Item_field(cache_table->field[0]))) |
|||
{ |
|||
DBUG_PRINT("error", ("Creating Item_field failed")); |
|||
goto error; |
|||
} |
|||
|
|||
if (make_equalities()) |
|||
{ |
|||
DBUG_PRINT("error", ("Creating equalities failed")); |
|||
goto error; |
|||
} |
|||
|
|||
DBUG_VOID_RETURN; |
|||
|
|||
error: |
|||
/* switch off cache */ |
|||
free_tmp_table(table_thd, cache_table); |
|||
cache_table= NULL; |
|||
DBUG_VOID_RETURN; |
|||
} |
|||
|
|||
|
|||
Expression_cache_tmptable::~Expression_cache_tmptable() |
|||
{ |
|||
if (cache_table) |
|||
free_tmp_table(table_thd, cache_table); |
|||
} |
|||
|
|||
|
|||
/**
|
|||
Check if a given set of parameters of the expression is in the cache |
|||
|
|||
@param [out] value the expression value found in the cache if any |
|||
|
|||
@details |
|||
For a given set of the parameters of the expression the function |
|||
checks whether it can be found in some entry of the cache. If so |
|||
the function returns the result of the expression extracted from |
|||
the cache. |
|||
|
|||
@retval Expression_cache::HIT if the set of parameters is in the cache |
|||
@retval Expression_cache::MISS - otherwise |
|||
*/ |
|||
|
|||
Expression_cache::result Expression_cache_tmptable::check_value(Item **value) |
|||
{ |
|||
int res; |
|||
DBUG_ENTER("Expression_cache_tmptable::check_value"); |
|||
|
|||
/*
|
|||
We defer cache initialization to get item references that are |
|||
used at the execution phase. |
|||
*/ |
|||
if (!inited) |
|||
init(); |
|||
|
|||
if (cache_table) |
|||
{ |
|||
DBUG_PRINT("info", ("status: %u has_record %u", |
|||
(uint)cache_table->status, (uint)ref.has_record)); |
|||
if ((res= join_read_key2(table_thd, NULL, cache_table, &ref)) == 1) |
|||
DBUG_RETURN(ERROR); |
|||
if (res || (equalities && !equalities->val_int())) |
|||
{ |
|||
subquery_cache_miss++; |
|||
DBUG_RETURN(MISS); |
|||
} |
|||
|
|||
subquery_cache_hit++; |
|||
*value= cached_result; |
|||
DBUG_RETURN(Expression_cache::HIT); |
|||
} |
|||
DBUG_RETURN(Expression_cache::MISS); |
|||
} |
|||
|
|||
|
|||
/**
|
|||
Put a new entry into the expression cache |
|||
|
|||
@param value the result of the expression to be put into the cache |
|||
|
|||
@details |
|||
The function evaluates 'value' and puts the result into the cache as the |
|||
result of the expression for the current set of parameters. |
|||
|
|||
@retval FALSE OK |
|||
@retval TRUE Error |
|||
*/ |
|||
|
|||
my_bool Expression_cache_tmptable::put_value(Item *value) |
|||
{ |
|||
int error; |
|||
DBUG_ENTER("Expression_cache_tmptable::put_value"); |
|||
DBUG_ASSERT(inited); |
|||
|
|||
if (!cache_table) |
|||
{ |
|||
DBUG_PRINT("info", ("No table so behave as we successfully put value")); |
|||
DBUG_RETURN(FALSE); |
|||
} |
|||
|
|||
*(items.head_ref())= value; |
|||
fill_record(table_thd, cache_table->field, items, TRUE, TRUE); |
|||
if (table_thd->is_error()) |
|||
goto err;; |
|||
|
|||
if ((error= cache_table->file->ha_write_row(cache_table->record[0]))) |
|||
{ |
|||
/* create_myisam_from_heap will generate error if needed */ |
|||
if (cache_table->file->is_fatal_error(error, HA_CHECK_DUP) && |
|||
create_internal_tmp_table_from_heap(table_thd, cache_table, |
|||
cache_table_param.start_recinfo, |
|||
&cache_table_param.recinfo, |
|||
error, 1)) |
|||
goto err; |
|||
} |
|||
cache_table->status= 0; /* cache_table->record contains an existed record */ |
|||
ref.has_record= TRUE; /* the same as above */ |
|||
DBUG_PRINT("info", ("has_record: TRUE status: 0")); |
|||
|
|||
DBUG_RETURN(FALSE); |
|||
|
|||
err: |
|||
free_tmp_table(table_thd, cache_table); |
|||
cache_table= NULL; |
|||
DBUG_RETURN(TRUE); |
|||
} |
|||
@ -0,0 +1,80 @@ |
|||
#ifndef SQL_EXPRESSION_CACHE_INCLUDED |
|||
#define SQL_EXPRESSION_CACHE_INCLUDED |
|||
|
|||
#include "sql_select.h" |
|||
|
|||
/** |
|||
Interface for expression cache |
|||
|
|||
@note |
|||
Parameters of an expression cache interface are set on the creation of the |
|||
cache. They are passed when a cache object of the implementation class is |
|||
constructed. That's why they are not visible in this interface. |
|||
*/ |
|||
|
|||
extern ulonglong subquery_cache_miss, subquery_cache_hit; |
|||
|
|||
class Expression_cache :public Sql_alloc |
|||
{ |
|||
public: |
|||
enum result {ERROR, HIT, MISS}; |
|||
|
|||
Expression_cache(){}; |
|||
virtual ~Expression_cache() {}; |
|||
/** |
|||
Shall check the presence of expression value in the cache for a given |
|||
set of values of the expression parameters. Return the result of the |
|||
expression if it's found in the cache. |
|||
*/ |
|||
virtual result check_value(Item **value)= 0; |
|||
/** |
|||
Shall put the value of an expression for given set of its parameters |
|||
into the expression cache |
|||
*/ |
|||
virtual my_bool put_value(Item *value)= 0; |
|||
}; |
|||
|
|||
struct st_table_ref; |
|||
struct st_join_table; |
|||
class Item_field; |
|||
|
|||
|
|||
/** |
|||
Implementation of expression cache over a temporary table |
|||
*/ |
|||
|
|||
class Expression_cache_tmptable :public Expression_cache |
|||
{ |
|||
public: |
|||
Expression_cache_tmptable(THD *thd, List<Item*> &dependants, Item *value); |
|||
virtual ~Expression_cache_tmptable(); |
|||
virtual result check_value(Item **value); |
|||
virtual my_bool put_value(Item *value); |
|||
|
|||
private: |
|||
void init(); |
|||
bool make_equalities(); |
|||
|
|||
/* tmp table parameters */ |
|||
TMP_TABLE_PARAM cache_table_param; |
|||
/* temporary table to store this cache */ |
|||
TABLE *cache_table; |
|||
/* Thread handle for the temporary table */ |
|||
THD *table_thd; |
|||
/* TABLE_REF for index lookup */ |
|||
struct st_table_ref ref; |
|||
/* Cached result */ |
|||
Item_field *cached_result; |
|||
/* List of references to the parameters of the expression */ |
|||
List<Item*> *list; |
|||
/* List of items */ |
|||
List<Item> items; |
|||
/* Value Item example */ |
|||
Item *val; |
|||
/* Expression to check after index lookup */ |
|||
Item *equalities; |
|||
/* Set on if the object has been succesfully initialized with init() */ |
|||
bool inited; |
|||
}; |
|||
|
|||
#endif /* SQL_EXPRESSION_CACHE_INCLUDED */ |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue