Commit 57c199d8 authored by Sergey Petrunya's avatar Sergey Petrunya

Merge maria-5.1 -> maria-5.1-table-elimination

parents 915a624c fef409cb
...@@ -1920,3 +1920,4 @@ sql/share/swedish ...@@ -1920,3 +1920,4 @@ sql/share/swedish
sql/share/ukrainian sql/share/ukrainian
libmysqld/examples/mysqltest.cc libmysqld/examples/mysqltest.cc
extra/libevent/event-config.h extra/libevent/event-config.h
libmysqld/opt_table_elimination.cc
...@@ -76,7 +76,7 @@ sqlsources = derror.cc field.cc field_conv.cc strfunc.cc filesort.cc \ ...@@ -76,7 +76,7 @@ sqlsources = derror.cc field.cc field_conv.cc strfunc.cc filesort.cc \
rpl_filter.cc sql_partition.cc sql_builtin.cc sql_plugin.cc \ rpl_filter.cc sql_partition.cc sql_builtin.cc sql_plugin.cc \
sql_tablespace.cc \ sql_tablespace.cc \
rpl_injector.cc my_user.c partition_info.cc \ rpl_injector.cc my_user.c partition_info.cc \
sql_servers.cc event_parse_data.cc sql_servers.cc event_parse_data.cc opt_table_elimination.cc
libmysqld_int_a_SOURCES= $(libmysqld_sources) libmysqld_int_a_SOURCES= $(libmysqld_sources)
nodist_libmysqld_int_a_SOURCES= $(libmysqlsources) $(sqlsources) nodist_libmysqld_int_a_SOURCES= $(libmysqlsources) $(sqlsources)
......
...@@ -3,6 +3,9 @@ SET @old_max_allowed_packet= @@global.max_allowed_packet; ...@@ -3,6 +3,9 @@ SET @old_max_allowed_packet= @@global.max_allowed_packet;
SET @@global.max_allowed_packet = 2 * 1024 * 1024 + 1024; SET @@global.max_allowed_packet = 2 * 1024 * 1024 + 1024;
CREATE TABLE t1(data LONGBLOB); CREATE TABLE t1(data LONGBLOB);
INSERT INTO t1 SELECT REPEAT('1', 2*1024*1024); INSERT INTO t1 SELECT REPEAT('1', 2*1024*1024);
SELECT COUNT(*) FROM t1;
COUNT(*)
1
SET @old_general_log = @@global.general_log; SET @old_general_log = @@global.general_log;
SET @@global.general_log = 0; SET @@global.general_log = 0;
SET @@global.general_log = @old_general_log; SET @@global.general_log = @old_general_log;
......
...@@ -121,8 +121,8 @@ insert into t1 values (1); ...@@ -121,8 +121,8 @@ insert into t1 values (1);
explain select * from t1 where 3 in (select (1+1) union select 1); explain select * from t1 where 3 in (select (1+1) union select 1);
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables 1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
2 DEPENDENT SUBQUERY NULL NULL NULL NULL NULL NULL NULL No tables used 2 DEPENDENT SUBQUERY NULL NULL NULL NULL NULL NULL NULL Impossible HAVING
3 DEPENDENT UNION NULL NULL NULL NULL NULL NULL NULL No tables used 3 DEPENDENT UNION NULL NULL NULL NULL NULL NULL NULL Impossible HAVING
NULL UNION RESULT <union2,3> ALL NULL NULL NULL NULL NULL NULL UNION RESULT <union2,3> ALL NULL NULL NULL NULL NULL
select * from t1 where 3 in (select (1+1) union select 1); select * from t1 where 3 in (select (1+1) union select 1);
a a
......
...@@ -3585,7 +3585,6 @@ INSERT INTO t2 VALUES (1,'a'),(2,'b'),(3,'c'); ...@@ -3585,7 +3585,6 @@ INSERT INTO t2 VALUES (1,'a'),(2,'b'),(3,'c');
EXPLAIN SELECT t1.a FROM t1 LEFT JOIN t2 ON t2.b=t1.b WHERE t1.a=3; EXPLAIN SELECT t1.a FROM t1 LEFT JOIN t2 ON t2.b=t1.b WHERE t1.a=3;
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 const PRIMARY PRIMARY 4 const 1 1 SIMPLE t1 const PRIMARY PRIMARY 4 const 1
1 SIMPLE t2 const b b 22 const 1 Using index
DROP TABLE t1,t2; DROP TABLE t1,t2;
CREATE TABLE t1(id int PRIMARY KEY, b int, e int); CREATE TABLE t1(id int PRIMARY KEY, b int, e int);
CREATE TABLE t2(i int, a int, INDEX si(i), INDEX ai(a)); CREATE TABLE t2(i int, a int, INDEX si(i), INDEX ai(a));
......
...@@ -4353,13 +4353,13 @@ id select_type table type possible_keys key key_len ref rows filtered Extra ...@@ -4353,13 +4353,13 @@ id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 2 100.00 1 PRIMARY t1 ALL NULL NULL NULL NULL 2 100.00
2 DEPENDENT SUBQUERY t1 ALL NULL NULL NULL NULL 2 100.00 Using temporary; Using filesort 2 DEPENDENT SUBQUERY t1 ALL NULL NULL NULL NULL 2 100.00 Using temporary; Using filesort
Warnings: Warnings:
Note 1003 select 1 AS `1` from `test`.`t1` where <in_optimizer>(1,<exists>(select 1 AS `1` from `test`.`t1` group by `test`.`t1`.`a` having (<cache>(1) = <ref_null_helper>(1)))) Note 1003 select 1 AS `1` from `test`.`t1` where <in_optimizer>(1,<exists>(select 1 AS `1` from `test`.`t1` group by `test`.`t1`.`a` having 1))
EXPLAIN EXTENDED SELECT 1 FROM t1 WHERE 1 IN (SELECT 1 FROM t1 WHERE a > 3 GROUP BY a); EXPLAIN EXTENDED SELECT 1 FROM t1 WHERE 1 IN (SELECT 1 FROM t1 WHERE a > 3 GROUP BY a);
id select_type table type possible_keys key key_len ref rows filtered Extra id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables 1 PRIMARY NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
2 DEPENDENT SUBQUERY t1 ALL NULL NULL NULL NULL 2 100.00 Using where; Using temporary; Using filesort 2 DEPENDENT SUBQUERY t1 ALL NULL NULL NULL NULL 2 100.00 Using where; Using temporary; Using filesort
Warnings: Warnings:
Note 1003 select 1 AS `1` from `test`.`t1` where <in_optimizer>(1,<exists>(select 1 AS `1` from `test`.`t1` where (`test`.`t1`.`a` > 3) group by `test`.`t1`.`a` having (<cache>(1) = <ref_null_helper>(1)))) Note 1003 select 1 AS `1` from `test`.`t1` where <in_optimizer>(1,<exists>(select 1 AS `1` from `test`.`t1` where (`test`.`t1`.`a` > 3) group by `test`.`t1`.`a` having 1))
DROP TABLE t1; DROP TABLE t1;
End of 5.0 tests. End of 5.0 tests.
CREATE TABLE t1 (a INT, b INT); CREATE TABLE t1 (a INT, b INT);
......
drop table if exists t0, t1, t2, t3;
drop view if exists v1, v2;
create table t1 (a int);
insert into t1 values (0),(1),(2),(3);
create table t0 as select * from t1;
create table t2 (a int primary key, b int)
as select a, a as b from t1 where a in (1,2);
create table t3 (a int primary key, b int)
as select a, a as b from t1 where a in (1,3);
# This will be eliminated:
explain select t1.a from t1 left join t2 on t2.a=t1.a;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 4
explain extended select t1.a from t1 left join t2 on t2.a=t1.a;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 4 100.00
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where 1
select t1.a from t1 left join t2 on t2.a=t1.a;
a
0
1
2
3
# This will not be eliminated as t2.b is in in select list:
explain select * from t1 left join t2 on t2.a=t1.a;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 4
1 SIMPLE t2 eq_ref PRIMARY PRIMARY 4 test.t1.a 1
# This will not be eliminated as t2.b is in in order list:
explain select t1.a from t1 left join t2 on t2.a=t1.a order by t2.b;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 4 Using temporary; Using filesort
1 SIMPLE t2 eq_ref PRIMARY PRIMARY 4 test.t1.a 1
# This will not be eliminated as t2.b is in group list:
explain select t1.a from t1 left join t2 on t2.a=t1.a group by t2.b;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 4 Using temporary; Using filesort
1 SIMPLE t2 eq_ref PRIMARY PRIMARY 4 test.t1.a 1
# This will not be eliminated as t2.b is in the WHERE
explain select t1.a from t1 left join t2 on t2.a=t1.a where t2.b < 3 or t2.b is null;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 4
1 SIMPLE t2 eq_ref PRIMARY PRIMARY 4 test.t1.a 1 Using where
# Elimination of multiple tables:
explain select t1.a from t1 left join (t2 join t3) on t2.a=t1.a and t3.a=t1.a;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 4
# Elimination of multiple tables (2):
explain select t1.a from t1 left join (t2 join t3 on t2.b=t3.b) on t2.a=t1.a and t3.a=t1.a;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 4
# Elimination when done within an outer join nest:
explain extended
select t0.*
from
t0 left join (t1 left join (t2 join t3 on t2.b=t3.b) on t2.a=t1.a and
t3.a=t1.a) on t0.a=t1.a;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t0 ALL NULL NULL NULL NULL 4 100.00
1 SIMPLE t1 ALL NULL NULL NULL NULL 4 100.00
Warnings:
Note 1003 select `test`.`t0`.`a` AS `a` from `test`.`t0` left join (`test`.`t1`) on((`test`.`t0`.`a` = `test`.`t1`.`a`)) where 1
# Elimination with aggregate functions
explain select count(*) from t1 left join t2 on t2.a=t1.a;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 4
explain select count(1) from t1 left join t2 on t2.a=t1.a;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 4
explain select count(1) from t1 left join t2 on t2.a=t1.a group by t1.a;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 4 Using temporary; Using filesort
This must not use elimination:
explain select count(1) from t1 left join t2 on t2.a=t1.a group by t2.a;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 4 Using temporary; Using filesort
1 SIMPLE t2 eq_ref PRIMARY PRIMARY 4 test.t1.a 1 Using index
drop table t0, t1, t2, t3;
create table t0 ( id integer, primary key (id));
create table t1 (
id integer,
attr1 integer,
primary key (id),
key (attr1)
);
create table t2 (
id integer,
attr2 integer,
fromdate date,
primary key (id, fromdate),
key (attr2,fromdate)
);
insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
insert into t0 select A.id + 10*B.id from t0 A, t0 B where B.id > 0;
insert into t1 select id, id from t0;
insert into t2 select id, id, date_add('2009-06-22', interval id day) from t0;
insert into t2 select id, id+1, date_add('2008-06-22', interval id day) from t0;
create view v1 as
select
F.id, A1.attr1, A2.attr2
from
t0 F
left join t1 A1 on A1.id=F.id
left join t2 A2 on A2.id=F.id and
A2.fromdate=(select MAX(fromdate) from
t2 where id=A2.id);
create view v2 as
select
F.id, A1.attr1, A2.attr2
from
t0 F
left join t1 A1 on A1.id=F.id
left join t2 A2 on A2.id=F.id and
A2.fromdate=(select MAX(fromdate) from
t2 where id=F.id);
This should use one table:
explain select id from v1 where id=2;
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY F const PRIMARY PRIMARY 4 const 1 Using index
This should use one table:
explain extended select id from v1 where id in (1,2,3,4);
id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY F range PRIMARY PRIMARY 4 NULL 4 100.00 Using where; Using index
Warnings:
Note 1276 Field or reference 'test.A2.id' of SELECT #3 was resolved in SELECT #1
Note 1003 select `F`.`id` AS `id` from `test`.`t0` `F` where (`F`.`id` in (1,2,3,4))
This should use facts and A1 tables:
explain extended select id from v1 where attr1 between 12 and 14;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY A1 range PRIMARY,attr1 attr1 5 NULL 2 100.00 Using where
1 PRIMARY F eq_ref PRIMARY PRIMARY 4 test.A1.id 1 100.00 Using index
Warnings:
Note 1276 Field or reference 'test.A2.id' of SELECT #3 was resolved in SELECT #1
Note 1003 select `F`.`id` AS `id` from `test`.`t0` `F` join `test`.`t1` `A1` where ((`F`.`id` = `A1`.`id`) and (`A1`.`attr1` between 12 and 14))
This should use facts, A2 and its subquery:
explain extended select id from v1 where attr2 between 12 and 14;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY A2 range PRIMARY,attr2 attr2 5 NULL 5 100.00 Using where
1 PRIMARY F eq_ref PRIMARY PRIMARY 4 test.A2.id 1 100.00 Using index
3 DEPENDENT SUBQUERY t2 ref PRIMARY PRIMARY 4 test.A2.id 2 100.00 Using index
Warnings:
Note 1276 Field or reference 'test.A2.id' of SELECT #3 was resolved in SELECT #1
Note 1003 select `F`.`id` AS `id` from `test`.`t0` `F` join `test`.`t2` `A2` where ((`F`.`id` = `A2`.`id`) and (`A2`.`attr2` between 12 and 14) and (`A2`.`fromdate` = (select max(`test`.`t2`.`fromdate`) AS `MAX(fromdate)` from `test`.`t2` where (`test`.`t2`.`id` = `A2`.`id`))))
This should use one table:
explain select id from v2 where id=2;
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY F const PRIMARY PRIMARY 4 const 1 Using index
This should use one table:
explain extended select id from v2 where id in (1,2,3,4);
id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY F range PRIMARY PRIMARY 4 NULL 4 100.00 Using where; Using index
Warnings:
Note 1276 Field or reference 'test.F.id' of SELECT #3 was resolved in SELECT #1
Note 1003 select `F`.`id` AS `id` from `test`.`t0` `F` where (`F`.`id` in (1,2,3,4))
This should use facts and A1 tables:
explain extended select id from v2 where attr1 between 12 and 14;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY A1 range PRIMARY,attr1 attr1 5 NULL 2 100.00 Using where
1 PRIMARY F eq_ref PRIMARY PRIMARY 4 test.A1.id 1 100.00 Using index
Warnings:
Note 1276 Field or reference 'test.F.id' of SELECT #3 was resolved in SELECT #1
Note 1003 select `F`.`id` AS `id` from `test`.`t0` `F` join `test`.`t1` `A1` where ((`F`.`id` = `A1`.`id`) and (`A1`.`attr1` between 12 and 14))
This should use facts, A2 and its subquery:
explain extended select id from v2 where attr2 between 12 and 14;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY A2 range PRIMARY,attr2 attr2 5 NULL 5 100.00 Using where
1 PRIMARY F eq_ref PRIMARY PRIMARY 4 test.A2.id 1 100.00 Using where; Using index
3 DEPENDENT SUBQUERY t2 ref PRIMARY PRIMARY 4 test.F.id 2 100.00 Using index
Warnings:
Note 1276 Field or reference 'test.F.id' of SELECT #3 was resolved in SELECT #1
Note 1003 select `F`.`id` AS `id` from `test`.`t0` `F` join `test`.`t2` `A2` where ((`F`.`id` = `A2`.`id`) and (`A2`.`attr2` between 12 and 14) and (`A2`.`fromdate` = (select max(`test`.`t2`.`fromdate`) AS `MAX(fromdate)` from `test`.`t2` where (`test`.`t2`.`id` = `F`.`id`))))
drop view v1, v2;
drop table t0, t1, t2;
create table t1 (a int);
insert into t1 values (0),(1),(2),(3);
create table t2 (pk1 int, pk2 int, pk3 int, col int, primary key(pk1, pk2, pk3));
insert into t2 select a,a,a,a from t1;
This must use only t1:
explain select t1.* from t1 left join t2 on t2.pk1=t1.a and
t2.pk2=t2.pk1+1 and
t2.pk3=t2.pk2+1;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 4
This must use only t1:
explain select t1.* from t1 left join t2 on t2.pk1=t1.a and
t2.pk3=t2.pk1+1 and
t2.pk2=t2.pk3+1;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 4
This must use both:
explain select t1.* from t1 left join t2 on t2.pk1=t1.a and
t2.pk3=t2.pk1+1 and
t2.pk2=t2.pk3+t2.col;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 4
1 SIMPLE t2 ref PRIMARY PRIMARY 4 test.t1.a 1
This must use only t1:
explain select t1.* from t1 left join t2 on t2.pk2=t1.a and
t2.pk1=t2.pk2+1 and
t2.pk3=t2.pk1;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 4
drop table t1, t2;
...@@ -522,7 +522,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra ...@@ -522,7 +522,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra
2 UNION t2 const PRIMARY PRIMARY 4 const 1 100.00 2 UNION t2 const PRIMARY PRIMARY 4 const 1 100.00
NULL UNION RESULT <union1,2> ALL NULL NULL NULL NULL NULL NULL NULL UNION RESULT <union1,2> ALL NULL NULL NULL NULL NULL NULL
Warnings: Warnings:
Note 1003 (select '1' AS `a`,'1' AS `b` from `test`.`t1` where ('1' = 1)) union (select '1' AS `a`,'10' AS `b` from `test`.`t2` where ('1' = 1)) Note 1003 (select '1' AS `a`,'1' AS `b` from `test`.`t1` where 1) union (select '1' AS `a`,'10' AS `b` from `test`.`t2` where 1)
(select * from t1 where a=5) union (select * from t2 where a=1); (select * from t1 where a=5) union (select * from t2 where a=1);
a b a b
1 10 1 10
......
...@@ -27,7 +27,8 @@ connect (con1, localhost, root,,); ...@@ -27,7 +27,8 @@ connect (con1, localhost, root,,);
CREATE TABLE t1(data LONGBLOB); CREATE TABLE t1(data LONGBLOB);
INSERT INTO t1 SELECT REPEAT('1', 2*1024*1024); INSERT INTO t1 SELECT REPEAT('1', 2*1024*1024);
# The following is to remove the race between end of insert and start of MYSQL_DUMP:
SELECT COUNT(*) FROM t1;
let $outfile= $MYSQLTEST_VARDIR/tmp/bug41486.sql; let $outfile= $MYSQLTEST_VARDIR/tmp/bug41486.sql;
--error 0,1 --error 0,1
remove_file $outfile; remove_file $outfile;
......
#
# Table elimination (MWL#17) tests
#
--disable_warnings
drop table if exists t0, t1, t2, t3;
drop view if exists v1, v2;
--enable_warnings
create table t1 (a int);
insert into t1 values (0),(1),(2),(3);
create table t0 as select * from t1;
create table t2 (a int primary key, b int)
as select a, a as b from t1 where a in (1,2);
create table t3 (a int primary key, b int)
as select a, a as b from t1 where a in (1,3);
--echo # This will be eliminated:
explain select t1.a from t1 left join t2 on t2.a=t1.a;
explain extended select t1.a from t1 left join t2 on t2.a=t1.a;
select t1.a from t1 left join t2 on t2.a=t1.a;
--echo # This will not be eliminated as t2.b is in in select list:
explain select * from t1 left join t2 on t2.a=t1.a;
--echo # This will not be eliminated as t2.b is in in order list:
explain select t1.a from t1 left join t2 on t2.a=t1.a order by t2.b;
--echo # This will not be eliminated as t2.b is in group list:
explain select t1.a from t1 left join t2 on t2.a=t1.a group by t2.b;
--echo # This will not be eliminated as t2.b is in the WHERE
explain select t1.a from t1 left join t2 on t2.a=t1.a where t2.b < 3 or t2.b is null;
--echo # Elimination of multiple tables:
explain select t1.a from t1 left join (t2 join t3) on t2.a=t1.a and t3.a=t1.a;
--echo # Elimination of multiple tables (2):
explain select t1.a from t1 left join (t2 join t3 on t2.b=t3.b) on t2.a=t1.a and t3.a=t1.a;
--echo # Elimination when done within an outer join nest:
explain extended
select t0.*
from
t0 left join (t1 left join (t2 join t3 on t2.b=t3.b) on t2.a=t1.a and
t3.a=t1.a) on t0.a=t1.a;
--echo # Elimination with aggregate functions
explain select count(*) from t1 left join t2 on t2.a=t1.a;
explain select count(1) from t1 left join t2 on t2.a=t1.a;
explain select count(1) from t1 left join t2 on t2.a=t1.a group by t1.a;
--echo This must not use elimination:
explain select count(1) from t1 left join t2 on t2.a=t1.a group by t2.a;
drop table t0, t1, t2, t3;
# This will stand for elim_facts
create table t0 ( id integer, primary key (id));
# Attribute1, non-versioned
create table t1 (
id integer,
attr1 integer,
primary key (id),
key (attr1)
);
# Attribute2, time-versioned
create table t2 (
id integer,
attr2 integer,
fromdate date,
primary key (id, fromdate),
key (attr2,fromdate)
);
insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
insert into t0 select A.id + 10*B.id from t0 A, t0 B where B.id > 0;
insert into t1 select id, id from t0;
insert into t2 select id, id, date_add('2009-06-22', interval id day) from t0;
insert into t2 select id, id+1, date_add('2008-06-22', interval id day) from t0;
create view v1 as
select
F.id, A1.attr1, A2.attr2
from
t0 F
left join t1 A1 on A1.id=F.id
left join t2 A2 on A2.id=F.id and
A2.fromdate=(select MAX(fromdate) from
t2 where id=A2.id);
create view v2 as
select
F.id, A1.attr1, A2.attr2
from
t0 F
left join t1 A1 on A1.id=F.id
left join t2 A2 on A2.id=F.id and
A2.fromdate=(select MAX(fromdate) from
t2 where id=F.id);
--echo This should use one table:
explain select id from v1 where id=2;
--echo This should use one table:
explain extended select id from v1 where id in (1,2,3,4);
--echo This should use facts and A1 tables:
explain extended select id from v1 where attr1 between 12 and 14;
--echo This should use facts, A2 and its subquery:
explain extended select id from v1 where attr2 between 12 and 14;
# Repeat for v2:
--echo This should use one table:
explain select id from v2 where id=2;
--echo This should use one table:
explain extended select id from v2 where id in (1,2,3,4);
--echo This should use facts and A1 tables:
explain extended select id from v2 where attr1 between 12 and 14;
--echo This should use facts, A2 and its subquery:
explain extended select id from v2 where attr2 between 12 and 14;
drop view v1, v2;
drop table t0, t1, t2;
#
# Tests for the code that uses t.keypartX=func(t.keypartY) equalities to
# make table elimination inferences
#
create table t1 (a int);
insert into t1 values (0),(1),(2),(3);
create table t2 (pk1 int, pk2 int, pk3 int, col int, primary key(pk1, pk2, pk3));
insert into t2 select a,a,a,a from t1;
--echo This must use only t1:
explain select t1.* from t1 left join t2 on t2.pk1=t1.a and
t2.pk2=t2.pk1+1 and
t2.pk3=t2.pk2+1;
--echo This must use only t1:
explain select t1.* from t1 left join t2 on t2.pk1=t1.a and
t2.pk3=t2.pk1+1 and
t2.pk2=t2.pk3+1;
--echo This must use both:
explain select t1.* from t1 left join t2 on t2.pk1=t1.a and
t2.pk3=t2.pk1+1 and
t2.pk2=t2.pk3+t2.col;
--echo This must use only t1:
explain select t1.* from t1 left join t2 on t2.pk2=t1.a and
t2.pk1=t2.pk2+1 and
t2.pk3=t2.pk1;
drop table t1, t2;
...@@ -703,3 +703,73 @@ ...@@ -703,3 +703,73 @@
fun:malloc fun:malloc
fun:inet_ntoa fun:inet_ntoa
} }
#
# Some problem inside glibc on Ubuntu 9.04, x86 (but not amd64):
#
# ==5985== 19 bytes in 1 blocks are still reachable in loss record 1 of 6
# ==5985== at 0x7AF3FDE: malloc (vg_replace_malloc.c:207)
# ... 11,12, or 13 functions w/o symbols ...
# ==5985== by 0x8717185: nptl_pthread_exit_hack_handler (my_thr_init.c:55)
#
# Since valgrind 3.3.0 doesn't support '...' multi-function pattern, using
# multiple suppressions:
#
{
Mem loss inside nptl_pthread_exit_hack_handler
Memcheck:Leak
fun:*
fun:*
fun:*
fun:*
fun:*
fun:*
fun:*
fun:*
fun:*
fun:*
fun:*
fun:*
fun:nptl_pthread_exit_hack_handler
}
{
Mem loss inside nptl_pthread_exit_hack_handler
Memcheck:Leak
fun:*
fun:*
fun:*
fun:*
fun:*
fun:*
fun:*
fun:*
fun:*
fun:*
fun:*
fun:*
fun:*
fun:nptl_pthread_exit_hack_handler
}
{
Mem loss inside nptl_pthread_exit_hack_handler
Memcheck:Leak
fun:*
fun:*
fun:*
fun:*
fun:*
fun:*
fun:*
fun:*
fun:*
fun:*
fun:*
fun:*
fun:*
fun:*
fun:nptl_pthread_exit_hack_handler
}
#!@PERL@
# Test of table elimination feature
use Cwd;
use DBI;
use Getopt::Long;
use Benchmark;
$opt_loop_count=100000;
$opt_medium_loop_count=10000;
$opt_small_loop_count=100;
$pwd = cwd(); $pwd = "." if ($pwd eq '');
require "$pwd/bench-init.pl" || die "Can't read Configuration file: $!\n";
if ($opt_small_test)
{
$opt_loop_count/=10;
$opt_medium_loop_count/=10;
$opt_small_loop_count/=10;
}
print "Testing table elimination feature\n";
print "The test table has $opt_loop_count rows.\n\n";
# A query to get the recent versions of all attributes:
$select_current_full_facts="
select
F.id, A1.attr1, A2.attr2
from
elim_facts F
left join elim_attr1 A1 on A1.id=F.id
left join elim_attr2 A2 on A2.id=F.id and
A2.fromdate=(select MAX(fromdate) from
elim_attr2 where id=A2.id);
";
$select_current_full_facts="
select
F.id, A1.attr1, A2.attr2
from
elim_facts F
left join elim_attr1 A1 on A1.id=F.id
left join elim_attr2 A2 on A2.id=F.id and
A2.fromdate=(select MAX(fromdate) from
elim_attr2 where id=F.id);
";
# TODO: same as above but for some given date also?
# TODO:
####
#### Connect and start timeing
####
$dbh = $server->connect();
$start_time=new Benchmark;
####
#### Create needed tables
####
goto select_test if ($opt_skip_create);
print "Creating tables\n";
$dbh->do("drop table elim_facts" . $server->{'drop_attr'});
$dbh->do("drop table elim_attr1" . $server->{'drop_attr'});
$dbh->do("drop table elim_attr2" . $server->{'drop_attr'});
# The facts table
do_many($dbh,$server->create("elim_facts",
["id integer"],
["primary key (id)"]));
# Attribute1, non-versioned
do_many($dbh,$server->create("elim_attr1",
["id integer",
"attr1 integer"],
["primary key (id)",
"key (attr1)"]));
# Attribute2, time-versioned
do_many($dbh,$server->create("elim_attr2",
["id integer",
"attr2 integer",
"fromdate date"],
["primary key (id, fromdate)",
"key (attr2,fromdate)"]));
#NOTE: ignoring: if ($limits->{'views'})
$dbh->do("drop view elim_current_facts");
$dbh->do("create view elim_current_facts as $select_current_full_facts");
if ($opt_lock_tables)
{
do_query($dbh,"LOCK TABLES elim_facts, elim_attr1, elim_attr2 WRITE");
}
if ($opt_fast && defined($server->{vacuum}))
{
$server->vacuum(1,\$dbh);
}
####
#### Fill the facts table
####
$n_facts= $opt_loop_count;
if ($opt_fast && $server->{transactions})
{
$dbh->{AutoCommit} = 0;
}
print "Inserting $n_facts rows into facts table\n";
$loop_time=new Benchmark;
$query="insert into elim_facts values (";
for ($id=0; $id < $n_facts ; $id++)
{
do_query($dbh,"$query $id)");
}
if ($opt_fast && $server->{transactions})
{
$dbh->commit;
$dbh->{AutoCommit} = 1;
}
$end_time=new Benchmark;
print "Time to insert ($n_facts): " .
timestr(timediff($end_time, $loop_time),"all") . "\n\n";
####
#### Fill attr1 table
####
if ($opt_fast && $server->{transactions})
{
$dbh->{AutoCommit} = 0;
}
print "Inserting $n_facts rows into attr1 table\n";
$loop_time=new Benchmark;
$query="insert into elim_attr1 values (";
for ($id=0; $id < $n_facts ; $id++)
{
$attr1= ceil(rand($n_facts));
do_query($dbh,"$query $id, $attr1)");
}
if ($opt_fast && $server->{transactions})
{
$dbh->commit;
$dbh->{AutoCommit} = 1;
}
$end_time=new Benchmark;
print "Time to insert ($n_facts): " .
timestr(timediff($end_time, $loop_time),"all") . "\n\n";
####
#### Fill attr2 table
####
if ($opt_fast && $server->{transactions})
{
$dbh->{AutoCommit} = 0;
}
print "Inserting $n_facts rows into attr2 table\n";
$loop_time=new Benchmark;
for ($id=0; $id < $n_facts ; $id++)
{
# Two values for each $id - current one and obsolete one.
$attr1= ceil(rand($n_facts));
$query="insert into elim_attr2 values ($id, $attr1, now())";
do_query($dbh,$query);
$query="insert into elim_attr2 values ($id, $attr1, '2009-01-01')";
do_query($dbh,$query);
}
if ($opt_fast && $server->{transactions})
{
$dbh->commit;
$dbh->{AutoCommit} = 1;
}
$end_time=new Benchmark;
print "Time to insert ($n_facts): " .
timestr(timediff($end_time, $loop_time),"all") . "\n\n";
####
#### Finalize the database population
####
if ($opt_lock_tables)
{
do_query($dbh,"UNLOCK TABLES");
}
if ($opt_fast && defined($server->{vacuum}))
{
$server->vacuum(0,\$dbh,["elim_facts", "elim_attr1", "elim_attr2"]);
}
if ($opt_lock_tables)
{
do_query($dbh,"LOCK TABLES elim_facts, elim_attr1, elim_attr2 WRITE");
}
####
#### Do some selects on the table
####
select_test:
#
# The selects will be:
# - N pk-lookups with all attributes
# - pk-attribute-based lookup
# - latest-attribute value based lookup.
###
### Bare facts select:
###
print "testing bare facts facts table\n";
$loop_time=new Benchmark;
$rows=0;
for ($i=0 ; $i < $opt_medium_loop_count ; $i++)
{
$val= ceil(rand($n_facts));
$rows+=fetch_all_rows($dbh,"select * from elim_facts where id=$val");
}
$count=$i;
$end_time=new Benchmark;
print "time for select_bare_facts ($count:$rows): " .
timestr(timediff($end_time, $loop_time),"all") . "\n";
###
### Full facts select, no elimination:
###
print "testing full facts facts table\n";
$loop_time=new Benchmark;
$rows=0;
for ($i=0 ; $i < $opt_medium_loop_count ; $i++)
{
$val= rand($n_facts);
$rows+=fetch_all_rows($dbh,"select * from elim_current_facts where id=$val");
}
$count=$i;
$end_time=new Benchmark;
print "time for select_two_attributes ($count:$rows): " .
timestr(timediff($end_time, $loop_time),"all") . "\n";
###
### Now with elimination: select only only one fact
###
print "testing selection of one attribute\n";
$loop_time=new Benchmark;
$rows=0;
for ($i=0 ; $i < $opt_medium_loop_count ; $i++)
{
$val= rand($n_facts);
$rows+=fetch_all_rows($dbh,"select id, attr1 from elim_current_facts where id=$val");
}
$count=$i;
$end_time=new Benchmark;
print "time for select_one_attribute ($count:$rows): " .
timestr(timediff($end_time, $loop_time),"all") . "\n";
###
### Now with elimination: select only only one fact
###
print "testing selection of one attribute\n";
$loop_time=new Benchmark;
$rows=0;
for ($i=0 ; $i < $opt_medium_loop_count ; $i++)
{
$val= rand($n_facts);
$rows+=fetch_all_rows($dbh,"select id, attr2 from elim_current_facts where id=$val");
}
$count=$i;
$end_time=new Benchmark;
print "time for select_one_attribute ($count:$rows): " .
timestr(timediff($end_time, $loop_time),"all") . "\n";
###
### TODO...
###
;
####
#### End of benchmark
####
if ($opt_lock_tables)
{
do_query($dbh,"UNLOCK TABLES");
}
if (!$opt_skip_delete)
{
do_query($dbh,"drop table elim_facts, elim_attr1, elim_attr2" . $server->{'drop_attr'});
}
if ($opt_fast && defined($server->{vacuum}))
{
$server->vacuum(0,\$dbh);
}
$dbh->disconnect; # close connection
end_benchmark($start_time);
...@@ -73,7 +73,7 @@ ADD_EXECUTABLE(mysqld ...@@ -73,7 +73,7 @@ ADD_EXECUTABLE(mysqld
partition_info.cc rpl_utility.cc rpl_injector.cc sql_locale.cc partition_info.cc rpl_utility.cc rpl_injector.cc sql_locale.cc
rpl_rli.cc rpl_mi.cc sql_servers.cc rpl_rli.cc rpl_mi.cc sql_servers.cc
sql_connect.cc scheduler.cc sql_connect.cc scheduler.cc
sql_profile.cc event_parse_data.cc sql_profile.cc event_parse_data.cc opt_table_elimination.cc
${PROJECT_SOURCE_DIR}/sql/sql_yacc.cc ${PROJECT_SOURCE_DIR}/sql/sql_yacc.cc
${PROJECT_SOURCE_DIR}/sql/sql_yacc.h ${PROJECT_SOURCE_DIR}/sql/sql_yacc.h
${PROJECT_SOURCE_DIR}/include/mysqld_error.h ${PROJECT_SOURCE_DIR}/include/mysqld_error.h
......
...@@ -121,7 +121,8 @@ mysqld_SOURCES = sql_lex.cc sql_handler.cc sql_partition.cc \ ...@@ -121,7 +121,8 @@ mysqld_SOURCES = sql_lex.cc sql_handler.cc sql_partition.cc \
event_queue.cc event_db_repository.cc events.cc \ event_queue.cc event_db_repository.cc events.cc \
sql_plugin.cc sql_binlog.cc \ sql_plugin.cc sql_binlog.cc \
sql_builtin.cc sql_tablespace.cc partition_info.cc \ sql_builtin.cc sql_tablespace.cc partition_info.cc \
sql_servers.cc event_parse_data.cc sql_servers.cc event_parse_data.cc \
opt_table_elimination.cc
nodist_mysqld_SOURCES = mini_client_errors.c pack.c client.c my_time.c my_user.c nodist_mysqld_SOURCES = mini_client_errors.c pack.c client.c my_time.c my_user.c
......
...@@ -1915,6 +1915,15 @@ void Item_field::reset_field(Field *f) ...@@ -1915,6 +1915,15 @@ void Item_field::reset_field(Field *f)
name= (char*) f->field_name; name= (char*) f->field_name;
} }
bool Item_field::check_column_usage_processor(uchar *arg)
{
Field_enumerator *fe= (Field_enumerator*)arg;
fe->see_field(field);
return FALSE;
}
const char *Item_ident::full_name() const const char *Item_ident::full_name() const
{ {
char *tmp; char *tmp;
...@@ -3380,7 +3389,7 @@ static void mark_as_dependent(THD *thd, SELECT_LEX *last, SELECT_LEX *current, ...@@ -3380,7 +3389,7 @@ static void mark_as_dependent(THD *thd, SELECT_LEX *last, SELECT_LEX *current,
/* store pointer on SELECT_LEX from which item is dependent */ /* store pointer on SELECT_LEX from which item is dependent */
if (mark_item) if (mark_item)
mark_item->depended_from= last; mark_item->depended_from= last;
current->mark_as_dependent(last); current->mark_as_dependent(last, resolved_item);
if (thd->lex->describe & DESCRIBE_EXTENDED) if (thd->lex->describe & DESCRIBE_EXTENDED)
{ {
char warn_buff[MYSQL_ERRMSG_SIZE]; char warn_buff[MYSQL_ERRMSG_SIZE];
......
...@@ -731,7 +731,11 @@ public: ...@@ -731,7 +731,11 @@ public:
virtual bool val_bool_result() { return val_bool(); } virtual bool val_bool_result() { return val_bool(); }
virtual bool is_null_result() { return is_null(); } virtual bool is_null_result() { return is_null(); }
/* bit map of tables used by item */ /*
Bitmap of tables used by item
(note: if you need to check dependencies on individual columns, check out
check_column_usage_processor)
*/
virtual table_map used_tables() const { return (table_map) 0L; } virtual table_map used_tables() const { return (table_map) 0L; }
/* /*
Return table map of tables that can't be NULL tables (tables that are Return table map of tables that can't be NULL tables (tables that are
...@@ -888,6 +892,8 @@ public: ...@@ -888,6 +892,8 @@ public:
virtual bool reset_query_id_processor(uchar *query_id_arg) { return 0; } virtual bool reset_query_id_processor(uchar *query_id_arg) { return 0; }
virtual bool is_expensive_processor(uchar *arg) { return 0; } virtual bool is_expensive_processor(uchar *arg) { return 0; }
virtual bool register_field_in_read_map(uchar *arg) { return 0; } virtual bool register_field_in_read_map(uchar *arg) { return 0; }
virtual bool check_column_usage_processor(uchar *arg) { return 0; }
virtual bool mark_as_eliminated_processor(uchar *arg) { return 0; }
/* /*
Check if a partition function is allowed Check if a partition function is allowed
SYNOPSIS SYNOPSIS
...@@ -1012,6 +1018,14 @@ public: ...@@ -1012,6 +1018,14 @@ public:
}; };
/* Data for Item::check_column_usage_processor */
class Field_enumerator
{
public:
virtual void see_field(Field *field)= 0;
virtual ~Field_enumerator() {}; /* Shut up compiler warning */
};
class sp_head; class sp_head;
...@@ -1477,6 +1491,7 @@ public: ...@@ -1477,6 +1491,7 @@ public:
bool find_item_in_field_list_processor(uchar *arg); bool find_item_in_field_list_processor(uchar *arg);
bool register_field_in_read_map(uchar *arg); bool register_field_in_read_map(uchar *arg);
bool check_partition_func_processor(uchar *int_arg) {return FALSE;} bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
bool check_column_usage_processor(uchar *arg);
void cleanup(); void cleanup();
bool result_as_longlong() bool result_as_longlong()
{ {
...@@ -2203,6 +2218,10 @@ public: ...@@ -2203,6 +2218,10 @@ public:
if (!depended_from) if (!depended_from)
(*ref)->update_used_tables(); (*ref)->update_used_tables();
} }
bool const_item() const
{
return (*ref)->const_item();
}
table_map not_null_tables() const { return (*ref)->not_null_tables(); } table_map not_null_tables() const { return (*ref)->not_null_tables(); }
void set_result_field(Field *field) { result_field= field; } void set_result_field(Field *field) { result_field= field; }
bool is_result_field() { return 1; } bool is_result_field() { return 1; }
......
...@@ -39,7 +39,7 @@ inline Item * and_items(Item* cond, Item *item) ...@@ -39,7 +39,7 @@ inline Item * and_items(Item* cond, Item *item)
Item_subselect::Item_subselect(): Item_subselect::Item_subselect():
Item_result_field(), value_assigned(0), thd(0), substitution(0), Item_result_field(), value_assigned(0), thd(0), substitution(0),
engine(0), old_engine(0), used_tables_cache(0), have_to_be_excluded(0), engine(0), old_engine(0), used_tables_cache(0), have_to_be_excluded(0),
const_item_cache(1), engine_changed(0), changed(0), is_correlated(FALSE) const_item_cache(1), in_fix_fields(0), engine_changed(0), changed(0), is_correlated(FALSE)
{ {
with_subselect= 1; with_subselect= 1;
reset(); reset();
...@@ -151,10 +151,14 @@ bool Item_subselect::fix_fields(THD *thd_param, Item **ref) ...@@ -151,10 +151,14 @@ bool Item_subselect::fix_fields(THD *thd_param, Item **ref)
DBUG_ASSERT(fixed == 0); DBUG_ASSERT(fixed == 0);
engine->set_thd((thd= thd_param)); engine->set_thd((thd= thd_param));
if (!in_fix_fields)
refers_to.empty();
eliminated= FALSE;
if (check_stack_overrun(thd, STACK_MIN_SIZE, (uchar*)&res)) if (check_stack_overrun(thd, STACK_MIN_SIZE, (uchar*)&res))
return TRUE; return TRUE;
in_fix_fields++;
res= engine->prepare(); res= engine->prepare();
// all transformation is done (used by prepared statements) // all transformation is done (used by prepared statements)
...@@ -181,12 +185,14 @@ bool Item_subselect::fix_fields(THD *thd_param, Item **ref) ...@@ -181,12 +185,14 @@ bool Item_subselect::fix_fields(THD *thd_param, Item **ref)
if (!(*ref)->fixed) if (!(*ref)->fixed)
ret= (*ref)->fix_fields(thd, ref); ret= (*ref)->fix_fields(thd, ref);
thd->where= save_where; thd->where= save_where;
in_fix_fields--;
return ret; return ret;
} }
// Is it one field subselect? // Is it one field subselect?
if (engine->cols() > max_columns) if (engine->cols() > max_columns)
{ {
my_error(ER_OPERAND_COLUMNS, MYF(0), 1); my_error(ER_OPERAND_COLUMNS, MYF(0), 1);
in_fix_fields--;
return TRUE; return TRUE;
} }
fix_length_and_dec(); fix_length_and_dec();
...@@ -203,11 +209,30 @@ bool Item_subselect::fix_fields(THD *thd_param, Item **ref) ...@@ -203,11 +209,30 @@ bool Item_subselect::fix_fields(THD *thd_param, Item **ref)
fixed= 1; fixed= 1;
err: err:
in_fix_fields--;
thd->where= save_where; thd->where= save_where;
return res; return res;
} }
bool Item_subselect::check_column_usage_processor(uchar *arg)
{
List_iterator<Item> it(refers_to);
Item *item;
while ((item= it++))
{
if (item->walk(&Item::check_column_usage_processor,FALSE, arg))
return TRUE;
}
return FALSE;
}
bool Item_subselect::mark_as_eliminated_processor(uchar *arg)
{
eliminated= TRUE;
return FALSE;
}
bool Item_subselect::walk(Item_processor processor, bool walk_subquery, bool Item_subselect::walk(Item_processor processor, bool walk_subquery,
uchar *argument) uchar *argument)
{ {
...@@ -225,6 +250,7 @@ bool Item_subselect::walk(Item_processor processor, bool walk_subquery, ...@@ -225,6 +250,7 @@ bool Item_subselect::walk(Item_processor processor, bool walk_subquery,
if (lex->having && (lex->having)->walk(processor, walk_subquery, if (lex->having && (lex->having)->walk(processor, walk_subquery,
argument)) argument))
return 1; return 1;
/* TODO: why does this walk WHERE/HAVING but not ON expressions of outer joins? */
while ((item=li++)) while ((item=li++))
{ {
......
...@@ -52,8 +52,16 @@ protected: ...@@ -52,8 +52,16 @@ protected:
bool have_to_be_excluded; bool have_to_be_excluded;
/* cache of constant state */ /* cache of constant state */
bool const_item_cache; bool const_item_cache;
public: public:
/*
References from inside the subquery to the select that this predicate is
in. References to parent selects not included.
*/
List<Item> refers_to;
int in_fix_fields;
bool eliminated;
/* changed engine indicator */ /* changed engine indicator */
bool engine_changed; bool engine_changed;
/* subquery is transformed */ /* subquery is transformed */
...@@ -126,6 +134,8 @@ public: ...@@ -126,6 +134,8 @@ public:
virtual void reset_value_registration() {} virtual void reset_value_registration() {}
enum_parsing_place place() { return parsing_place; } enum_parsing_place place() { return parsing_place; }
bool walk(Item_processor processor, bool walk_subquery, uchar *arg); bool walk(Item_processor processor, bool walk_subquery, uchar *arg);
bool mark_as_eliminated_processor(uchar *arg);
bool check_column_usage_processor(uchar *arg);
/** /**
Get the SELECT_LEX structure associated with this Item. Get the SELECT_LEX structure associated with this Item.
......
...@@ -350,7 +350,7 @@ bool Item_sum::register_sum_func(THD *thd, Item **ref) ...@@ -350,7 +350,7 @@ bool Item_sum::register_sum_func(THD *thd, Item **ref)
sl= sl->master_unit()->outer_select() ) sl= sl->master_unit()->outer_select() )
sl->master_unit()->item->with_sum_func= 1; sl->master_unit()->item->with_sum_func= 1;
} }
thd->lex->current_select->mark_as_dependent(aggr_sel); thd->lex->current_select->mark_as_dependent(aggr_sel, NULL);
return FALSE; return FALSE;
} }
...@@ -542,11 +542,6 @@ void Item_sum::update_used_tables () ...@@ -542,11 +542,6 @@ void Item_sum::update_used_tables ()
args[i]->update_used_tables(); args[i]->update_used_tables();
used_tables_cache|= args[i]->used_tables(); used_tables_cache|= args[i]->used_tables();
} }
used_tables_cache&= PSEUDO_TABLE_BITS;
/* the aggregate function is aggregated into its local context */
used_tables_cache |= (1 << aggr_sel->join->tables) - 1;
} }
} }
......
...@@ -255,6 +255,12 @@ protected: ...@@ -255,6 +255,12 @@ protected:
*/ */
Item **orig_args, *tmp_orig_args[2]; Item **orig_args, *tmp_orig_args[2];
table_map used_tables_cache; table_map used_tables_cache;
/*
TRUE <=> We've managed to calculate the value of this Item in
opt_sum_query(), hence it can be considered constant at all subsequent
steps.
*/
bool forced_const; bool forced_const;
public: public:
...@@ -341,6 +347,15 @@ public: ...@@ -341,6 +347,15 @@ public:
virtual const char *func_name() const= 0; virtual const char *func_name() const= 0;
virtual Item *result_item(Field *field) virtual Item *result_item(Field *field)
{ return new Item_field(field); } { return new Item_field(field); }
/*
Return bitmap of tables that are needed to evaluate the item.
The implementation takes into account the used strategy: items resolved
at optimization phase will report 0.
Items that depend on the number of join output records, but not columns
of any particular table (like COUNT(*)) will report 0 from used_tables(),
but will still return false from const_item().
*/
table_map used_tables() const { return used_tables_cache; } table_map used_tables() const { return used_tables_cache; }
void update_used_tables (); void update_used_tables ();
void cleanup() void cleanup()
......
This diff is collapsed.
...@@ -93,6 +93,34 @@ public: ...@@ -93,6 +93,34 @@ public:
} }
}; };
/* An iterator to quickly walk over bits in unlonglong bitmap. */
class Table_map_iterator
{
ulonglong bmp;
uint no;
public:
Table_map_iterator(ulonglong t) : bmp(t), no(0) {}
int next_bit()
{
static const char last_bit[16]= {32, 0, 1, 0,
2, 0, 1, 0,
3, 0, 1, 0,
2, 0, 1, 0};
uint bit;
while ((bit= last_bit[bmp & 0xF]) == 32)
{
no += 4;
bmp= bmp >> 4;
if (!bmp)
return BITMAP_END;
}
bmp &= ~(1LL << bit);
return no + bit;
}
int operator++(int) { return next_bit(); }
enum { BITMAP_END= 64 };
};
template <> class Bitmap<64> template <> class Bitmap<64>
{ {
ulonglong map; ulonglong map;
...@@ -136,5 +164,10 @@ public: ...@@ -136,5 +164,10 @@ public:
my_bool operator==(const Bitmap<64>& map2) const { return map == map2.map; } my_bool operator==(const Bitmap<64>& map2) const { return map == map2.map; }
char *print(char *buf) const { longlong2str(map,buf,16); return buf; } char *print(char *buf) const { longlong2str(map,buf,16); return buf; }
ulonglong to_ulonglong() const { return map; } ulonglong to_ulonglong() const { return map; }
class Iterator : public Table_map_iterator
{
public:
Iterator(Bitmap<64> &bmp) : Table_map_iterator(bmp.map) {}
};
}; };
...@@ -1778,8 +1778,9 @@ void st_select_lex_unit::exclude_tree() ...@@ -1778,8 +1778,9 @@ void st_select_lex_unit::exclude_tree()
'last' should be reachable from this st_select_lex_node 'last' should be reachable from this st_select_lex_node
*/ */
void st_select_lex::mark_as_dependent(st_select_lex *last) void st_select_lex::mark_as_dependent(st_select_lex *last, Item *dependency)
{ {
SELECT_LEX *next_to_last;
/* /*
Mark all selects from resolved to 1 before select where was Mark all selects from resolved to 1 before select where was
found table as depended (of select where was found table) found table as depended (of select where was found table)
...@@ -1787,6 +1788,7 @@ void st_select_lex::mark_as_dependent(st_select_lex *last) ...@@ -1787,6 +1788,7 @@ void st_select_lex::mark_as_dependent(st_select_lex *last)
for (SELECT_LEX *s= this; for (SELECT_LEX *s= this;
s && s != last; s && s != last;
s= s->outer_select()) s= s->outer_select())
{
if (!(s->uncacheable & UNCACHEABLE_DEPENDENT)) if (!(s->uncacheable & UNCACHEABLE_DEPENDENT))
{ {
// Select is dependent of outer select // Select is dependent of outer select
...@@ -1802,8 +1804,12 @@ void st_select_lex::mark_as_dependent(st_select_lex *last) ...@@ -1802,8 +1804,12 @@ void st_select_lex::mark_as_dependent(st_select_lex *last)
sl->uncacheable|= UNCACHEABLE_UNITED; sl->uncacheable|= UNCACHEABLE_UNITED;
} }
} }
next_to_last= s;
}
is_correlated= TRUE; is_correlated= TRUE;
this->master_unit()->item->is_correlated= TRUE; this->master_unit()->item->is_correlated= TRUE;
if (dependency)
next_to_last->master_unit()->item->refers_to.push_back(dependency);
} }
bool st_select_lex_node::set_braces(bool value) { return 1; } bool st_select_lex_node::set_braces(bool value) { return 1; }
......
...@@ -743,7 +743,7 @@ public: ...@@ -743,7 +743,7 @@ public:
return master_unit()->return_after_parsing(); return master_unit()->return_after_parsing();
} }
void mark_as_dependent(st_select_lex *last); void mark_as_dependent(st_select_lex *last, Item *dependency);
bool set_braces(bool value); bool set_braces(bool value);
bool inc_in_sum_expr(); bool inc_in_sum_expr();
......
This diff is collapsed.
...@@ -285,7 +285,15 @@ public: ...@@ -285,7 +285,15 @@ public:
fetching data from a cursor fetching data from a cursor
*/ */
bool resume_nested_loop; bool resume_nested_loop;
table_map const_table_map,found_const_table_map; table_map const_table_map;
/*
Constant tables for which we have found a row (as opposed to those for
which we didn't).
*/
table_map found_const_table_map;
/* Tables removed by table elimination. Set to 0 before the elimination. */
table_map eliminated_tables;
/* /*
Bitmap of all inner tables from outer joins Bitmap of all inner tables from outer joins
*/ */
...@@ -425,6 +433,7 @@ public: ...@@ -425,6 +433,7 @@ public:
table= 0; table= 0;
tables= 0; tables= 0;
const_tables= 0; const_tables= 0;
eliminated_tables= 0;
join_list= 0; join_list= 0;
sort_and_group= 0; sort_and_group= 0;
first_record= 0; first_record= 0;
...@@ -530,6 +539,10 @@ public: ...@@ -530,6 +539,10 @@ public:
return (unit == &thd->lex->unit && (unit->fake_select_lex == 0 || return (unit == &thd->lex->unit && (unit->fake_select_lex == 0 ||
select_lex == unit->fake_select_lex)); select_lex == unit->fake_select_lex));
} }
inline table_map all_tables_map()
{
return (table_map(1) << tables) - 1;
}
private: private:
bool make_simple_join(JOIN *join, TABLE *tmp_table); bool make_simple_join(JOIN *join, TABLE *tmp_table);
}; };
...@@ -730,9 +743,12 @@ bool error_if_full_join(JOIN *join); ...@@ -730,9 +743,12 @@ bool error_if_full_join(JOIN *join);
int report_error(TABLE *table, int error); int report_error(TABLE *table, int error);
int safe_index_read(JOIN_TAB *tab); int safe_index_read(JOIN_TAB *tab);
COND *remove_eq_conds(THD *thd, COND *cond, Item::cond_result *cond_value); COND *remove_eq_conds(THD *thd, COND *cond, Item::cond_result *cond_value);
void set_position(JOIN *join,uint idx,JOIN_TAB *table,KEYUSE *key);
inline bool optimizer_flag(THD *thd, uint flag) inline bool optimizer_flag(THD *thd, uint flag)
{ {
return (thd->variables.optimizer_switch & flag); return (thd->variables.optimizer_switch & flag);
} }
void eliminate_tables(JOIN *join);
...@@ -1366,7 +1366,8 @@ struct TABLE_LIST ...@@ -1366,7 +1366,8 @@ struct TABLE_LIST
return (derived || view || schema_table || (create && !table->db_stat) || return (derived || view || schema_table || (create && !table->db_stat) ||
!table); !table);
} }
void print(THD *thd, String *str, enum_query_type query_type); void print(THD *thd, table_map eliminated_tables, String *str,
enum_query_type query_type);
bool check_single_table(TABLE_LIST **table, table_map map, bool check_single_table(TABLE_LIST **table, table_map map,
TABLE_LIST *view); TABLE_LIST *view);
bool set_insert_values(MEM_ROOT *mem_root); bool set_insert_values(MEM_ROOT *mem_root);
...@@ -1615,7 +1616,11 @@ public: ...@@ -1615,7 +1616,11 @@ public:
typedef struct st_nested_join typedef struct st_nested_join
{ {
List<TABLE_LIST> join_list; /* list of elements in the nested join */ List<TABLE_LIST> join_list; /* list of elements in the nested join */
table_map used_tables; /* bitmap of tables in the nested join */ /*
Bitmap of tables within this nested join (including those embedded within
its children), including tables removed by table elimination.
*/
table_map used_tables;
table_map not_null_tables; /* tables that rejects nulls */ table_map not_null_tables; /* tables that rejects nulls */
struct st_join_table *first_nested;/* the first nested table in the plan */ struct st_join_table *first_nested;/* the first nested table in the plan */
/* /*
...@@ -1626,6 +1631,11 @@ typedef struct st_nested_join ...@@ -1626,6 +1631,11 @@ typedef struct st_nested_join
Before each use the counters are zeroed by reset_nj_counters. Before each use the counters are zeroed by reset_nj_counters.
*/ */
uint counter; uint counter;
/*
Number of elements in join_list that were not (or contain table(s) that
weren't) removed by table elimination.
*/
uint n_tables;
nested_join_map nj_map; /* Bit used to identify this nested join*/ nested_join_map nj_map; /* Bit used to identify this nested join*/
} NESTED_JOIN; } NESTED_JOIN;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment