Merge maria-5.1 -> maria-5.1-table-elimination
This commit is contained in:
commit
57c199d8d1
@ -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 \
|
|||||||
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;
|
|||||||
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);
|
|||||||
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');
|
|||||||
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
|
|||||||
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);
|
||||||
|
204
mysql-test/r/table_elim.result
Normal file
204
mysql-test/r/table_elim.result
Normal file
@ -0,0 +1,204 @@
|
|||||||
|
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
|
|||||||
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,,);
|
|||||||
|
|
||||||
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;
|
||||||
|
160
mysql-test/t/table_elim.test
Normal file
160
mysql-test/t/table_elim.test
Normal file
@ -0,0 +1,160 @@
|
|||||||
|
#
|
||||||
|
# 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 @@
|
|||||||
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
|
||||||
|
}
|
||||||
|
|
||||||
|
320
sql-bench/test-table-elimination.sh
Executable file
320
sql-bench/test-table-elimination.sh
Executable file
@ -0,0 +1,320 @@
|
|||||||
|
#!@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
|
|||||||
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 \
|
|||||||
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
|
||||||
|
|
||||||
|
11
sql/item.cc
11
sql/item.cc
@ -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,
|
|||||||
/* 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];
|
||||||
|
21
sql/item.h
21
sql/item.h
@ -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:
|
|||||||
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:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* 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:
|
|||||||
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:
|
|||||||
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)
|
|||||||
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)
|
|||||||
|
|
||||||
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)
|
|||||||
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)
|
|||||||
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,
|
|||||||
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:
|
|||||||
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:
|
|||||||
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)
|
|||||||
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 ()
|
|||||||
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:
|
|||||||
*/
|
*/
|
||||||
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:
|
|||||||
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()
|
||||||
|
1295
sql/opt_table_elimination.cc
Normal file
1295
sql/opt_table_elimination.cc
Normal file
File diff suppressed because it is too large
Load Diff
@ -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:
|
|||||||
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()
|
|||||||
'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)
|
|||||||
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)
|
|||||||
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:
|
|||||||
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();
|
||||||
|
@ -60,7 +60,6 @@ static bool update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,
|
|||||||
table_map table_map, SELECT_LEX *select_lex,
|
table_map table_map, SELECT_LEX *select_lex,
|
||||||
st_sargable_param **sargables);
|
st_sargable_param **sargables);
|
||||||
static int sort_keyuse(KEYUSE *a,KEYUSE *b);
|
static int sort_keyuse(KEYUSE *a,KEYUSE *b);
|
||||||
static void set_position(JOIN *join,uint index,JOIN_TAB *table,KEYUSE *key);
|
|
||||||
static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, KEYUSE *org_keyuse,
|
static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, KEYUSE *org_keyuse,
|
||||||
table_map used_tables);
|
table_map used_tables);
|
||||||
static bool choose_plan(JOIN *join,table_map join_tables);
|
static bool choose_plan(JOIN *join,table_map join_tables);
|
||||||
@ -115,7 +114,7 @@ static COND *simplify_joins(JOIN *join, List<TABLE_LIST> *join_list,
|
|||||||
COND *conds, bool top);
|
COND *conds, bool top);
|
||||||
static bool check_interleaving_with_nj(JOIN_TAB *next);
|
static bool check_interleaving_with_nj(JOIN_TAB *next);
|
||||||
static void restore_prev_nj_state(JOIN_TAB *last);
|
static void restore_prev_nj_state(JOIN_TAB *last);
|
||||||
static void reset_nj_counters(List<TABLE_LIST> *join_list);
|
static uint reset_nj_counters(JOIN *join, List<TABLE_LIST> *join_list);
|
||||||
static uint build_bitmap_for_nested_joins(List<TABLE_LIST> *join_list,
|
static uint build_bitmap_for_nested_joins(List<TABLE_LIST> *join_list,
|
||||||
uint first_unused);
|
uint first_unused);
|
||||||
|
|
||||||
@ -1012,7 +1011,7 @@ JOIN::optimize()
|
|||||||
DBUG_RETURN(1);
|
DBUG_RETURN(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
reset_nj_counters(join_list);
|
reset_nj_counters(this, join_list);
|
||||||
make_outerjoin_info(this);
|
make_outerjoin_info(this);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -2381,6 +2380,13 @@ mysql_select(THD *thd, Item ***rref_pointer_array,
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
When in EXPLAIN, delay deleting the joins so that they are still
|
||||||
|
available when we're producing EXPLAIN EXTENDED warning text.
|
||||||
|
*/
|
||||||
|
if (select_options & SELECT_DESCRIBE)
|
||||||
|
free_join= 0;
|
||||||
|
|
||||||
if (!(join= new JOIN(thd, fields, select_options, result)))
|
if (!(join= new JOIN(thd, fields, select_options, result)))
|
||||||
DBUG_RETURN(TRUE);
|
DBUG_RETURN(TRUE);
|
||||||
thd_proc_info(thd, "init");
|
thd_proc_info(thd, "init");
|
||||||
@ -2646,24 +2652,31 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables_arg, COND *conds,
|
|||||||
~outer_join, join->select_lex, &sargables))
|
~outer_join, join->select_lex, &sargables))
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
/* Read tables with 0 or 1 rows (system tables) */
|
|
||||||
join->const_table_map= 0;
|
join->const_table_map= 0;
|
||||||
|
join->const_tables= const_count;
|
||||||
|
eliminate_tables(join);
|
||||||
|
const_count= join->const_tables;
|
||||||
|
found_const_table_map= join->const_table_map;
|
||||||
|
|
||||||
|
/* Read tables with 0 or 1 rows (system tables) */
|
||||||
for (POSITION *p_pos=join->positions, *p_end=p_pos+const_count;
|
for (POSITION *p_pos=join->positions, *p_end=p_pos+const_count;
|
||||||
p_pos < p_end ;
|
p_pos < p_end ;
|
||||||
p_pos++)
|
p_pos++)
|
||||||
{
|
{
|
||||||
int tmp;
|
|
||||||
s= p_pos->table;
|
s= p_pos->table;
|
||||||
s->type=JT_SYSTEM;
|
if (! (s->table->map & join->eliminated_tables))
|
||||||
join->const_table_map|=s->table->map;
|
|
||||||
if ((tmp=join_read_const_table(s, p_pos)))
|
|
||||||
{
|
{
|
||||||
if (tmp > 0)
|
int tmp;
|
||||||
goto error; // Fatal error
|
s->type=JT_SYSTEM;
|
||||||
|
join->const_table_map|=s->table->map;
|
||||||
|
if ((tmp=join_read_const_table(s, p_pos)))
|
||||||
|
{
|
||||||
|
if (tmp > 0)
|
||||||
|
goto error; // Fatal error
|
||||||
|
}
|
||||||
|
else
|
||||||
|
found_const_table_map|= s->table->map;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
found_const_table_map|= s->table->map;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* loop until no more const tables are found */
|
/* loop until no more const tables are found */
|
||||||
@ -2688,7 +2701,8 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables_arg, COND *conds,
|
|||||||
substitution of a const table the key value happens to be null
|
substitution of a const table the key value happens to be null
|
||||||
then we can state that there are no matches for this equi-join.
|
then we can state that there are no matches for this equi-join.
|
||||||
*/
|
*/
|
||||||
if ((keyuse= s->keyuse) && *s->on_expr_ref && !s->embedding_map)
|
if ((keyuse= s->keyuse) && *s->on_expr_ref && !s->embedding_map &&
|
||||||
|
!(table->map & join->eliminated_tables))
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
When performing an outer join operation if there are no matching rows
|
When performing an outer join operation if there are no matching rows
|
||||||
@ -2965,6 +2979,26 @@ typedef struct key_field_t {
|
|||||||
|
|
||||||
This is called for OR between different levels.
|
This is called for OR between different levels.
|
||||||
|
|
||||||
|
That is, the function operates on an array of KEY_FIELD elements which has
|
||||||
|
two parts:
|
||||||
|
|
||||||
|
$LEFT_PART $RIGHT_PART
|
||||||
|
+-----------------------+-----------------------+
|
||||||
|
start new_fields end
|
||||||
|
|
||||||
|
$LEFT_PART and $RIGHT_PART are arrays that have KEY_FIELD elements for two
|
||||||
|
parts of the OR condition. Our task is to produce an array of KEY_FIELD
|
||||||
|
elements that would correspond to "$LEFT_PART OR $RIGHT_PART".
|
||||||
|
|
||||||
|
The rules for combining elements are as follows:
|
||||||
|
(keyfieldA1 AND keyfieldA2 AND ...) OR (keyfieldB1 AND keyfieldB2 AND ...)=
|
||||||
|
AND_ij (keyfieldA_i OR keyfieldB_j)
|
||||||
|
|
||||||
|
We discard all (keyfieldA_i OR keyfieldB_j) that refer to different
|
||||||
|
fields. For those referring to the same field, the logic is as follows:
|
||||||
|
|
||||||
|
t.keycol=
|
||||||
|
|
||||||
To be able to do 'ref_or_null' we merge a comparison of a column
|
To be able to do 'ref_or_null' we merge a comparison of a column
|
||||||
and 'column IS NULL' to one test. This is useful for sub select queries
|
and 'column IS NULL' to one test. This is useful for sub select queries
|
||||||
that are internally transformed to something like:.
|
that are internally transformed to something like:.
|
||||||
@ -3990,8 +4024,7 @@ add_group_and_distinct_keys(JOIN *join, JOIN_TAB *join_tab)
|
|||||||
|
|
||||||
/** Save const tables first as used tables. */
|
/** Save const tables first as used tables. */
|
||||||
|
|
||||||
static void
|
void set_position(JOIN *join,uint idx,JOIN_TAB *table,KEYUSE *key)
|
||||||
set_position(JOIN *join,uint idx,JOIN_TAB *table,KEYUSE *key)
|
|
||||||
{
|
{
|
||||||
join->positions[idx].table= table;
|
join->positions[idx].table= table;
|
||||||
join->positions[idx].key=key;
|
join->positions[idx].key=key;
|
||||||
@ -4592,7 +4625,7 @@ choose_plan(JOIN *join, table_map join_tables)
|
|||||||
DBUG_ENTER("choose_plan");
|
DBUG_ENTER("choose_plan");
|
||||||
|
|
||||||
join->cur_embedding_map= 0;
|
join->cur_embedding_map= 0;
|
||||||
reset_nj_counters(join->join_list);
|
reset_nj_counters(join, join->join_list);
|
||||||
/*
|
/*
|
||||||
if (SELECT_STRAIGHT_JOIN option is set)
|
if (SELECT_STRAIGHT_JOIN option is set)
|
||||||
reorder tables so dependent tables come after tables they depend
|
reorder tables so dependent tables come after tables they depend
|
||||||
@ -5757,6 +5790,7 @@ JOIN::make_simple_join(JOIN *parent, TABLE *tmp_table)
|
|||||||
tables= 1;
|
tables= 1;
|
||||||
const_tables= 0;
|
const_tables= 0;
|
||||||
const_table_map= 0;
|
const_table_map= 0;
|
||||||
|
eliminated_tables= 0;
|
||||||
tmp_table_param.field_count= tmp_table_param.sum_func_count=
|
tmp_table_param.field_count= tmp_table_param.sum_func_count=
|
||||||
tmp_table_param.func_count= 0;
|
tmp_table_param.func_count= 0;
|
||||||
tmp_table_param.copy_field= tmp_table_param.copy_field_end=0;
|
tmp_table_param.copy_field= tmp_table_param.copy_field_end=0;
|
||||||
@ -6021,7 +6055,7 @@ make_outerjoin_info(JOIN *join)
|
|||||||
}
|
}
|
||||||
if (!tab->first_inner)
|
if (!tab->first_inner)
|
||||||
tab->first_inner= nested_join->first_nested;
|
tab->first_inner= nested_join->first_nested;
|
||||||
if (++nested_join->counter < nested_join->join_list.elements)
|
if (++nested_join->counter < nested_join->n_tables)
|
||||||
break;
|
break;
|
||||||
/* Table tab is the last inner table for nested join. */
|
/* Table tab is the last inner table for nested join. */
|
||||||
nested_join->first_nested->last_inner= tab;
|
nested_join->first_nested->last_inner= tab;
|
||||||
@ -8575,6 +8609,8 @@ simplify_joins(JOIN *join, List<TABLE_LIST> *join_list, COND *conds, bool top)
|
|||||||
conds= simplify_joins(join, &nested_join->join_list, conds, top);
|
conds= simplify_joins(join, &nested_join->join_list, conds, top);
|
||||||
used_tables= nested_join->used_tables;
|
used_tables= nested_join->used_tables;
|
||||||
not_null_tables= nested_join->not_null_tables;
|
not_null_tables= nested_join->not_null_tables;
|
||||||
|
/* The following two might become unequal after table elimination: */
|
||||||
|
nested_join->n_tables= nested_join->join_list.elements;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -8733,7 +8769,7 @@ static uint build_bitmap_for_nested_joins(List<TABLE_LIST> *join_list,
|
|||||||
with anything)
|
with anything)
|
||||||
2. we could run out bits in nested_join_map otherwise.
|
2. we could run out bits in nested_join_map otherwise.
|
||||||
*/
|
*/
|
||||||
if (nested_join->join_list.elements != 1)
|
if (nested_join->n_tables != 1)
|
||||||
{
|
{
|
||||||
nested_join->nj_map= (nested_join_map) 1 << first_unused++;
|
nested_join->nj_map= (nested_join_map) 1 << first_unused++;
|
||||||
first_unused= build_bitmap_for_nested_joins(&nested_join->join_list,
|
first_unused= build_bitmap_for_nested_joins(&nested_join->join_list,
|
||||||
@ -8755,21 +8791,26 @@ static uint build_bitmap_for_nested_joins(List<TABLE_LIST> *join_list,
|
|||||||
tables which will be ignored.
|
tables which will be ignored.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static void reset_nj_counters(List<TABLE_LIST> *join_list)
|
static uint reset_nj_counters(JOIN *join, List<TABLE_LIST> *join_list)
|
||||||
{
|
{
|
||||||
List_iterator<TABLE_LIST> li(*join_list);
|
List_iterator<TABLE_LIST> li(*join_list);
|
||||||
TABLE_LIST *table;
|
TABLE_LIST *table;
|
||||||
DBUG_ENTER("reset_nj_counters");
|
DBUG_ENTER("reset_nj_counters");
|
||||||
|
uint n=0;
|
||||||
while ((table= li++))
|
while ((table= li++))
|
||||||
{
|
{
|
||||||
NESTED_JOIN *nested_join;
|
NESTED_JOIN *nested_join;
|
||||||
if ((nested_join= table->nested_join))
|
if ((nested_join= table->nested_join))
|
||||||
{
|
{
|
||||||
nested_join->counter= 0;
|
nested_join->counter= 0;
|
||||||
reset_nj_counters(&nested_join->join_list);
|
//nested_join->n_tables= my_count_bits(nested_join->used_tables &
|
||||||
|
// ~join->eliminated_tables);
|
||||||
|
nested_join->n_tables= reset_nj_counters(join, &nested_join->join_list);
|
||||||
}
|
}
|
||||||
|
if (table->table && (table->table->map & ~join->eliminated_tables))
|
||||||
|
n++;
|
||||||
}
|
}
|
||||||
DBUG_VOID_RETURN;
|
DBUG_RETURN(n);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -8894,7 +8935,7 @@ static bool check_interleaving_with_nj(JOIN_TAB *next_tab)
|
|||||||
join->cur_embedding_map |= next_emb->nested_join->nj_map;
|
join->cur_embedding_map |= next_emb->nested_join->nj_map;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (next_emb->nested_join->join_list.elements !=
|
if (next_emb->nested_join->n_tables !=
|
||||||
next_emb->nested_join->counter)
|
next_emb->nested_join->counter)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -8926,9 +8967,23 @@ static void restore_prev_nj_state(JOIN_TAB *last)
|
|||||||
JOIN *join= last->join;
|
JOIN *join= last->join;
|
||||||
while (last_emb)
|
while (last_emb)
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
psergey-elim: (nevermind)
|
||||||
|
new_prefix= cur_prefix & ~last;
|
||||||
|
if (!(new_prefix & cur_table_map)) // removed last inner table
|
||||||
|
{
|
||||||
|
join->cur_embedding_map&= ~last_emb->nested_join->nj_map;
|
||||||
|
}
|
||||||
|
else (current)
|
||||||
|
{
|
||||||
|
// Won't hurt doing it all the time:
|
||||||
|
join->cur_embedding_map |= ...;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
*/
|
||||||
if (!(--last_emb->nested_join->counter))
|
if (!(--last_emb->nested_join->counter))
|
||||||
join->cur_embedding_map&= ~last_emb->nested_join->nj_map;
|
join->cur_embedding_map&= ~last_emb->nested_join->nj_map;
|
||||||
else if (last_emb->nested_join->join_list.elements-1 ==
|
else if (last_emb->nested_join->n_tables-1 ==
|
||||||
last_emb->nested_join->counter)
|
last_emb->nested_join->counter)
|
||||||
join->cur_embedding_map|= last_emb->nested_join->nj_map;
|
join->cur_embedding_map|= last_emb->nested_join->nj_map;
|
||||||
else
|
else
|
||||||
@ -16238,6 +16293,14 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
|
|||||||
tmp3.length(0);
|
tmp3.length(0);
|
||||||
|
|
||||||
quick_type= -1;
|
quick_type= -1;
|
||||||
|
|
||||||
|
/* Don't show eliminated tables */
|
||||||
|
if (table->map & join->eliminated_tables)
|
||||||
|
{
|
||||||
|
used_tables|=table->map;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
item_list.empty();
|
item_list.empty();
|
||||||
/* id */
|
/* id */
|
||||||
item_list.push_back(new Item_uint((uint32)
|
item_list.push_back(new Item_uint((uint32)
|
||||||
@ -16560,8 +16623,11 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
|
|||||||
unit;
|
unit;
|
||||||
unit= unit->next_unit())
|
unit= unit->next_unit())
|
||||||
{
|
{
|
||||||
if (mysql_explain_union(thd, unit, result))
|
if (!(unit->item && unit->item->eliminated))
|
||||||
DBUG_VOID_RETURN;
|
{
|
||||||
|
if (mysql_explain_union(thd, unit, result))
|
||||||
|
DBUG_VOID_RETURN;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
DBUG_VOID_RETURN;
|
DBUG_VOID_RETURN;
|
||||||
}
|
}
|
||||||
@ -16602,7 +16668,6 @@ bool mysql_explain_union(THD *thd, SELECT_LEX_UNIT *unit, select_result *result)
|
|||||||
unit->fake_select_lex->options|= SELECT_DESCRIBE;
|
unit->fake_select_lex->options|= SELECT_DESCRIBE;
|
||||||
if (!(res= unit->prepare(thd, result, SELECT_NO_UNLOCK | SELECT_DESCRIBE)))
|
if (!(res= unit->prepare(thd, result, SELECT_NO_UNLOCK | SELECT_DESCRIBE)))
|
||||||
res= unit->exec();
|
res= unit->exec();
|
||||||
res|= unit->cleanup();
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -16635,6 +16700,7 @@ bool mysql_explain_union(THD *thd, SELECT_LEX_UNIT *unit, select_result *result)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
static void print_join(THD *thd,
|
static void print_join(THD *thd,
|
||||||
|
table_map eliminated_tables,
|
||||||
String *str,
|
String *str,
|
||||||
List<TABLE_LIST> *tables,
|
List<TABLE_LIST> *tables,
|
||||||
enum_query_type query_type)
|
enum_query_type query_type)
|
||||||
@ -16650,12 +16716,33 @@ static void print_join(THD *thd,
|
|||||||
*t= ti++;
|
*t= ti++;
|
||||||
|
|
||||||
DBUG_ASSERT(tables->elements >= 1);
|
DBUG_ASSERT(tables->elements >= 1);
|
||||||
(*table)->print(thd, str, query_type);
|
/*
|
||||||
|
Assert that the first table in the list isn't eliminated. This comes from
|
||||||
|
the fact that the first table can't be inner table of an outer join.
|
||||||
|
*/
|
||||||
|
DBUG_ASSERT(!eliminated_tables ||
|
||||||
|
!(((*table)->table && ((*table)->table->map & eliminated_tables)) ||
|
||||||
|
((*table)->nested_join && !((*table)->nested_join->used_tables &
|
||||||
|
~eliminated_tables))));
|
||||||
|
(*table)->print(thd, eliminated_tables, str, query_type);
|
||||||
|
|
||||||
TABLE_LIST **end= table + tables->elements;
|
TABLE_LIST **end= table + tables->elements;
|
||||||
for (TABLE_LIST **tbl= table + 1; tbl < end; tbl++)
|
for (TABLE_LIST **tbl= table + 1; tbl < end; tbl++)
|
||||||
{
|
{
|
||||||
TABLE_LIST *curr= *tbl;
|
TABLE_LIST *curr= *tbl;
|
||||||
|
/*
|
||||||
|
The "eliminated_tables &&" check guards againist the case of
|
||||||
|
printing the query for CREATE VIEW. We do that without having run
|
||||||
|
JOIN::optimize() and so will have nested_join->used_tables==0.
|
||||||
|
*/
|
||||||
|
if (eliminated_tables &&
|
||||||
|
((curr->table && (curr->table->map & eliminated_tables)) ||
|
||||||
|
(curr->nested_join && !(curr->nested_join->used_tables &
|
||||||
|
~eliminated_tables))))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (curr->outer_join)
|
if (curr->outer_join)
|
||||||
{
|
{
|
||||||
/* MySQL converts right to left joins */
|
/* MySQL converts right to left joins */
|
||||||
@ -16665,7 +16752,7 @@ static void print_join(THD *thd,
|
|||||||
str->append(STRING_WITH_LEN(" straight_join "));
|
str->append(STRING_WITH_LEN(" straight_join "));
|
||||||
else
|
else
|
||||||
str->append(STRING_WITH_LEN(" join "));
|
str->append(STRING_WITH_LEN(" join "));
|
||||||
curr->print(thd, str, query_type);
|
curr->print(thd, eliminated_tables, str, query_type);
|
||||||
if (curr->on_expr)
|
if (curr->on_expr)
|
||||||
{
|
{
|
||||||
str->append(STRING_WITH_LEN(" on("));
|
str->append(STRING_WITH_LEN(" on("));
|
||||||
@ -16719,12 +16806,13 @@ Index_hint::print(THD *thd, String *str)
|
|||||||
@param str string where table should be printed
|
@param str string where table should be printed
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void TABLE_LIST::print(THD *thd, String *str, enum_query_type query_type)
|
void TABLE_LIST::print(THD *thd, table_map eliminated_tables, String *str,
|
||||||
|
enum_query_type query_type)
|
||||||
{
|
{
|
||||||
if (nested_join)
|
if (nested_join)
|
||||||
{
|
{
|
||||||
str->append('(');
|
str->append('(');
|
||||||
print_join(thd, str, &nested_join->join_list, query_type);
|
print_join(thd, eliminated_tables, str, &nested_join->join_list, query_type);
|
||||||
str->append(')');
|
str->append(')');
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -16866,7 +16954,7 @@ void st_select_lex::print(THD *thd, String *str, enum_query_type query_type)
|
|||||||
{
|
{
|
||||||
str->append(STRING_WITH_LEN(" from "));
|
str->append(STRING_WITH_LEN(" from "));
|
||||||
/* go through join tree */
|
/* go through join tree */
|
||||||
print_join(thd, str, &top_join_list, query_type);
|
print_join(thd, join? join->eliminated_tables: 0, str, &top_join_list, query_type);
|
||||||
}
|
}
|
||||||
else if (where)
|
else if (where)
|
||||||
{
|
{
|
||||||
|
@ -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:
|
|||||||
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:
|
|||||||
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);
|
|||||||
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);
|
||||||
|
|
||||||
|
14
sql/table.h
14
sql/table.h
@ -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:
|
|||||||
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
|
|||||||
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;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user