diff options
author | Galina Shalygina <galina.shalygina@mariadb.com> | 2018-02-06 14:02:57 +0200 |
---|---|---|
committer | Galina Shalygina <galina.shalygina@mariadb.com> | 2018-05-05 17:42:23 +0200 |
commit | 79a7641b40c7b12dda4a6e30e7688b2f796e6a98 (patch) | |
tree | fa985171228a17a05280e296e40fa7a8f7aca233 | |
parent | f271100836d8a91a775894ec36b869a66a3145e5 (diff) | |
download | mariadb-git-79a7641b40c7b12dda4a6e30e7688b2f796e6a98.tar.gz |
MDEV-12387 Push conditions into materialized subqueries
The logic and the implementation scheme are similar with the
MDEV-9197 Pushdown conditions into non-mergeable views/derived tables
How the push down is made on the example:
select * from t1
where a>3 and b>10 and
(a,b) in (select x,max(y) from t2 group by x);
-->
select * from t1
where a>3 and b>10 and
(a,b) in (select x,max(y)
from t2
where x>3
group by x
having max(y)>10);
The implementation scheme:
1. Search for the condition cond that depends only on the fields
from the left part of the IN subquery (left_part)
2. Find fields F_group in the select of the right part of the
IN subquery (right_part) that are used in the GROUP BY
3. Extract from the cond condition cond_where that depends only on the
fields from the left_part that stay at the same places in the left_part
(have the same indexes) as the F_group fields in the projection of the
right_part
4. Transform cond_where so it can be pushed into the WHERE clause of the
right_part and delete cond_where from the cond
5. Transform cond so it can be pushed into the HAVING clause of the right_part
The optimization is made in the
Item_in_subselect::pushdown_cond_for_in_subquery() and is controlled by the
variable condition_pushdown_for_subquery.
New test file in_subq_cond_pushdown.test is created.
There are also some changes made for setup_jtbm_semi_joins().
Now it is decomposed into the 2 procedures: setup_degenerate_jtbm_semi_joins()
that is called before optimize_cond() for cond and setup_jtbm_semi_joins()
that is called after optimize_cond().
New setup_jtbm_semi_joins() is made in the way so that the result of its work is
the same as if it was called before optimize_cond().
The code that is common for pushdown into materialized derived and into materialized
IN subqueries is factored out into pushdown_cond_for_derived(),
Item_in_subselect::pushdown_cond_for_in_subquery() and
st_select_lex::pushdown_cond_into_where_clause().
29 files changed, 6101 insertions, 491 deletions
diff --git a/mysql-test/r/derived.result b/mysql-test/r/derived.result index 32184c5637b..75b53911436 100644 --- a/mysql-test/r/derived.result +++ b/mysql-test/r/derived.result @@ -632,7 +632,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 2 DERIVED t1 system NULL NULL NULL NULL 1 100.00 Warnings: Note 1276 Field or reference 'sq.f2' of SELECT #3 was resolved in SELECT #1 -Note 1003 /* select#1 */ select 6 AS `f1` from <materialize> (/* select#4 */ select `test`.`t2`.`f3` from `test`.`t2` having `test`.`t2`.`f3` >= 8) semi join (`test`.`t2`) where `test`.`t2`.`f3` = 6 and `<subquery4>`.`f3` = 9 +Note 1003 /* select#1 */ select 6 AS `f1` from <materialize> (/* select#4 */ select `test`.`t2`.`f3` from `test`.`t2` having `test`.`t2`.`f3` >= 8) semi join (`test`.`t2`) where `<subquery4>`.`f3` = 9 and `test`.`t2`.`f3` = 6 DROP TABLE t2,t1; # # MDEV-9462: Out of memory using explain on 2 empty tables diff --git a/mysql-test/r/in_subq_cond_pushdown.result b/mysql-test/r/in_subq_cond_pushdown.result new file mode 100644 index 00000000000..b9e55229ff8 --- /dev/null +++ b/mysql-test/r/in_subq_cond_pushdown.result @@ -0,0 +1,3801 @@ +CREATE TABLE t1 (a INT, b INT, c INT, d INT); +CREATE TABLE t2 (e INT, f INT, g INT); +CREATE TABLE t3 (x INT, y INT); +INSERT INTO t1 VALUES +(1,1,18,1), (2,1,25,1), (1,3,40,1), (2,3,40,4), +(4,2,24,4), (3,2,23,1), (1,2,40,2), (3,4,17,2), +(5,5,65,1), (2,3,70,3), (1,4,35,3), (2,3,25,3), +(2,2,40,4), (1,4,55,1), (5,3,72,4), (1,2,70,5); +INSERT INTO t2 VALUES +(1,2,38), (2,3,15), (1,3,40), (1,4,35), +(2,2,70), (3,4,23), (5,5,12), (5,4,17), +(3,3,17), (4,2,24), (2,5,25), (5,1,65); +INSERT INTO t3 VALUES +(1,25), (1,18), (2,15), (4,24), +(1,35), (3,23), (3,17), (2,15); +CREATE VIEW v1 AS +( +SELECT t3.x AS v1_x, t3.y AS v1_y FROM t3 WHERE t3.x<=3 +); +CREATE VIEW v2 AS +( +SELECT t2.e, t2.f, MAX(t2.g) AS max_g +FROM t2 +GROUP BY t2.e +HAVING max_g>25 +); +# conjunctive subformula : pushing into HAVING +SET STATEMENT optimizer_switch='condition_pushdown_for_subquery=off' FOR SELECT * FROM t1 +WHERE t1.c<25 AND +(t1.a,t1.c) IN (SELECT t2.e,MAX(t2.g) FROM t2 WHERE t2.e<5 GROUP BY t2.e); +a b c d +4 2 24 4 +3 2 23 1 +SELECT * FROM t1 +WHERE t1.c<25 AND +(t1.a,t1.c) IN (SELECT t2.e,MAX(t2.g) FROM t2 WHERE t2.e<5 GROUP BY t2.e); +a b c d +4 2 24 4 +3 2 23 1 +EXPLAIN SELECT * FROM t1 +WHERE t1.c<25 AND +(t1.a,t1.c) IN (SELECT t2.e,MAX(t2.g) FROM t2 WHERE t2.e<5 GROUP BY t2.e); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 16 Using where +1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 8 test.t1.a,test.t1.c 1 +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 12 Using where; Using temporary +EXPLAIN FORMAT=JSON SELECT * FROM t1 +WHERE t1.c<25 AND +(t1.a,t1.c) IN (SELECT t2.e,MAX(t2.g) FROM t2 WHERE t2.e<5 GROUP BY t2.e); +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 16, + "filtered": 100, + "attached_condition": "t1.c < 25 and t1.a is not null and t1.c is not null" + }, + "table": { + "table_name": "<subquery2>", + "access_type": "eq_ref", + "possible_keys": ["distinct_key"], + "key": "distinct_key", + "key_length": "8", + "used_key_parts": ["e", "MAX(t2.g)"], + "ref": ["test.t1.a", "test.t1.c"], + "rows": 1, + "filtered": 100, + "materialized": { + "unique": 1, + "query_block": { + "select_id": 2, + "having_condition": "`MAX(t2.g)` < 25", + "temporary_table": { + "table": { + "table_name": "t2", + "access_type": "ALL", + "rows": 12, + "filtered": 100, + "attached_condition": "t2.e < 5" + } + } + } + } + } + } +} +# extracted AND formula : pushing into HAVING +SET STATEMENT optimizer_switch='condition_pushdown_for_subquery=off' FOR SELECT * FROM t1 +WHERE t1.c>55 AND t1.b<4 AND +(t1.a,t1.b,t1.c) IN +( +SELECT t2.e,t2.f,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e +) +; +a b c d +2 3 70 3 +SELECT * FROM t1 +WHERE t1.c>55 AND t1.b<4 AND +(t1.a,t1.b,t1.c) IN +( +SELECT t2.e,t2.f,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e +) +; +a b c d +2 3 70 3 +EXPLAIN SELECT * FROM t1 +WHERE t1.c>55 AND t1.b<4 AND +(t1.a,t1.b,t1.c) IN +( +SELECT t2.e,t2.f,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e +) +; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 16 Using where +1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 12 test.t1.a,test.t1.b,test.t1.c 1 +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 12 Using where; Using temporary +EXPLAIN FORMAT=JSON SELECT * FROM t1 +WHERE t1.c>55 AND t1.b<4 AND +(t1.a,t1.b,t1.c) IN +( +SELECT t2.e,t2.f,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e +) +; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 16, + "filtered": 100, + "attached_condition": "t1.c > 55 and t1.b < 4 and t1.a is not null and t1.b is not null and t1.c is not null" + }, + "table": { + "table_name": "<subquery2>", + "access_type": "eq_ref", + "possible_keys": ["distinct_key"], + "key": "distinct_key", + "key_length": "12", + "used_key_parts": ["e", "f", "MAX(t2.g)"], + "ref": ["test.t1.a", "test.t1.b", "test.t1.c"], + "rows": 1, + "filtered": 100, + "materialized": { + "unique": 1, + "query_block": { + "select_id": 2, + "having_condition": "`MAX(t2.g)` > 55 and t2.f < 4", + "temporary_table": { + "table": { + "table_name": "t2", + "access_type": "ALL", + "rows": 12, + "filtered": 100, + "attached_condition": "t2.e < 5" + } + } + } + } + } + } +} +# extracted OR formula : pushing into HAVING +SET STATEMENT optimizer_switch='condition_pushdown_for_subquery=off' FOR SELECT * FROM t1 +WHERE (t1.c>60 OR t1.c<25) AND +(t1.a,t1.b,t1.c) IN +( +SELECT t2.e,t2.f,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e +) +; +a b c d +4 2 24 4 +2 3 70 3 +SELECT * FROM t1 +WHERE (t1.c>60 OR t1.c<25) AND +(t1.a,t1.b,t1.c) IN +( +SELECT t2.e,t2.f,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e +) +; +a b c d +4 2 24 4 +2 3 70 3 +EXPLAIN SELECT * FROM t1 +WHERE (t1.c>60 OR t1.c<25) AND +(t1.a,t1.b,t1.c) IN +( +SELECT t2.e,t2.f,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e +) +; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 16 Using where +1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 12 test.t1.a,test.t1.b,test.t1.c 1 +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 12 Using where; Using temporary +EXPLAIN FORMAT=JSON SELECT * FROM t1 +WHERE (t1.c>60 OR t1.c<25) AND +(t1.a,t1.b,t1.c) IN +( +SELECT t2.e,t2.f,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e +) +; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 16, + "filtered": 100, + "attached_condition": "(t1.c > 60 or t1.c < 25) and t1.a is not null and t1.b is not null and t1.c is not null" + }, + "table": { + "table_name": "<subquery2>", + "access_type": "eq_ref", + "possible_keys": ["distinct_key"], + "key": "distinct_key", + "key_length": "12", + "used_key_parts": ["e", "f", "MAX(t2.g)"], + "ref": ["test.t1.a", "test.t1.b", "test.t1.c"], + "rows": 1, + "filtered": 100, + "materialized": { + "unique": 1, + "query_block": { + "select_id": 2, + "having_condition": "`MAX(t2.g)` > 60 or `MAX(t2.g)` < 25", + "temporary_table": { + "table": { + "table_name": "t2", + "access_type": "ALL", + "rows": 12, + "filtered": 100, + "attached_condition": "t2.e < 5" + } + } + } + } + } + } +} +# extracted AND-OR formula : pushing into HAVING +SET STATEMENT optimizer_switch='condition_pushdown_for_subquery=off' FOR SELECT * FROM t1 +WHERE ((t1.c>60 OR t1.c<25) AND t1.b>2) AND +(t1.a,t1.b,t1.c) IN +( +SELECT t2.e,t2.f,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e +) +; +a b c d +2 3 70 3 +SELECT * FROM t1 +WHERE ((t1.c>60 OR t1.c<25) AND t1.b>2) AND +(t1.a,t1.b,t1.c) IN +( +SELECT t2.e,t2.f,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e +) +; +a b c d +2 3 70 3 +EXPLAIN SELECT * FROM t1 +WHERE ((t1.c>60 OR t1.c<25) AND t1.b>2) AND +(t1.a,t1.b,t1.c) IN +( +SELECT t2.e,t2.f,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e +) +; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 16 Using where +1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 12 test.t1.a,test.t1.b,test.t1.c 1 +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 12 Using where; Using temporary +EXPLAIN FORMAT=JSON SELECT * FROM t1 +WHERE ((t1.c>60 OR t1.c<25) AND t1.b>2) AND +(t1.a,t1.b,t1.c) IN +( +SELECT t2.e,t2.f,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e +) +; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 16, + "filtered": 100, + "attached_condition": "(t1.c > 60 or t1.c < 25) and t1.b > 2 and t1.a is not null and t1.b is not null and t1.c is not null" + }, + "table": { + "table_name": "<subquery2>", + "access_type": "eq_ref", + "possible_keys": ["distinct_key"], + "key": "distinct_key", + "key_length": "12", + "used_key_parts": ["e", "f", "MAX(t2.g)"], + "ref": ["test.t1.a", "test.t1.b", "test.t1.c"], + "rows": 1, + "filtered": 100, + "materialized": { + "unique": 1, + "query_block": { + "select_id": 2, + "having_condition": "(`MAX(t2.g)` > 60 or `MAX(t2.g)` < 25) and t2.f > 2", + "temporary_table": { + "table": { + "table_name": "t2", + "access_type": "ALL", + "rows": 12, + "filtered": 100, + "attached_condition": "t2.e < 5" + } + } + } + } + } + } +} +# conjunctive subformula : pushing into HAVING +SET STATEMENT optimizer_switch='condition_pushdown_for_subquery=off' FOR SELECT * FROM t1 +WHERE ((t1.a<2 OR t1.d>3) AND t1.b>1) AND +(t1.a,t1.b,t1.c) IN +( +SELECT t2.e,t2.f,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e +) +; +a b c d +4 2 24 4 +1 2 40 2 +SELECT * FROM t1 +WHERE ((t1.a<2 OR t1.d>3) AND t1.b>1) AND +(t1.a,t1.b,t1.c) IN +( +SELECT t2.e,t2.f,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e +) +; +a b c d +4 2 24 4 +1 2 40 2 +EXPLAIN SELECT * FROM t1 +WHERE ((t1.a<2 OR t1.d>3) AND t1.b>1) AND +(t1.a,t1.b,t1.c) IN +( +SELECT t2.e,t2.f,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e +) +; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 16 Using where +1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 12 test.t1.a,test.t1.b,test.t1.c 1 +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 12 Using where; Using temporary +EXPLAIN FORMAT=JSON SELECT * FROM t1 +WHERE ((t1.a<2 OR t1.d>3) AND t1.b>1) AND +(t1.a,t1.b,t1.c) IN +( +SELECT t2.e,t2.f,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e +) +; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 16, + "filtered": 100, + "attached_condition": "(t1.a < 2 or t1.d > 3) and t1.b > 1 and t1.a is not null and t1.b is not null and t1.c is not null" + }, + "table": { + "table_name": "<subquery2>", + "access_type": "eq_ref", + "possible_keys": ["distinct_key"], + "key": "distinct_key", + "key_length": "12", + "used_key_parts": ["e", "f", "MAX(t2.g)"], + "ref": ["test.t1.a", "test.t1.b", "test.t1.c"], + "rows": 1, + "filtered": 100, + "materialized": { + "unique": 1, + "query_block": { + "select_id": 2, + "having_condition": "t2.f > 1", + "temporary_table": { + "table": { + "table_name": "t2", + "access_type": "ALL", + "rows": 12, + "filtered": 100, + "attached_condition": "t2.e < 5" + } + } + } + } + } + } +} +# using view IN subquery defINition : pushing into HAVING +SET STATEMENT optimizer_switch='condition_pushdown_for_subquery=off' FOR SELECT * FROM t1 +WHERE t1.c>20 AND +(t1.a,t1.c) IN +( +SELECT v1_x,MAX(v1_y) +FROM v1 +WHERE v1_x>1 +GROUP BY v1_x +) +; +a b c d +3 2 23 1 +SELECT * FROM t1 +WHERE t1.c>20 AND +(t1.a,t1.c) IN +( +SELECT v1_x,MAX(v1_y) +FROM v1 +WHERE v1_x>1 +GROUP BY v1_x +) +; +a b c d +3 2 23 1 +EXPLAIN SELECT * FROM t1 +WHERE t1.c>20 AND +(t1.a,t1.c) IN +( +SELECT v1_x,MAX(v1_y) +FROM v1 +WHERE v1_x>1 +GROUP BY v1_x +) +; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 16 Using where +1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 8 test.t1.a,test.t1.c 1 +2 MATERIALIZED t3 ALL NULL NULL NULL NULL 8 Using where; Using temporary +EXPLAIN FORMAT=JSON SELECT * FROM t1 +WHERE t1.c>20 AND +(t1.a,t1.c) IN +( +SELECT v1_x,MAX(v1_y) +FROM v1 +WHERE v1_x>1 +GROUP BY v1_x +) +; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 16, + "filtered": 100, + "attached_condition": "t1.c > 20 and t1.a is not null and t1.c is not null" + }, + "table": { + "table_name": "<subquery2>", + "access_type": "eq_ref", + "possible_keys": ["distinct_key"], + "key": "distinct_key", + "key_length": "8", + "used_key_parts": ["v1_x", "MAX(v1_y)"], + "ref": ["test.t1.a", "test.t1.c"], + "rows": 1, + "filtered": 100, + "materialized": { + "unique": 1, + "query_block": { + "select_id": 2, + "having_condition": "`MAX(v1_y)` > 20", + "temporary_table": { + "table": { + "table_name": "t3", + "access_type": "ALL", + "rows": 8, + "filtered": 100, + "attached_condition": "t3.x > 1 and t3.x <= 3" + } + } + } + } + } + } +} +# using equality : pushing into WHERE +SET STATEMENT optimizer_switch='condition_pushdown_for_subquery=off' FOR SELECT * FROM t1,v1 +WHERE t1.c>20 AND t1.c=v1_y AND +(t1.a,t1.c) IN +( +SELECT t2.e,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e +) +; +a b c d v1_x v1_y +3 2 23 1 3 23 +SELECT * FROM t1,v1 +WHERE t1.c>20 AND t1.c=v1_y AND +(t1.a,t1.c) IN +( +SELECT t2.e,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e +) +; +a b c d v1_x v1_y +3 2 23 1 3 23 +EXPLAIN SELECT * FROM t1,v1 +WHERE t1.c>20 AND t1.c=v1_y AND +(t1.a,t1.c) IN +( +SELECT t2.e,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e +) +; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t3 ALL NULL NULL NULL NULL 8 Using where +1 PRIMARY t1 ALL NULL NULL NULL NULL 16 Using where; Using join buffer (flat, BNL join) +1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 8 test.t1.a,test.t3.y 1 +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 12 Using where; Using temporary +EXPLAIN FORMAT=JSON SELECT * FROM t1,v1 +WHERE t1.c>20 AND t1.c=v1_y AND +(t1.a,t1.c) IN +( +SELECT t2.e,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e +) +; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "t3", + "access_type": "ALL", + "rows": 8, + "filtered": 100, + "attached_condition": "t3.y > 20 and t3.x <= 3 and t3.y is not null" + }, + "block-nl-join": { + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 16, + "filtered": 100 + }, + "buffer_type": "flat", + "buffer_size": "256Kb", + "join_type": "BNL", + "attached_condition": "t1.c = t3.y and t1.a is not null" + }, + "table": { + "table_name": "<subquery2>", + "access_type": "eq_ref", + "possible_keys": ["distinct_key"], + "key": "distinct_key", + "key_length": "8", + "used_key_parts": ["e", "MAX(t2.g)"], + "ref": ["test.t1.a", "test.t3.y"], + "rows": 1, + "filtered": 100, + "materialized": { + "unique": 1, + "query_block": { + "select_id": 2, + "having_condition": "`MAX(t2.g)` > 20", + "temporary_table": { + "table": { + "table_name": "t2", + "access_type": "ALL", + "rows": 12, + "filtered": 100, + "attached_condition": "t2.e < 5" + } + } + } + } + } + } +} +# conjunctive subformula : pushing into WHERE +SET STATEMENT optimizer_switch='condition_pushdown_for_subquery=off' FOR SELECT * FROM t1 +WHERE t1.a<2 AND +(t1.a,t1.c) IN +( +SELECT t2.e,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e +) +; +a b c d +1 3 40 1 +1 2 40 2 +SELECT * FROM t1 +WHERE t1.a<2 AND +(t1.a,t1.c) IN +( +SELECT t2.e,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e +) +; +a b c d +1 3 40 1 +1 2 40 2 +EXPLAIN SELECT * FROM t1 +WHERE t1.a<2 AND +(t1.a,t1.c) IN +( +SELECT t2.e,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e +) +; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 16 Using where +1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 8 test.t1.a,test.t1.c 1 +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 12 Using where; Using temporary +EXPLAIN FORMAT=JSON SELECT * FROM t1 +WHERE t1.a<2 AND +(t1.a,t1.c) IN +( +SELECT t2.e,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e +) +; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 16, + "filtered": 100, + "attached_condition": "t1.a < 2 and t1.a is not null and t1.c is not null" + }, + "table": { + "table_name": "<subquery2>", + "access_type": "eq_ref", + "possible_keys": ["distinct_key"], + "key": "distinct_key", + "key_length": "8", + "used_key_parts": ["e", "MAX(t2.g)"], + "ref": ["test.t1.a", "test.t1.c"], + "rows": 1, + "filtered": 100, + "materialized": { + "unique": 1, + "query_block": { + "select_id": 2, + "temporary_table": { + "table": { + "table_name": "t2", + "access_type": "ALL", + "rows": 12, + "filtered": 100, + "attached_condition": "t2.e < 5 and t2.e < 2" + } + } + } + } + } + } +} +# extracted AND formula : pushing into WHERE +SET STATEMENT optimizer_switch='condition_pushdown_for_subquery=off' FOR SELECT * FROM t1 +WHERE t1.a>2 AND t1.a<5 AND +(t1.a,t1.c) IN +( +SELECT t2.e,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e +) +; +a b c d +4 2 24 4 +3 2 23 1 +SELECT * FROM t1 +WHERE t1.a>2 AND t1.a<5 AND +(t1.a,t1.c) IN +( +SELECT t2.e,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e +) +; +a b c d +4 2 24 4 +3 2 23 1 +EXPLAIN SELECT * FROM t1 +WHERE t1.a>2 AND t1.a<5 AND +(t1.a,t1.c) IN +( +SELECT t2.e,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e +) +; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 16 Using where +1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 8 test.t1.a,test.t1.c 1 +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 12 Using where; Using temporary +EXPLAIN FORMAT=JSON SELECT * FROM t1 +WHERE t1.a>2 AND t1.a<5 AND +(t1.a,t1.c) IN +( +SELECT t2.e,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e +) +; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 16, + "filtered": 100, + "attached_condition": "t1.a > 2 and t1.a < 5 and t1.a is not null and t1.c is not null" + }, + "table": { + "table_name": "<subquery2>", + "access_type": "eq_ref", + "possible_keys": ["distinct_key"], + "key": "distinct_key", + "key_length": "8", + "used_key_parts": ["e", "MAX(t2.g)"], + "ref": ["test.t1.a", "test.t1.c"], + "rows": 1, + "filtered": 100, + "materialized": { + "unique": 1, + "query_block": { + "select_id": 2, + "temporary_table": { + "table": { + "table_name": "t2", + "access_type": "ALL", + "rows": 12, + "filtered": 100, + "attached_condition": "t2.e < 5 and t2.e > 2 and t2.e < 5" + } + } + } + } + } + } +} +# extracted OR formula : pushing into WHERE +SET STATEMENT optimizer_switch='condition_pushdown_for_subquery=off' FOR SELECT * FROM t1 +WHERE (t1.a<2 OR t1.a>=4) AND +(t1.a,t1.c) IN +( +SELECT t2.e,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e +) +; +a b c d +1 3 40 1 +4 2 24 4 +1 2 40 2 +SELECT * FROM t1 +WHERE (t1.a<2 OR t1.a>=4) AND +(t1.a,t1.c) IN +( +SELECT t2.e,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e +) +; +a b c d +1 3 40 1 +4 2 24 4 +1 2 40 2 +EXPLAIN SELECT * FROM t1 +WHERE (t1.a<2 OR t1.a>=4) AND +(t1.a,t1.c) IN +( +SELECT t2.e,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e +) +; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 16 Using where +1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 8 test.t1.a,test.t1.c 1 +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 12 Using where; Using temporary +EXPLAIN FORMAT=JSON SELECT * FROM t1 +WHERE (t1.a<2 OR t1.a>=4) AND +(t1.a,t1.c) IN +( +SELECT t2.e,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e +) +; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 16, + "filtered": 100, + "attached_condition": "(t1.a < 2 or t1.a >= 4) and t1.a is not null and t1.c is not null" + }, + "table": { + "table_name": "<subquery2>", + "access_type": "eq_ref", + "possible_keys": ["distinct_key"], + "key": "distinct_key", + "key_length": "8", + "used_key_parts": ["e", "MAX(t2.g)"], + "ref": ["test.t1.a", "test.t1.c"], + "rows": 1, + "filtered": 100, + "materialized": { + "unique": 1, + "query_block": { + "select_id": 2, + "temporary_table": { + "table": { + "table_name": "t2", + "access_type": "ALL", + "rows": 12, + "filtered": 100, + "attached_condition": "t2.e < 5 and (t2.e < 2 or t2.e >= 4)" + } + } + } + } + } + } +} +# extracted AND-OR formula : pushing into WHERE +SET STATEMENT optimizer_switch='condition_pushdown_for_subquery=off' FOR SELECT * FROM t1 +WHERE ((t1.a<2 OR t1.a=5) AND t1.b>3) AND +(t1.a,t1.b,t1.c) IN +( +SELECT t2.e,t2.f,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e,t2.f +) +; +a b c d +1 4 35 3 +SELECT * FROM t1 +WHERE ((t1.a<2 OR t1.a=5) AND t1.b>3) AND +(t1.a,t1.b,t1.c) IN +( +SELECT t2.e,t2.f,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e,t2.f +) +; +a b c d +1 4 35 3 +EXPLAIN SELECT * FROM t1 +WHERE ((t1.a<2 OR t1.a=5) AND t1.b>3) AND +(t1.a,t1.b,t1.c) IN +( +SELECT t2.e,t2.f,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e,t2.f +) +; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 16 Using where +1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 12 test.t1.a,test.t1.b,test.t1.c 1 +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 12 Using where; Using temporary +EXPLAIN FORMAT=JSON SELECT * FROM t1 +WHERE ((t1.a<2 OR t1.a=5) AND t1.b>3) AND +(t1.a,t1.b,t1.c) IN +( +SELECT t2.e,t2.f,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e,t2.f +) +; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 16, + "filtered": 100, + "attached_condition": "(t1.a < 2 or t1.a = 5) and t1.b > 3 and t1.a is not null and t1.b is not null and t1.c is not null" + }, + "table": { + "table_name": "<subquery2>", + "access_type": "eq_ref", + "possible_keys": ["distinct_key"], + "key": "distinct_key", + "key_length": "12", + "used_key_parts": ["e", "f", "MAX(t2.g)"], + "ref": ["test.t1.a", "test.t1.b", "test.t1.c"], + "rows": 1, + "filtered": 100, + "materialized": { + "unique": 1, + "query_block": { + "select_id": 2, + "temporary_table": { + "table": { + "table_name": "t2", + "access_type": "ALL", + "rows": 12, + "filtered": 100, + "attached_condition": "t2.e < 5 and (t2.e < 2 or t2.e = 5) and t2.f > 3" + } + } + } + } + } + } +} +# extracted AND-OR formula : pushing into WHERE +SET STATEMENT optimizer_switch='condition_pushdown_for_subquery=off' FOR SELECT * FROM t1 +WHERE ((t1.a<2 OR t1.a=5) AND t1.b>3) AND +(t1.a,t1.b,t1.c) IN +( +SELECT t2.e,t2.f,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e,t2.f +) +; +a b c d +1 4 35 3 +SELECT * FROM t1 +WHERE ((t1.a<2 OR t1.a=5) AND t1.b>3) AND +(t1.a,t1.b,t1.c) IN +( +SELECT t2.e,t2.f,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e,t2.f +) +; +a b c d +1 4 35 3 +EXPLAIN SELECT * FROM t1 +WHERE ((t1.a<2 OR t1.a=5) AND t1.b>3) AND +(t1.a,t1.b,t1.c) IN +( +SELECT t2.e,t2.f,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e,t2.f +) +; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 16 Using where +1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 12 test.t1.a,test.t1.b,test.t1.c 1 +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 12 Using where; Using temporary +EXPLAIN FORMAT=JSON SELECT * FROM t1 +WHERE ((t1.a<2 OR t1.a=5) AND t1.b>3) AND +(t1.a,t1.b,t1.c) IN +( +SELECT t2.e,t2.f,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e,t2.f +) +; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 16, + "filtered": 100, + "attached_condition": "(t1.a < 2 or t1.a = 5) and t1.b > 3 and t1.a is not null and t1.b is not null and t1.c is not null" + }, + "table": { + "table_name": "<subquery2>", + "access_type": "eq_ref", + "possible_keys": ["distinct_key"], + "key": "distinct_key", + "key_length": "12", + "used_key_parts": ["e", "f", "MAX(t2.g)"], + "ref": ["test.t1.a", "test.t1.b", "test.t1.c"], + "rows": 1, + "filtered": 100, + "materialized": { + "unique": 1, + "query_block": { + "select_id": 2, + "temporary_table": { + "table": { + "table_name": "t2", + "access_type": "ALL", + "rows": 12, + "filtered": 100, + "attached_condition": "t2.e < 5 and (t2.e < 2 or t2.e = 5) and t2.f > 3" + } + } + } + } + } + } +} +# conjunctive subformula : pushing into WHERE +SET STATEMENT optimizer_switch='condition_pushdown_for_subquery=off' FOR SELECT * FROM t1 +WHERE ((t1.b<3 OR t1.d>2) AND t1.a<2) AND +(t1.a,t1.b,t1.c) IN +( +SELECT t2.e,t2.f,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e +) +; +a b c d +1 2 40 2 +SELECT * FROM t1 +WHERE ((t1.b<3 OR t1.d>2) AND t1.a<2) AND +(t1.a,t1.b,t1.c) IN +( +SELECT t2.e,t2.f,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e +) +; +a b c d +1 2 40 2 +EXPLAIN SELECT * FROM t1 +WHERE ((t1.b<3 OR t1.d>2) AND t1.a<2) AND +(t1.a,t1.b,t1.c) IN +( +SELECT t2.e,t2.f,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e +) +; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 16 Using where +1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 12 test.t1.a,test.t1.b,test.t1.c 1 +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 12 Using where; Using temporary +EXPLAIN FORMAT=JSON SELECT * FROM t1 +WHERE ((t1.b<3 OR t1.d>2) AND t1.a<2) AND +(t1.a,t1.b,t1.c) IN +( +SELECT t2.e,t2.f,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e +) +; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 16, + "filtered": 100, + "attached_condition": "(t1.b < 3 or t1.d > 2) and t1.a < 2 and t1.a is not null and t1.b is not null and t1.c is not null" + }, + "table": { + "table_name": "<subquery2>", + "access_type": "eq_ref", + "possible_keys": ["distinct_key"], + "key": "distinct_key", + "key_length": "12", + "used_key_parts": ["e", "f", "MAX(t2.g)"], + "ref": ["test.t1.a", "test.t1.b", "test.t1.c"], + "rows": 1, + "filtered": 100, + "materialized": { + "unique": 1, + "query_block": { + "select_id": 2, + "temporary_table": { + "table": { + "table_name": "t2", + "access_type": "ALL", + "rows": 12, + "filtered": 100, + "attached_condition": "t2.e < 5 and t2.e < 2" + } + } + } + } + } + } +} +# using equalities : pushing into WHERE +SET STATEMENT optimizer_switch='condition_pushdown_for_subquery=off' FOR SELECT * FROM t1 +WHERE t1.d=1 AND t1.a=t1.d AND +(t1.a,t1.c) IN +( +SELECT t2.e,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e +) +; +a b c d +1 3 40 1 +SELECT * FROM t1 +WHERE t1.d=1 AND t1.a=t1.d AND +(t1.a,t1.c) IN +( +SELECT t2.e,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e +) +; +a b c d +1 3 40 1 +EXPLAIN SELECT * FROM t1 +WHERE t1.d=1 AND t1.a=t1.d AND +(t1.a,t1.c) IN +( +SELECT t2.e,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e +) +; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 16 Using where +1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 8 const,test.t1.c 1 +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 12 Using where +EXPLAIN FORMAT=JSON SELECT * FROM t1 +WHERE t1.d=1 AND t1.a=t1.d AND +(t1.a,t1.c) IN +( +SELECT t2.e,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e +) +; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 16, + "filtered": 100, + "attached_condition": "t1.a = 1 and t1.d = 1 and t1.c is not null" + }, + "table": { + "table_name": "<subquery2>", + "access_type": "eq_ref", + "possible_keys": ["distinct_key"], + "key": "distinct_key", + "key_length": "8", + "used_key_parts": ["e", "MAX(t2.g)"], + "ref": ["const", "test.t1.c"], + "rows": 1, + "filtered": 100, + "materialized": { + "unique": 1, + "query_block": { + "select_id": 2, + "table": { + "table_name": "t2", + "access_type": "ALL", + "rows": 12, + "filtered": 100, + "attached_condition": "t2.e = 1" + } + } + } + } + } +} +# using equality : pushing into WHERE +SET STATEMENT optimizer_switch='condition_pushdown_for_subquery=off' FOR SELECT * FROM t1 +WHERE t1.d>1 AND t1.a=t1.d AND +(t1.a,t1.c) IN +( +SELECT t2.e,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e +) +; +a b c d +4 2 24 4 +SELECT * FROM t1 +WHERE t1.d>1 AND t1.a=t1.d AND +(t1.a,t1.c) IN +( +SELECT t2.e,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e +) +; +a b c d +4 2 24 4 +EXPLAIN SELECT * FROM t1 +WHERE t1.d>1 AND t1.a=t1.d AND +(t1.a,t1.c) IN +( +SELECT t2.e,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e +) +; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 16 Using where +1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 8 test.t1.a,test.t1.c 1 +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 12 Using where; Using temporary +EXPLAIN FORMAT=JSON SELECT * FROM t1 +WHERE t1.d>1 AND t1.a=t1.d AND +(t1.a,t1.c) IN +( +SELECT t2.e,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e +) +; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 16, + "filtered": 100, + "attached_condition": "t1.d = t1.a and t1.a > 1 and t1.a is not null and t1.c is not null" + }, + "table": { + "table_name": "<subquery2>", + "access_type": "eq_ref", + "possible_keys": ["distinct_key"], + "key": "distinct_key", + "key_length": "8", + "used_key_parts": ["e", "MAX(t2.g)"], + "ref": ["test.t1.a", "test.t1.c"], + "rows": 1, + "filtered": 100, + "materialized": { + "unique": 1, + "query_block": { + "select_id": 2, + "temporary_table": { + "table": { + "table_name": "t2", + "access_type": "ALL", + "rows": 12, + "filtered": 100, + "attached_condition": "t2.e < 5 and t2.e > 1" + } + } + } + } + } + } +} +# using view IN subquery definition : pushing into WHERE +SET STATEMENT optimizer_switch='condition_pushdown_for_subquery=off' FOR SELECT * FROM t1 +WHERE t1.a<3 AND +(t1.a,t1.c) IN +( +SELECT v1_x,MAX(v1_y) +FROM v1 +WHERE v1_x>1 +GROUP BY v1_x +) +; +a b c d +SELECT * FROM t1 +WHERE t1.a<3 AND +(t1.a,t1.c) IN +( +SELECT v1_x,MAX(v1_y) +FROM v1 +WHERE v1_x>1 +GROUP BY v1_x +) +; +a b c d +EXPLAIN SELECT * FROM t1 +WHERE t1.a<3 AND +(t1.a,t1.c) IN +( +SELECT v1_x,MAX(v1_y) +FROM v1 +WHERE v1_x>1 +GROUP BY v1_x +) +; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 16 Using where +1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 8 test.t1.a,test.t1.c 1 +2 MATERIALIZED t3 ALL NULL NULL NULL NULL 8 Using where; Using temporary +EXPLAIN FORMAT=JSON SELECT * FROM t1 +WHERE t1.a<3 AND +(t1.a,t1.c) IN +( +SELECT v1_x,MAX(v1_y) +FROM v1 +WHERE v1_x>1 +GROUP BY v1_x +) +; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 16, + "filtered": 100, + "attached_condition": "t1.a < 3 and t1.a is not null and t1.c is not null" + }, + "table": { + "table_name": "<subquery2>", + "access_type": "eq_ref", + "possible_keys": ["distinct_key"], + "key": "distinct_key", + "key_length": "8", + "used_key_parts": ["v1_x", "MAX(v1_y)"], + "ref": ["test.t1.a", "test.t1.c"], + "rows": 1, + "filtered": 100, + "materialized": { + "unique": 1, + "query_block": { + "select_id": 2, + "temporary_table": { + "table": { + "table_name": "t3", + "access_type": "ALL", + "rows": 8, + "filtered": 100, + "attached_condition": "t3.x > 1 and t3.x <= 3 and t3.x < 3" + } + } + } + } + } + } +} +# using equality : pushing into WHERE +SET STATEMENT optimizer_switch='condition_pushdown_for_subquery=off' FOR SELECT * FROM t1,v1 +WHERE t1.a=v1_x AND v1_x<2 AND v1_y>30 AND +(t1.a,t1.c) IN +( +SELECT t2.e,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e +) +; +a b c d v1_x v1_y +1 3 40 1 1 35 +1 2 40 2 1 35 +SELECT * FROM t1,v1 +WHERE t1.a=v1_x AND v1_x<2 AND v1_y>30 AND +(t1.a,t1.c) IN +( +SELECT t2.e,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e +) +; +a b c d v1_x v1_y +1 3 40 1 1 35 +1 2 40 2 1 35 +EXPLAIN SELECT * FROM t1,v1 +WHERE t1.a=v1_x AND v1_x<2 AND v1_y>30 AND +(t1.a,t1.c) IN +( +SELECT t2.e,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e +) +; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t3 ALL NULL NULL NULL NULL 8 Using where +1 PRIMARY t1 ALL NULL NULL NULL NULL 16 Using where; Using join buffer (flat, BNL join) +1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 8 test.t3.x,test.t1.c 1 +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 12 Using where; Using temporary +EXPLAIN FORMAT=JSON SELECT * FROM t1,v1 +WHERE t1.a=v1_x AND v1_x<2 AND v1_y>30 AND +(t1.a,t1.c) IN +( +SELECT t2.e,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e +) +; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "t3", + "access_type": "ALL", + "rows": 8, + "filtered": 100, + "attached_condition": "t3.x < 2 and t3.y > 30 and t3.x <= 3 and t3.x is not null" + }, + "block-nl-join": { + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 16, + "filtered": 100 + }, + "buffer_type": "flat", + "buffer_size": "256Kb", + "join_type": "BNL", + "attached_condition": "t1.a = t3.x and t1.c is not null" + }, + "table": { + "table_name": "<subquery2>", + "access_type": "eq_ref", + "possible_keys": ["distinct_key"], + "key": "distinct_key", + "key_length": "8", + "used_key_parts": ["e", "MAX(t2.g)"], + "ref": ["test.t3.x", "test.t1.c"], + "rows": 1, + "filtered": 100, + "materialized": { + "unique": 1, + "query_block": { + "select_id": 2, + "temporary_table": { + "table": { + "table_name": "t2", + "access_type": "ALL", + "rows": 12, + "filtered": 100, + "attached_condition": "t2.e < 5 and t2.e <= 3" + } + } + } + } + } + } +} +# conjunctive subformula : pushing into WHERE +# extracted OR formula : pushing into HAVING +SET STATEMENT optimizer_switch='condition_pushdown_for_subquery=off' FOR SELECT * FROM t1 +WHERE ((t1.b<3 OR t1.b=4) AND t1.a<3) AND +(t1.a,t1.b,t1.c) IN +( +SELECT t2.e,t2.f,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e +) +; +a b c d +1 2 40 2 +SELECT * FROM t1 +WHERE ((t1.b<3 OR t1.b=4) AND t1.a<3) AND +(t1.a,t1.b,t1.c) IN +( +SELECT t2.e,t2.f,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e +) +; +a b c d +1 2 40 2 +EXPLAIN SELECT * FROM t1 +WHERE ((t1.b<3 OR t1.b=4) AND t1.a<3) AND +(t1.a,t1.b,t1.c) IN +( +SELECT t2.e,t2.f,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e +) +; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 16 Using where +1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 12 test.t1.a,test.t1.b,test.t1.c 1 +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 12 Using where; Using temporary +EXPLAIN FORMAT=JSON SELECT * FROM t1 +WHERE ((t1.b<3 OR t1.b=4) AND t1.a<3) AND +(t1.a,t1.b,t1.c) IN +( +SELECT t2.e,t2.f,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e +) +; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 16, + "filtered": 100, + "attached_condition": "(t1.b < 3 or t1.b = 4) and t1.a < 3 and t1.a is not null and t1.b is not null and t1.c is not null" + }, + "table": { + "table_name": "<subquery2>", + "access_type": "eq_ref", + "possible_keys": ["distinct_key"], + "key": "distinct_key", + "key_length": "12", + "used_key_parts": ["e", "f", "MAX(t2.g)"], + "ref": ["test.t1.a", "test.t1.b", "test.t1.c"], + "rows": 1, + "filtered": 100, + "materialized": { + "unique": 1, + "query_block": { + "select_id": 2, + "having_condition": "t2.f < 3 or t2.f = 4", + "temporary_table": { + "table": { + "table_name": "t2", + "access_type": "ALL", + "rows": 12, + "filtered": 100, + "attached_condition": "t2.e < 5 and t2.e < 3" + } + } + } + } + } + } +} +# conjunctive subformula using addition : pushing into HAVING +SET STATEMENT optimizer_switch='condition_pushdown_for_subquery=off' FOR SELECT * FROM t1 +WHERE (t1.a+t1.c>41) AND +(t1.a,t1.c) IN +( +SELECT t2.e,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e +) +; +a b c d +2 3 70 3 +SELECT * FROM t1 +WHERE (t1.a+t1.c>41) AND +(t1.a,t1.c) IN +( +SELECT t2.e,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e +) +; +a b c d +2 3 70 3 +EXPLAIN SELECT * FROM t1 +WHERE (t1.a+t1.c>41) AND +(t1.a,t1.c) IN +( +SELECT t2.e,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e +) +; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 16 Using where +1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 8 test.t1.a,test.t1.c 1 +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 12 Using where; Using temporary +EXPLAIN FORMAT=JSON SELECT * FROM t1 +WHERE (t1.a+t1.c>41) AND +(t1.a,t1.c) IN +( +SELECT t2.e,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e +) +; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 16, + "filtered": 100, + "attached_condition": "t1.a + t1.c > 41 and t1.a is not null and t1.c is not null" + }, + "table": { + "table_name": "<subquery2>", + "access_type": "eq_ref", + "possible_keys": ["distinct_key"], + "key": "distinct_key", + "key_length": "8", + "used_key_parts": ["e", "MAX(t2.g)"], + "ref": ["test.t1.a", "test.t1.c"], + "rows": 1, + "filtered": 100, + "materialized": { + "unique": 1, + "query_block": { + "select_id": 2, + "having_condition": "t2.e + `MAX(t2.g)` > 41", + "temporary_table": { + "table": { + "table_name": "t2", + "access_type": "ALL", + "rows": 12, + "filtered": 100, + "attached_condition": "t2.e < 5" + } + } + } + } + } + } +} +# conjunctive subformula using substitution : pushing into HAVING +SET STATEMENT optimizer_switch='condition_pushdown_for_subquery=off' FOR SELECT * FROM t1 +WHERE (t1.c-t1.a<35) AND +(t1.a,t1.c) IN +( +SELECT t2.e,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e +) +; +a b c d +4 2 24 4 +3 2 23 1 +SELECT * FROM t1 +WHERE (t1.c-t1.a<35) AND +(t1.a,t1.c) IN +( +SELECT t2.e,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e +) +; +a b c d +4 2 24 4 +3 2 23 1 +EXPLAIN SELECT * FROM t1 +WHERE (t1.c-t1.a<35) AND +(t1.a,t1.c) IN +( +SELECT t2.e,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e +) +; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 16 Using where +1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 8 test.t1.a,test.t1.c 1 +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 12 Using where; Using temporary +EXPLAIN FORMAT=JSON SELECT * FROM t1 +WHERE (t1.c-t1.a<35) AND +(t1.a,t1.c) IN +( +SELECT t2.e,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e +) +; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 16, + "filtered": 100, + "attached_condition": "t1.c - t1.a < 35 and t1.a is not null and t1.c is not null" + }, + "table": { + "table_name": "<subquery2>", + "access_type": "eq_ref", + "possible_keys": ["distinct_key"], + "key": "distinct_key", + "key_length": "8", + "used_key_parts": ["e", "MAX(t2.g)"], + "ref": ["test.t1.a", "test.t1.c"], + "rows": 1, + "filtered": 100, + "materialized": { + "unique": 1, + "query_block": { + "select_id": 2, + "having_condition": "`MAX(t2.g)` - t2.e < 35", + "temporary_table": { + "table": { + "table_name": "t2", + "access_type": "ALL", + "rows": 12, + "filtered": 100, + "attached_condition": "t2.e < 5" + } + } + } + } + } + } +} +# conjunctive subformula using multiplication : pushing into HAVING +SET STATEMENT optimizer_switch='condition_pushdown_for_subquery=off' FOR SELECT * FROM t1 +WHERE (t1.c*t1.a>100) AND +(t1.a,t1.c) IN +( +SELECT t2.e,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e +) +; +a b c d +2 3 70 3 +SELECT * FROM t1 +WHERE (t1.c*t1.a>100) AND +(t1.a,t1.c) IN +( +SELECT t2.e,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e +) +; +a b c d +2 3 70 3 +EXPLAIN SELECT * FROM t1 +WHERE (t1.c*t1.a>100) AND +(t1.a,t1.c) IN +( +SELECT t2.e,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e +) +; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 16 Using where +1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 8 test.t1.a,test.t1.c 1 +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 12 Using where; Using temporary +EXPLAIN FORMAT=JSON SELECT * FROM t1 +WHERE (t1.c*t1.a>100) AND +(t1.a,t1.c) IN +( +SELECT t2.e,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e +) +; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 16, + "filtered": 100, + "attached_condition": "t1.c * t1.a > 100 and t1.a is not null and t1.c is not null" + }, + "table": { + "table_name": "<subquery2>", + "access_type": "eq_ref", + "possible_keys": ["distinct_key"], + "key": "distinct_key", + "key_length": "8", + "used_key_parts": ["e", "MAX(t2.g)"], + "ref": ["test.t1.a", "test.t1.c"], + "rows": 1, + "filtered": 100, + "materialized": { + "unique": 1, + "query_block": { + "select_id": 2, + "having_condition": "`MAX(t2.g)` * t2.e > 100", + "temporary_table": { + "table": { + "table_name": "t2", + "access_type": "ALL", + "rows": 12, + "filtered": 100, + "attached_condition": "t2.e < 5" + } + } + } + } + } + } +} +# conjunctive subformula using division : pushing into HAVING +SET STATEMENT optimizer_switch='condition_pushdown_for_subquery=off' FOR SELECT * FROM t1 +WHERE (t1.c/t1.a>30) AND +(t1.a,t1.c) IN +( +SELECT t2.e,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e +) +; +a b c d +1 3 40 1 +1 2 40 2 +2 3 70 3 +SELECT * FROM t1 +WHERE (t1.c/t1.a>30) AND +(t1.a,t1.c) IN +( +SELECT t2.e,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e +) +; +a b c d +1 3 40 1 +1 2 40 2 +2 3 70 3 +EXPLAIN SELECT * FROM t1 +WHERE (t1.c/t1.a>30) AND +(t1.a,t1.c) IN +( +SELECT t2.e,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e +) +; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 16 Using where +1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 8 test.t1.a,test.t1.c 1 +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 12 Using where; Using temporary +EXPLAIN FORMAT=JSON SELECT * FROM t1 +WHERE (t1.c/t1.a>30) AND +(t1.a,t1.c) IN +( +SELECT t2.e,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e +) +; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 16, + "filtered": 100, + "attached_condition": "t1.c / t1.a > 30 and t1.a is not null and t1.c is not null" + }, + "table": { + "table_name": "<subquery2>", + "access_type": "eq_ref", + "possible_keys": ["distinct_key"], + "key": "distinct_key", + "key_length": "8", + "used_key_parts": ["e", "MAX(t2.g)"], + "ref": ["test.t1.a", "test.t1.c"], + "rows": 1, + "filtered": 100, + "materialized": { + "unique": 1, + "query_block": { + "select_id": 2, + "having_condition": "`MAX(t2.g)` / t2.e > 30", + "temporary_table": { + "table": { + "table_name": "t2", + "access_type": "ALL", + "rows": 12, + "filtered": 100, + "attached_condition": "t2.e < 5" + } + } + } + } + } + } +} +# conjunctive subformula using BETWEEN : pushing into HAVING +SET STATEMENT optimizer_switch='condition_pushdown_for_subquery=off' FOR SELECT * FROM t1 +WHERE (t1.c BETWEEN 50 AND 100) AND +(t1.a,t1.c) IN +( +SELECT t2.e,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e +) +; +a b c d +2 3 70 3 +SELECT * FROM t1 +WHERE (t1.c BETWEEN 50 AND 100) AND +(t1.a,t1.c) IN +( +SELECT t2.e,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e +) +; +a b c d +2 3 70 3 +EXPLAIN SELECT * FROM t1 +WHERE (t1.c BETWEEN 50 AND 100) AND +(t1.a,t1.c) IN +( +SELECT t2.e,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e +) +; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 16 Using where +1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 8 test.t1.a,test.t1.c 1 +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 12 Using where; Using temporary +EXPLAIN FORMAT=JSON SELECT * FROM t1 +WHERE (t1.c BETWEEN 50 AND 100) AND +(t1.a,t1.c) IN +( +SELECT t2.e,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e +) +; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 16, + "filtered": 100, + "attached_condition": "t1.c between 50 and 100 and t1.a is not null and t1.c is not null" + }, + "table": { + "table_name": "<subquery2>", + "access_type": "eq_ref", + "possible_keys": ["distinct_key"], + "key": "distinct_key", + "key_length": "8", + "used_key_parts": ["e", "MAX(t2.g)"], + "ref": ["test.t1.a", "test.t1.c"], + "rows": 1, + "filtered": 100, + "materialized": { + "unique": 1, + "query_block": { + "select_id": 2, + "having_condition": "`MAX(t2.g)` between 50 and 100", + "temporary_table": { + "table": { + "table_name": "t2", + "access_type": "ALL", + "rows": 12, + "filtered": 100, + "attached_condition": "t2.e < 5" + } + } + } + } + } + } +} +# conjunctive subformula using addition : pushing into WHERE +SET STATEMENT optimizer_switch='condition_pushdown_for_subquery=off' FOR SELECT * FROM t1 +WHERE (t1.a+t1.b > 5) AND +(t1.a,t1.b,t1.c) IN +( +SELECT t2.e,t2.f,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e,t2.f +) +; +a b c d +4 2 24 4 +SELECT * FROM t1 +WHERE (t1.a+t1.b > 5) AND +(t1.a,t1.b,t1.c) IN +( +SELECT t2.e,t2.f,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e,t2.f +) +; +a b c d +4 2 24 4 +EXPLAIN SELECT * FROM t1 +WHERE (t1.a+t1.b > 5) AND +(t1.a,t1.b,t1.c) IN +( +SELECT t2.e,t2.f,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e,t2.f +) +; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 16 Using where +1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 12 test.t1.a,test.t1.b,test.t1.c 1 +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 12 Using where; Using temporary +EXPLAIN FORMAT=JSON SELECT * FROM t1 +WHERE (t1.a+t1.b > 5) AND +(t1.a,t1.b,t1.c) IN +( +SELECT t2.e,t2.f,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e,t2.f +) +; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 16, + "filtered": 100, + "attached_condition": "t1.a + t1.b > 5 and t1.a is not null and t1.b is not null and t1.c is not null" + }, + "table": { + "table_name": "<subquery2>", + "access_type": "eq_ref", + "possible_keys": ["distinct_key"], + "key": "distinct_key", + "key_length": "12", + "used_key_parts": ["e", "f", "MAX(t2.g)"], + "ref": ["test.t1.a", "test.t1.b", "test.t1.c"], + "rows": 1, + "filtered": 100, + "materialized": { + "unique": 1, + "query_block": { + "select_id": 2, + "temporary_table": { + "table": { + "table_name": "t2", + "access_type": "ALL", + "rows": 12, + "filtered": 100, + "attached_condition": "t2.e < 5 and t2.e + t2.f > 5" + } + } + } + } + } + } +} +# conjunctive subformula using substitution : pushing into WHERE +SET STATEMENT optimizer_switch='condition_pushdown_for_subquery=off' FOR SELECT * FROM t1 +WHERE (t1.a-t1.b > 0) AND +(t1.a,t1.b,t1.c) IN +( +SELECT t2.e,t2.f,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e,t2.f +) +; +a b c d +4 2 24 4 +SELECT * FROM t1 +WHERE (t1.a-t1.b > 0) AND +(t1.a,t1.b,t1.c) IN +( +SELECT t2.e,t2.f,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e,t2.f +) +; +a b c d +4 2 24 4 +EXPLAIN SELECT * FROM t1 +WHERE (t1.a-t1.b > 0) AND +(t1.a,t1.b,t1.c) IN +( +SELECT t2.e,t2.f,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e,t2.f +) +; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 16 Using where +1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 12 test.t1.a,test.t1.b,test.t1.c 1 +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 12 Using where; Using temporary +EXPLAIN FORMAT=JSON SELECT * FROM t1 +WHERE (t1.a-t1.b > 0) AND +(t1.a,t1.b,t1.c) IN +( +SELECT t2.e,t2.f,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e,t2.f +) +; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 16, + "filtered": 100, + "attached_condition": "t1.a - t1.b > 0 and t1.a is not null and t1.b is not null and t1.c is not null" + }, + "table": { + "table_name": "<subquery2>", + "access_type": "eq_ref", + "possible_keys": ["distinct_key"], + "key": "distinct_key", + "key_length": "12", + "used_key_parts": ["e", "f", "MAX(t2.g)"], + "ref": ["test.t1.a", "test.t1.b", "test.t1.c"], + "rows": 1, + "filtered": 100, + "materialized": { + "unique": 1, + "query_block": { + "select_id": 2, + "temporary_table": { + "table": { + "table_name": "t2", + "access_type": "ALL", + "rows": 12, + "filtered": 100, + "attached_condition": "t2.e < 5 and t2.e - t2.f > 0" + } + } + } + } + } + } +} +# conjunctive subformula using multiplication : pushing into WHERE +SET STATEMENT optimizer_switch='condition_pushdown_for_subquery=off' FOR SELECT * FROM t1 +WHERE (t1.a*t1.b > 6) AND +(t1.a,t1.b,t1.c) IN +( +SELECT t2.e,t2.f,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e,t2.f +) +; +a b c d +4 2 24 4 +SELECT * FROM t1 +WHERE (t1.a*t1.b > 6) AND +(t1.a,t1.b,t1.c) IN +( +SELECT t2.e,t2.f,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e,t2.f +) +; +a b c d +4 2 24 4 +EXPLAIN SELECT * FROM t1 +WHERE (t1.a*t1.b > 6) AND +(t1.a,t1.b,t1.c) IN +( +SELECT t2.e,t2.f,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e,t2.f +) +; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 16 Using where +1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 12 test.t1.a,test.t1.b,test.t1.c 1 +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 12 Using where; Using temporary +EXPLAIN FORMAT=JSON SELECT * FROM t1 +WHERE (t1.a*t1.b > 6) AND +(t1.a,t1.b,t1.c) IN +( +SELECT t2.e,t2.f,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e,t2.f +) +; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 16, + "filtered": 100, + "attached_condition": "t1.a * t1.b > 6 and t1.a is not null and t1.b is not null and t1.c is not null" + }, + "table": { + "table_name": "<subquery2>", + "access_type": "eq_ref", + "possible_keys": ["distinct_key"], + "key": "distinct_key", + "key_length": "12", + "used_key_parts": ["e", "f", "MAX(t2.g)"], + "ref": ["test.t1.a", "test.t1.b", "test.t1.c"], + "rows": 1, + "filtered": 100, + "materialized": { + "unique": 1, + "query_block": { + "select_id": 2, + "temporary_table": { + "table": { + "table_name": "t2", + "access_type": "ALL", + "rows": 12, + "filtered": 100, + "attached_condition": "t2.e < 5 and t2.e * t2.f > 6" + } + } + } + } + } + } +} +# conjunctive subformula using division : pushing into WHERE +SET STATEMENT optimizer_switch='condition_pushdown_for_subquery=off' FOR SELECT * FROM t1 +WHERE (t1.b/t1.a > 2) AND +(t1.a,t1.b,t1.c) IN +( +SELECT t2.e,t2.f,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e,t2.f +) +; +a b c d +1 3 40 1 +1 4 35 3 +SELECT * FROM t1 +WHERE (t1.b/t1.a > 2) AND +(t1.a,t1.b,t1.c) IN +( +SELECT t2.e,t2.f,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e,t2.f +) +; +a b c d +1 3 40 1 +1 4 35 3 +EXPLAIN SELECT * FROM t1 +WHERE (t1.b/t1.a > 2) AND +(t1.a,t1.b,t1.c) IN +( +SELECT t2.e,t2.f,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e,t2.f +) +; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 16 Using where +1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 12 test.t1.a,test.t1.b,test.t1.c 1 +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 12 Using where; Using temporary +EXPLAIN FORMAT=JSON SELECT * FROM t1 +WHERE (t1.b/t1.a > 2) AND +(t1.a,t1.b,t1.c) IN +( +SELECT t2.e,t2.f,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e,t2.f +) +; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 16, + "filtered": 100, + "attached_condition": "t1.b / t1.a > 2 and t1.a is not null and t1.b is not null and t1.c is not null" + }, + "table": { + "table_name": "<subquery2>", + "access_type": "eq_ref", + "possible_keys": ["distinct_key"], + "key": "distinct_key", + "key_length": "12", + "used_key_parts": ["e", "f", "MAX(t2.g)"], + "ref": ["test.t1.a", "test.t1.b", "test.t1.c"], + "rows": 1, + "filtered": 100, + "materialized": { + "unique": 1, + "query_block": { + "select_id": 2, + "temporary_table": { + "table": { + "table_name": "t2", + "access_type": "ALL", + "rows": 12, + "filtered": 100, + "attached_condition": "t2.e < 5 and t2.f / t2.e > 2" + } + } + } + } + } + } +} +# conjunctive subformula using BETWEEN : pushing into WHERE +SET STATEMENT optimizer_switch='condition_pushdown_for_subquery=off' FOR SELECT * FROM t1 +WHERE (t1.a BETWEEN 1 AND 3) AND +(t1.a,t1.c) IN +( +SELECT t2.e,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e +) +; +a b c d +1 3 40 1 +3 2 23 1 +1 2 40 2 +2 3 70 3 +SELECT * FROM t1 +WHERE (t1.a BETWEEN 1 AND 3) AND +(t1.a,t1.c) IN +( +SELECT t2.e,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e +) +; +a b c d +1 3 40 1 +3 2 23 1 +1 2 40 2 +2 3 70 3 +EXPLAIN SELECT * FROM t1 +WHERE (t1.a BETWEEN 1 AND 3) AND +(t1.a,t1.c) IN +( +SELECT t2.e,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e +) +; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 16 Using where +1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 8 test.t1.a,test.t1.c 1 +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 12 Using where; Using temporary +EXPLAIN FORMAT=JSON SELECT * FROM t1 +WHERE (t1.a BETWEEN 1 AND 3) AND +(t1.a,t1.c) IN +( +SELECT t2.e,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e +) +; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 16, + "filtered": 100, + "attached_condition": "t1.a between 1 and 3 and t1.a is not null and t1.c is not null" + }, + "table": { + "table_name": "<subquery2>", + "access_type": "eq_ref", + "possible_keys": ["distinct_key"], + "key": "distinct_key", + "key_length": "8", + "used_key_parts": ["e", "MAX(t2.g)"], + "ref": ["test.t1.a", "test.t1.c"], + "rows": 1, + "filtered": 100, + "materialized": { + "unique": 1, + "query_block": { + "select_id": 2, + "temporary_table": { + "table": { + "table_name": "t2", + "access_type": "ALL", + "rows": 12, + "filtered": 100, + "attached_condition": "t2.e < 5 and t2.e between 1 and 3" + } + } + } + } + } + } +} +# conjunctive subformula : pushing into HAVING of the IN subquery +# conjunctive subformula : pushing into WHERE of the view from the IN subquery +SET STATEMENT optimizer_switch='condition_pushdown_for_subquery=off' FOR SELECT * FROM t1 +WHERE t1.c>3 AND +(t1.a,t1.b,t1.c) IN +( +SELECT v2.e,MAX(v2.f),v2.max_g +FROM v2 +WHERE v2.e<5 +GROUP BY v2.e +) +; +a b c d +1 2 40 2 +2 3 70 3 +SELECT * FROM t1 +WHERE t1.c>3 AND +(t1.a,t1.b,t1.c) IN +( +SELECT v2.e,MAX(v2.f),v2.max_g +FROM v2 +WHERE v2.e<5 +GROUP BY v2.e +) +; +a b c d +1 2 40 2 +2 3 70 3 +EXPLAIN SELECT * FROM t1 +WHERE t1.c>3 AND +(t1.a,t1.b,t1.c) IN +( +SELECT v2.e,MAX(v2.f),v2.max_g +FROM v2 +WHERE v2.e<5 +GROUP BY v2.e +) +; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 16 Using where +1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 12 test.t1.a,test.t1.b,test.t1.c 1 +2 MATERIALIZED <derived3> ALL NULL NULL NULL NULL 12 Using where; Using temporary +3 DERIVED t2 ALL NULL NULL NULL NULL 12 Using temporary; Using filesort +EXPLAIN FORMAT=JSON SELECT * FROM t1 +WHERE t1.c>3 AND +(t1.a,t1.b,t1.c) IN +( +SELECT v2.e,MAX(v2.f),v2.max_g +FROM v2 +WHERE v2.e<5 +GROUP BY v2.e +) +; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 16, + "filtered": 100, + "attached_condition": "t1.c > 3 and t1.a is not null and t1.b is not null and t1.c is not null" + }, + "table": { + "table_name": "<subquery2>", + "access_type": "eq_ref", + "possible_keys": ["distinct_key"], + "key": "distinct_key", + "key_length": "12", + "used_key_parts": ["e", "MAX(v2.f)", "max_g"], + "ref": ["test.t1.a", "test.t1.b", "test.t1.c"], + "rows": 1, + "filtered": 100, + "materialized": { + "unique": 1, + "query_block": { + "select_id": 2, + "having_condition": "v2.max_g > 3", + "temporary_table": { + "table": { + "table_name": "<derived3>", + "access_type": "ALL", + "rows": 12, + "filtered": 100, + "attached_condition": "v2.e < 5", + "materialized": { + "query_block": { + "select_id": 3, + "having_condition": "max_g > 25", + "filesort": { + "sort_key": "t2.e", + "temporary_table": { + "table": { + "table_name": "t2", + "access_type": "ALL", + "rows": 12, + "filtered": 100 + } + } + } + } + } + } + } + } + } + } + } +} +# conjunctive subformula : pushing into WHERE of the IN subquery +# conjunctive subformula : pushing into WHERE of the view +# from the IN subquery +SET STATEMENT optimizer_switch='condition_pushdown_for_subquery=off' FOR SELECT * FROM t1 +WHERE t1.a>1 AND +(t1.a,t1.b,t1.c) IN +( +SELECT v2.e,MAX(v2.f),v2.max_g +FROM v2 +WHERE v2.e<5 +GROUP BY v2.e +) +; +a b c d +2 3 70 3 +SELECT * FROM t1 +WHERE t1.a>1 AND +(t1.a,t1.b,t1.c) IN +( +SELECT v2.e,MAX(v2.f),v2.max_g +FROM v2 +WHERE v2.e<5 +GROUP BY v2.e +) +; +a b c d +2 3 70 3 +EXPLAIN SELECT * FROM t1 +WHERE t1.a>1 AND +(t1.a,t1.b,t1.c) IN +( +SELECT v2.e,MAX(v2.f),v2.max_g +FROM v2 +WHERE v2.e<5 +GROUP BY v2.e +) +; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 16 Using where +1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 12 test.t1.a,test.t1.b,test.t1.c 1 +2 MATERIALIZED <derived3> ALL NULL NULL NULL NULL 12 Using where; Using temporary +3 DERIVED t2 ALL NULL NULL NULL NULL 12 Using temporary; Using filesort +EXPLAIN FORMAT=JSON SELECT * FROM t1 +WHERE t1.a>1 AND +(t1.a,t1.b,t1.c) IN +( +SELECT v2.e,MAX(v2.f),v2.max_g +FROM v2 +WHERE v2.e<5 +GROUP BY v2.e +) +; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 16, + "filtered": 100, + "attached_condition": "t1.a > 1 and t1.a is not null and t1.b is not null and t1.c is not null" + }, + "table": { + "table_name": "<subquery2>", + "access_type": "eq_ref", + "possible_keys": ["distinct_key"], + "key": "distinct_key", + "key_length": "12", + "used_key_parts": ["e", "MAX(v2.f)", "max_g"], + "ref": ["test.t1.a", "test.t1.b", "test.t1.c"], + "rows": 1, + "filtered": 100, + "materialized": { + "unique": 1, + "query_block": { + "select_id": 2, + "temporary_table": { + "table": { + "table_name": "<derived3>", + "access_type": "ALL", + "rows": 12, + "filtered": 100, + "attached_condition": "v2.e < 5 and v2.e > 1", + "materialized": { + "query_block": { + "select_id": 3, + "having_condition": "max_g > 25", + "filesort": { + "sort_key": "t2.e", + "temporary_table": { + "table": { + "table_name": "t2", + "access_type": "ALL", + "rows": 12, + "filtered": 100 + } + } + } + } + } + } + } + } + } + } + } +} +# conjunctive subformula : pushing into WHERE and HAVING +# of the IN subquery +# conjunctive subformula : pushing into WHERE of the view +# from the IN subquery +SET STATEMENT optimizer_switch='condition_pushdown_for_subquery=off' FOR SELECT * FROM t1 +WHERE t1.a>1 AND t1.c<100 AND +(t1.a,t1.b,t1.c) IN +( +SELECT v2.e,MAX(v2.f),v2.max_g +FROM v2 +WHERE v2.e<5 +GROUP BY v2.e +) +; +a b c d +2 3 70 3 +SELECT * FROM t1 +WHERE t1.a>1 AND t1.c<100 AND +(t1.a,t1.b,t1.c) IN +( +SELECT v2.e,MAX(v2.f),v2.max_g +FROM v2 +WHERE v2.e<5 +GROUP BY v2.e +) +; +a b c d +2 3 70 3 +EXPLAIN SELECT * FROM t1 +WHERE t1.a>1 AND t1.c<100 AND +(t1.a,t1.b,t1.c) IN +( +SELECT v2.e,MAX(v2.f),v2.max_g +FROM v2 +WHERE v2.e<5 +GROUP BY v2.e +) +; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 16 Using where +1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 12 test.t1.a,test.t1.b,test.t1.c 1 +2 MATERIALIZED <derived3> ALL NULL NULL NULL NULL 12 Using where; Using temporary +3 DERIVED t2 ALL NULL NULL NULL NULL 12 Using temporary; Using filesort +EXPLAIN FORMAT=JSON SELECT * FROM t1 +WHERE t1.a>1 AND t1.c<100 AND +(t1.a,t1.b,t1.c) IN +( +SELECT v2.e,MAX(v2.f),v2.max_g +FROM v2 +WHERE v2.e<5 +GROUP BY v2.e +) +; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 16, + "filtered": 100, + "attached_condition": "t1.a > 1 and t1.c < 100 and t1.a is not null and t1.b is not null and t1.c is not null" + }, + "table": { + "table_name": "<subquery2>", + "access_type": "eq_ref", + "possible_keys": ["distinct_key"], + "key": "distinct_key", + "key_length": "12", + "used_key_parts": ["e", "MAX(v2.f)", "max_g"], + "ref": ["test.t1.a", "test.t1.b", "test.t1.c"], + "rows": 1, + "filtered": 100, + "materialized": { + "unique": 1, + "query_block": { + "select_id": 2, + "having_condition": "v2.max_g < 100", + "temporary_table": { + "table": { + "table_name": "<derived3>", + "access_type": "ALL", + "rows": 12, + "filtered": 100, + "attached_condition": "v2.e < 5 and v2.e > 1", + "materialized": { + "query_block": { + "select_id": 3, + "having_condition": "max_g > 25", + "filesort": { + "sort_key": "t2.e", + "temporary_table": { + "table": { + "table_name": "t2", + "access_type": "ALL", + "rows": 12, + "filtered": 100 + } + } + } + } + } + } + } + } + } + } + } +} +# conjunctive subformula : pushing into WHERE of the IN subquery +# extracted AND formula : pushing into HAVING of the derived table +# from the IN subquery +SET STATEMENT optimizer_switch='condition_pushdown_for_subquery=off' FOR SELECT * FROM t1 +WHERE t1.a>1 AND +(t1.a,t1.b,t1.c) IN +( +SELECT d_tab.e,MAX(d_tab.f),d_tab.max_g +FROM +( +SELECT t2.e, t2.f, MAX(t2.g) AS max_g +FROM t2 +GROUP BY t2.f +HAVING max_g>25 +) as d_tab +WHERE d_tab.e<5 +GROUP BY d_tab.e +) +; +a b c d +2 3 40 4 +SELECT * FROM t1 +WHERE t1.a>1 AND +(t1.a,t1.b,t1.c) IN +( +SELECT d_tab.e,MAX(d_tab.f),d_tab.max_g +FROM +( +SELECT t2.e, t2.f, MAX(t2.g) AS max_g +FROM t2 +GROUP BY t2.f +HAVING max_g>25 +) as d_tab +WHERE d_tab.e<5 +GROUP BY d_tab.e +) +; +a b c d +2 3 40 4 +EXPLAIN SELECT * FROM t1 +WHERE t1.a>1 AND +(t1.a,t1.b,t1.c) IN +( +SELECT d_tab.e,MAX(d_tab.f),d_tab.max_g +FROM +( +SELECT t2.e, t2.f, MAX(t2.g) AS max_g +FROM t2 +GROUP BY t2.f +HAVING max_g>25 +) as d_tab +WHERE d_tab.e<5 +GROUP BY d_tab.e +) +; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 16 Using where +1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 12 test.t1.a,test.t1.b,test.t1.c 1 +2 MATERIALIZED <derived3> ALL NULL NULL NULL NULL 12 Using where; Using temporary +3 DERIVED t2 ALL NULL NULL NULL NULL 12 Using temporary; Using filesort +EXPLAIN FORMAT=JSON SELECT * FROM t1 +WHERE t1.a>1 AND +(t1.a,t1.b,t1.c) IN +( +SELECT d_tab.e,MAX(d_tab.f),d_tab.max_g +FROM +( +SELECT t2.e, t2.f, MAX(t2.g) AS max_g +FROM t2 +GROUP BY t2.f +HAVING max_g>25 +) as d_tab +WHERE d_tab.e<5 +GROUP BY d_tab.e +) +; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 16, + "filtered": 100, + "attached_condition": "t1.a > 1 and t1.a is not null and t1.b is not null and t1.c is not null" + }, + "table": { + "table_name": "<subquery2>", + "access_type": "eq_ref", + "possible_keys": ["distinct_key"], + "key": "distinct_key", + "key_length": "12", + "used_key_parts": ["e", "MAX(d_tab.f)", "max_g"], + "ref": ["test.t1.a", "test.t1.b", "test.t1.c"], + "rows": 1, + "filtered": 100, + "materialized": { + "unique": 1, + "query_block": { + "select_id": 2, + "temporary_table": { + "table": { + "table_name": "<derived3>", + "access_type": "ALL", + "rows": 12, + "filtered": 100, + "attached_condition": "d_tab.e < 5 and d_tab.e > 1", + "materialized": { + "query_block": { + "select_id": 3, + "having_condition": "max_g > 25", + "filesort": { + "sort_key": "t2.f", + "temporary_table": { + "table": { + "table_name": "t2", + "access_type": "ALL", + "rows": 12, + "filtered": 100 + } + } + } + } + } + } + } + } + } + } + } +} +# conjunctive subformula : pushing into HAVING of the derived table +# conjunctive subformula : pushing into WHERE of the IN subquery from +# the derived table +SELECT * +FROM t3, +( +SELECT t1.a,t1.b,max(t1.c) as max_c +FROM t1 +WHERE t1.a>1 AND +(t1.a,t1.b,t1.c) IN +( +SELECT t2.e,t2.f,MAX(t2.g) +FROM t2 +WHERE t2.e<5 +GROUP BY t2.e +) +GROUP BY t1.a +) AS d_tab +WHERE d_tab.a=t3.x and d_tab.b>2; +x y a b max_c +2 15 2 3 70 +2 15 2 3 70 +SET STATEMENT optimizer_switch='condition_pushdown_for_subquery=off' FOR SELECT * FROM t1 +WHERE t1.a>1 AND +(t1.a,t1.b,t1.c) IN +( +SELECT d_tab.e,MAX(d_tab.f),d_tab.max_g +FROM +( +SELECT t2.e, t2.f, MAX(t2.g) AS max_g +FROM t2 +GROUP BY t2.f +HAVING max_g>25 +) as d_tab +WHERE d_tab.e<5 +GROUP BY d_tab.e +) +; +a b c d +2 3 40 4 +SELECT * FROM t1 +WHERE t1.a>1 AND +(t1.a,t1.b,t1.c) IN +( +SELECT d_tab.e,MAX(d_tab.f),d_tab.max_g +FROM +( +SELECT t2.e, t2.f, MAX(t2.g) AS max_g +FROM t2 +GROUP BY t2.f +HAVING max_g>25 +) as d_tab +WHERE d_tab.e<5 +GROUP BY d_tab.e +) +; +a b c d +2 3 40 4 +EXPLAIN SELECT * FROM t1 +WHERE t1.a>1 AND +(t1.a,t1.b,t1.c) IN +( +SELECT d_tab.e,MAX(d_tab.f),d_tab.max_g +FROM +( +SELECT t2.e, t2.f, MAX(t2.g) AS max_g +FROM t2 +GROUP BY t2.f +HAVING max_g>25 +) as d_tab +WHERE d_tab.e<5 +GROUP BY d_tab.e +) +; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 16 Using where +1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 12 test.t1.a,test.t1.b,test.t1.c 1 +2 MATERIALIZED <derived3> ALL NULL NULL NULL NULL 12 Using where; Using temporary +3 DERIVED t2 ALL NULL NULL NULL NULL 12 Using temporary; Using filesort +EXPLAIN FORMAT=JSON SELECT * FROM t1 +WHERE t1.a>1 AND +(t1.a,t1.b,t1.c) IN +( +SELECT d_tab.e,MAX(d_tab.f),d_tab.max_g +FROM +( +SELECT t2.e, t2.f, MAX(t2.g) AS max_g +FROM t2 +GROUP BY t2.f +HAVING max_g>25 +) as d_tab +WHERE d_tab.e<5 +GROUP BY d_tab.e +) +; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 16, + "filtered": 100, + "attached_condition": "t1.a > 1 and t1.a is not null and t1.b is not null and t1.c is not null" + }, + "table": { + "table_name": "<subquery2>", + "access_type": "eq_ref", + "possible_keys": ["distinct_key"], + "key": "distinct_key", + "key_length": "12", + "used_key_parts": ["e", "MAX(d_tab.f)", "max_g"], + "ref": ["test.t1.a", "test.t1.b", "test.t1.c"], + "rows": 1, + "filtered": 100, + "materialized": { + "unique": 1, + "query_block": { + "select_id": 2, + "temporary_table": { + "table": { + "table_name": "<derived3>", + "access_type": "ALL", + "rows": 12, + "filtered": 100, + "attached_condition": "d_tab.e < 5 and d_tab.e > 1", + "materialized": { + "query_block": { + "select_id": 3, + "having_condition": "max_g > 25", + "filesort": { + "sort_key": "t2.f", + "temporary_table": { + "table": { + "table_name": "t2", + "access_type": "ALL", + "rows": 12, + "filtered": 100 + } + } + } + } + } + } + } + } + } + } + } +} +# conjunctive subformula : pushing into WHERE of the derived table +# extracted AND formula : pushing into WHERE of the IN subquery from +# the derived table +SELECT * +FROM t3, +( +SELECT t1.a,t1.b,max(t1.c) as max_c +FROM t1 +WHERE t1.a>1 AND +(t1.a,t1.b,t1.c) IN +( +SELECT t2.e,t2.f,MAX(t2.g) +FROM t2 +GROUP BY t2.e +HAVING t2.f<5 +) +GROUP BY t1.a +) AS d_tab +WHERE d_tab.a=t3.x and d_tab.a<5; +x y a b max_c +2 15 2 3 70 +4 24 4 2 24 +2 15 2 3 70 +SET STATEMENT optimizer_switch='condition_pushdown_for_subquery=off' FOR SELECT * FROM t1 +WHERE t1.a>1 AND +(t1.a,t1.b,t1.c) IN +( +SELECT d_tab.e,MAX(d_tab.f),d_tab.max_g +FROM +( +SELECT t2.e, t2.f, MAX(t2.g) AS max_g +FROM t2 +GROUP BY t2.f +HAVING max_g>25 +) as d_tab +WHERE d_tab.e<5 +GROUP BY d_tab.e +) +; +a b c d +2 3 40 4 +SELECT * FROM t1 +WHERE t1.a>1 AND +(t1.a,t1.b,t1.c) IN +( +SELECT d_tab.e,MAX(d_tab.f),d_tab.max_g +FROM +( +SELECT t2.e, t2.f, MAX(t2.g) AS max_g +FROM t2 +GROUP BY t2.f +HAVING max_g>25 +) as d_tab +WHERE d_tab.e<5 +GROUP BY d_tab.e +) +; +a b c d +2 3 40 4 +EXPLAIN SELECT * FROM t1 +WHERE t1.a>1 AND +(t1.a,t1.b,t1.c) IN +( +SELECT d_tab.e,MAX(d_tab.f),d_tab.max_g +FROM +( +SELECT t2.e, t2.f, MAX(t2.g) AS max_g +FROM t2 +GROUP BY t2.f +HAVING max_g>25 +) as d_tab +WHERE d_tab.e<5 +GROUP BY d_tab.e +) +; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 16 Using where +1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 12 test.t1.a,test.t1.b,test.t1.c 1 +2 MATERIALIZED <derived3> ALL NULL NULL NULL NULL 12 Using where; Using temporary +3 DERIVED t2 ALL NULL NULL NULL NULL 12 Using temporary; Using filesort +EXPLAIN FORMAT=JSON SELECT * FROM t1 +WHERE t1.a>1 AND +(t1.a,t1.b,t1.c) IN +( +SELECT d_tab.e,MAX(d_tab.f),d_tab.max_g +FROM +( +SELECT t2.e, t2.f, MAX(t2.g) AS max_g +FROM t2 +GROUP BY t2.f +HAVING max_g>25 +) as d_tab +WHERE d_tab.e<5 +GROUP BY d_tab.e +) +; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 16, + "filtered": 100, + "attached_condition": "t1.a > 1 and t1.a is not null and t1.b is not null and t1.c is not null" + }, + "table": { + "table_name": "<subquery2>", + "access_type": "eq_ref", + "possible_keys": ["distinct_key"], + "key": "distinct_key", + "key_length": "12", + "used_key_parts": ["e", "MAX(d_tab.f)", "max_g"], + "ref": ["test.t1.a", "test.t1.b", "test.t1.c"], + "rows": 1, + "filtered": 100, + "materialized": { + "unique": 1, + "query_block": { + "select_id": 2, + "temporary_table": { + "table": { + "table_name": "<derived3>", + "access_type": "ALL", + "rows": 12, + "filtered": 100, + "attached_condition": "d_tab.e < 5 and d_tab.e > 1", + "materialized": { + "query_block": { + "select_id": 3, + "having_condition": "max_g > 25", + "filesort": { + "sort_key": "t2.f", + "temporary_table": { + "table": { + "table_name": "t2", + "access_type": "ALL", + "rows": 12, + "filtered": 100 + } + } + } + } + } + } + } + } + } + } + } +} +# conjunctive subformula : pushing into WHERE and HAVING +# of the derived table +# extracted AND formula : pushing into WHERE of the IN subquery +# from the derived table +SET STATEMENT optimizer_switch='condition_pushdown_for_subquery=off' FOR SELECT * +FROM t3, +( +SELECT t1.a,t1.b,max(t1.c) as max_c +FROM t1 +WHERE t1.a>1 AND +(t1.a,t1.b,t1.c) IN +( +SELECT t2.e,t2.f,MAX(t2.g) +FROM t2 +GROUP BY t2.e +HAVING t2.f<5 +) +GROUP BY t1.a +) AS d_tab +WHERE d_tab.a=t3.x AND d_tab.a<5 AND d_tab.max_c<70; +x y a b max_c +4 24 4 2 24 +SELECT * +FROM t3, +( +SELECT t1.a,t1.b,max(t1.c) as max_c +FROM t1 +WHERE t1.a>1 AND +(t1.a,t1.b,t1.c) IN +( +SELECT t2.e,t2.f,MAX(t2.g) +FROM t2 +GROUP BY t2.e +HAVING t2.f<5 +) +GROUP BY t1.a +) AS d_tab +WHERE d_tab.a=t3.x AND d_tab.a<5 AND d_tab.max_c<70; +x y a b max_c +4 24 4 2 24 +EXPLAIN SELECT * +FROM t3, +( +SELECT t1.a,t1.b,max(t1.c) as max_c +FROM t1 +WHERE t1.a>1 AND +(t1.a,t1.b,t1.c) IN +( +SELECT t2.e,t2.f,MAX(t2.g) +FROM t2 +GROUP BY t2.e +HAVING t2.f<5 +) +GROUP BY t1.a +) AS d_tab +WHERE d_tab.a=t3.x AND d_tab.a<5 AND d_tab.max_c<70; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t3 ALL NULL NULL NULL NULL 8 Using where +1 PRIMARY <derived2> ref key0 key0 5 test.t3.x 2 Using where +2 DERIVED t1 ALL NULL NULL NULL NULL 16 Using where; Using temporary; Using filesort +2 DERIVED <subquery3> eq_ref distinct_key distinct_key 12 test.t1.a,test.t1.b,test.t1.c 1 +3 MATERIALIZED t2 ALL NULL NULL NULL NULL 12 Using where; Using temporary +EXPLAIN FORMAT=JSON SELECT * +FROM t3, +( +SELECT t1.a,t1.b,max(t1.c) as max_c +FROM t1 +WHERE t1.a>1 AND +(t1.a,t1.b,t1.c) IN +( +SELECT t2.e,t2.f,MAX(t2.g) +FROM t2 +GROUP BY t2.e +HAVING t2.f<5 +) +GROUP BY t1.a +) AS d_tab +WHERE d_tab.a=t3.x AND d_tab.a<5 AND d_tab.max_c<70; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "t3", + "access_type": "ALL", + "rows": 8, + "filtered": 100, + "attached_condition": "t3.x < 5 and t3.x is not null" + }, + "table": { + "table_name": "<derived2>", + "access_type": "ref", + "possible_keys": ["key0"], + "key": "key0", + "key_length": "5", + "used_key_parts": ["a"], + "ref": ["test.t3.x"], + "rows": 2, + "filtered": 100, + "attached_condition": "d_tab.max_c < 70", + "materialized": { + "query_block": { + "select_id": 2, + "having_condition": "max_c < 70", + "filesort": { + "sort_key": "t1.a", + "temporary_table": { + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 16, + "filtered": 100, + "attached_condition": "t1.a > 1 and t1.a < 5 and t1.a is not null and t1.b is not null and t1.c is not null" + }, + "table": { + "table_name": "<subquery3>", + "access_type": "eq_ref", + "possible_keys": ["distinct_key"], + "key": "distinct_key", + "key_length": "12", + "used_key_parts": ["e", "f", "MAX(t2.g)"], + "ref": ["test.t1.a", "test.t1.b", "test.t1.c"], + "rows": 1, + "filtered": 100, + "materialized": { + "unique": 1, + "query_block": { + "select_id": 3, + "having_condition": "t2.f < 5", + "temporary_table": { + "table": { + "table_name": "t2", + "access_type": "ALL", + "rows": 12, + "filtered": 100, + "attached_condition": "t2.e > 1 and t2.e < 5" + } + } + } + } + } + } + } + } + } + } + } +} +# conjunctive subformula : pushing into WHERE of the derived table +# conjunctive subformula : pushing into HAVING of the IN subquery from +# the derived table +SELECT * +FROM t3, +( +SELECT t1.a,t1.b,max(t1.c) as max_c +FROM t1 +WHERE (t1.a,t1.b,t1.c) IN +( +SELECT t2.e,t2.f,MAX(t2.g) +FROM t2 +WHERE t2.f<4 +GROUP BY t2.f +) +GROUP BY t1.a +HAVING t1.b<5 +) AS d_tab +WHERE d_tab.a=t3.x and d_tab.a<5; +x y a b max_c +1 25 1 2 70 +1 18 1 2 70 +2 15 2 3 40 +1 35 1 2 70 +2 15 2 3 40 +SET STATEMENT optimizer_switch='condition_pushdown_for_subquery=off' FOR SELECT * +FROM t3, +( +SELECT t1.a,t1.b,max(t1.c) as max_c +FROM t1 +WHERE t1.a>1 AND +(t1.a,t1.b,t1.c) IN +( +SELECT t2.e,t2.f,MAX(t2.g) +FROM t2 +GROUP BY t2.e +HAVING t2.f<5 +) +GROUP BY t1.a +) AS d_tab +WHERE d_tab.a=t3.x AND d_tab.a<5 AND d_tab.max_c<70; +x y a b max_c +4 24 4 2 24 +SELECT * +FROM t3, +( +SELECT t1.a,t1.b,max(t1.c) as max_c +FROM t1 +WHERE t1.a>1 AND +(t1.a,t1.b,t1.c) IN +( +SELECT t2.e,t2.f,MAX(t2.g) +FROM t2 +GROUP BY t2.e +HAVING t2.f<5 +) +GROUP BY t1.a +) AS d_tab +WHERE d_tab.a=t3.x AND d_tab.a<5 AND d_tab.max_c<70; +x y a b max_c +4 24 4 2 24 +EXPLAIN SELECT * +FROM t3, +( +SELECT t1.a,t1.b,max(t1.c) as max_c +FROM t1 +WHERE t1.a>1 AND +(t1.a,t1.b,t1.c) IN +( +SELECT t2.e,t2.f,MAX(t2.g) +FROM t2 +GROUP BY t2.e +HAVING t2.f<5 +) +GROUP BY t1.a +) AS d_tab +WHERE d_tab.a=t3.x AND d_tab.a<5 AND d_tab.max_c<70; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t3 ALL NULL NULL NULL NULL 8 Using where +1 PRIMARY <derived2> ref key0 key0 5 test.t3.x 2 Using where +2 DERIVED t1 ALL NULL NULL NULL NULL 16 Using where; Using temporary; Using filesort +2 DERIVED <subquery3> eq_ref distinct_key distinct_key 12 test.t1.a,test.t1.b,test.t1.c 1 +3 MATERIALIZED t2 ALL NULL NULL NULL NULL 12 Using where; Using temporary +EXPLAIN FORMAT=JSON SELECT * +FROM t3, +( +SELECT t1.a,t1.b,max(t1.c) as max_c +FROM t1 +WHERE t1.a>1 AND +(t1.a,t1.b,t1.c) IN +( +SELECT t2.e,t2.f,MAX(t2.g) +FROM t2 +GROUP BY t2.e +HAVING t2.f<5 +) +GROUP BY t1.a +) AS d_tab +WHERE d_tab.a=t3.x AND d_tab.a<5 AND d_tab.max_c<70; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "t3", + "access_type": "ALL", + "rows": 8, + "filtered": 100, + "attached_condition": "t3.x < 5 and t3.x is not null" + }, + "table": { + "table_name": "<derived2>", + "access_type": "ref", + "possible_keys": ["key0"], + "key": "key0", + "key_length": "5", + "used_key_parts": ["a"], + "ref": ["test.t3.x"], + "rows": 2, + "filtered": 100, + "attached_condition": "d_tab.max_c < 70", + "materialized": { + "query_block": { + "select_id": 2, + "having_condition": "max_c < 70", + "filesort": { + "sort_key": "t1.a", + "temporary_table": { + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 16, + "filtered": 100, + "attached_condition": "t1.a > 1 and t1.a < 5 and t1.a is not null and t1.b is not null and t1.c is not null" + }, + "table": { + "table_name": "<subquery3>", + "access_type": "eq_ref", + "possible_keys": ["distinct_key"], + "key": "distinct_key", + "key_length": "12", + "used_key_parts": ["e", "f", "MAX(t2.g)"], + "ref": ["test.t1.a", "test.t1.b", "test.t1.c"], + "rows": 1, + "filtered": 100, + "materialized": { + "unique": 1, + "query_block": { + "select_id": 3, + "having_condition": "t2.f < 5", + "temporary_table": { + "table": { + "table_name": "t2", + "access_type": "ALL", + "rows": 12, + "filtered": 100, + "attached_condition": "t2.e > 1 and t2.e < 5" + } + } + } + } + } + } + } + } + } + } + } +} +# conjunctive subformula : pushing into WHERE +# using WINDOW FUNCTIONS : using MAX function +SET STATEMENT optimizer_switch='condition_pushdown_for_subquery=off' FOR SELECT * FROM t1 +WHERE (t1.b>1) AND +(t1.b, t1.c) IN +( +SELECT t2.f, MAX(t2.g) OVER (PARTITION BY t2.f) +FROM t2 +WHERE t2.e<5 +) +; +a b c d +1 3 40 1 +2 3 40 4 +1 4 35 3 +1 2 70 5 +SELECT * FROM t1 +WHERE (t1.b>1) AND +(t1.b, t1.c) IN +( +SELECT t2.f, MAX(t2.g) OVER (PARTITION BY t2.f) +FROM t2 +WHERE t2.e<5 +) +; +a b c d +1 3 40 1 +2 3 40 4 +1 4 35 3 +1 2 70 5 +EXPLAIN SELECT * FROM t1 +WHERE (t1.b>1) AND +(t1.b, t1.c) IN +( +SELECT t2.f, MAX(t2.g) OVER (PARTITION BY t2.f) +FROM t2 +WHERE t2.e<5 +) +; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 16 Using where +1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 8 test.t1.b,test.t1.c 1 +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 12 Using where; Using temporary +EXPLAIN FORMAT=JSON SELECT * FROM t1 +WHERE (t1.b>1) AND +(t1.b, t1.c) IN +( +SELECT t2.f, MAX(t2.g) OVER (PARTITION BY t2.f) +FROM t2 +WHERE t2.e<5 +) +; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 16, + "filtered": 100, + "attached_condition": "t1.b > 1 and t1.b is not null and t1.c is not null" + }, + "table": { + "table_name": "<subquery2>", + "access_type": "eq_ref", + "possible_keys": ["distinct_key"], + "key": "distinct_key", + "key_length": "8", + "used_key_parts": ["f", "MAX(t2.g) OVER (PARTITION BY t2.f)"], + "ref": ["test.t1.b", "test.t1.c"], + "rows": 1, + "filtered": 100, + "materialized": { + "unique": 1, + "query_block": { + "select_id": 2, + "window_functions_computation": { + "sorts": { + "filesort": { + "sort_key": "t2.f" + } + }, + "temporary_table": { + "table": { + "table_name": "t2", + "access_type": "ALL", + "rows": 12, + "filtered": 100, + "attached_condition": "t2.e < 5 and t2.f > 1" + } + } + } + } + } + } + } +} +# conjunctive subformula : pushing into WHERE +# using WINDOW FUNCTIONS : using SUM function +SET STATEMENT optimizer_switch='condition_pushdown_for_subquery=off' FOR SELECT * FROM t1 +WHERE (t1.b>1) AND +(t1.b, t1.c) IN +( +SELECT t2.f, CAST(SUM(t2.g) OVER (PARTITION BY t2.f) AS INT) +FROM t2 +WHERE t2.e<5 +) +; +a b c d +5 3 72 4 +SELECT * FROM t1 +WHERE (t1.b>1) AND +(t1.b, t1.c) IN +( +SELECT t2.f, CAST(SUM(t2.g) OVER (PARTITION BY t2.f) AS INT) +FROM t2 +WHERE t2.e<5 +) +; +a b c d +5 3 72 4 +EXPLAIN SELECT * FROM t1 +WHERE (t1.b>1) AND +(t1.b, t1.c) IN +( +SELECT t2.f, CAST(SUM(t2.g) OVER (PARTITION BY t2.f) AS INT) +FROM t2 +WHERE t2.e<5 +) +; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 16 Using where +1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 12 test.t1.b,test.t1.c 1 Using where +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 12 Using where; Using temporary +EXPLAIN FORMAT=JSON SELECT * FROM t1 +WHERE (t1.b>1) AND +(t1.b, t1.c) IN +( +SELECT t2.f, CAST(SUM(t2.g) OVER (PARTITION BY t2.f) AS INT) +FROM t2 +WHERE t2.e<5 +) +; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 16, + "filtered": 100, + "attached_condition": "t1.b > 1 and t1.b is not null and t1.c is not null" + }, + "table": { + "table_name": "<subquery2>", + "access_type": "eq_ref", + "possible_keys": ["distinct_key"], + "key": "distinct_key", + "key_length": "12", + "used_key_parts": ["f", "CAST(SUM(t2.g) OVER (PARTITION BY t2.f) AS INT)"], + "ref": ["test.t1.b", "test.t1.c"], + "rows": 1, + "filtered": 100, + "attached_condition": "t1.c = `<subquery2>`.`CAST(SUM(t2.g) OVER (PARTITION BY t2.f) AS INT)`", + "materialized": { + "unique": 1, + "query_block": { + "select_id": 2, + "window_functions_computation": { + "sorts": { + "filesort": { + "sort_key": "t2.f" + } + }, + "temporary_table": { + "table": { + "table_name": "t2", + "access_type": "ALL", + "rows": 12, + "filtered": 100, + "attached_condition": "t2.e < 5 and t2.f > 1" + } + } + } + } + } + } + } +} +DROP TABLE t1,t2,t3; +DROP VIEW v1; diff --git a/mysql-test/r/mysqld--help.result b/mysql-test/r/mysqld--help.result index f980018b86b..d6d94c6b22d 100644 --- a/mysql-test/r/mysqld--help.result +++ b/mysql-test/r/mysqld--help.result @@ -665,7 +665,8 @@ The following options may be given as the first argument: join_cache_hashed, join_cache_bka, optimize_join_buffer_size, table_elimination, extended_keys, exists_to_in, orderby_uses_equalities, - condition_pushdown_for_derived, split_materialized + condition_pushdown_for_derived, split_materialized, + condition_pushdown_for_subquery --optimizer-use-condition-selectivity=# Controls selectivity of which conditions the optimizer takes into account to calculate cardinality of a partial @@ -1518,7 +1519,7 @@ old-style-user-limits FALSE optimizer-prune-level 1 optimizer-search-depth 62 optimizer-selectivity-sampling-limit 100 -optimizer-switch index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on +optimizer-switch index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on,condition_pushdown_for_subquery=on optimizer-use-condition-selectivity 1 performance-schema FALSE performance-schema-accounts-size -1 diff --git a/mysql-test/r/subselect_mat.result b/mysql-test/r/subselect_mat.result index 6b5db62093e..64937a7b9a5 100644 --- a/mysql-test/r/subselect_mat.result +++ b/mysql-test/r/subselect_mat.result @@ -1925,7 +1925,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 Using where; Using join buffer (flat, BNL join) 2 MATERIALIZED t2 ALL NULL NULL NULL NULL 3 100.00 Warnings: -Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from <materialize> (/* select#2 */ select max(`test`.`t2`.`c`) from `test`.`t2`) join `test`.`t1` where `test`.`t1`.`b` = 7 and `test`.`t1`.`a` = `<subquery2>`.`MAX(c)` and (<cache>(`<subquery2>`.`MAX(c)` is null) or `<subquery2>`.`MAX(c)` = 7) +Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from <materialize> (/* select#2 */ select max(`test`.`t2`.`c`) from `test`.`t2` having `MAX(c)` is null or `MAX(c)` = 7) join `test`.`t1` where `test`.`t1`.`b` = 7 and `test`.`t1`.`a` = `<subquery2>`.`MAX(c)` and (<cache>(`<subquery2>`.`MAX(c)` is null) or `<subquery2>`.`MAX(c)` = 7) SELECT * FROM t1 WHERE a IN (SELECT MAX(c) FROM t2) AND b=7 AND (a IS NULL OR a=b); a b diff --git a/mysql-test/r/subselect_sj_mat.result b/mysql-test/r/subselect_sj_mat.result index 9e1870875ce..6a4a1a4ad5b 100644 --- a/mysql-test/r/subselect_sj_mat.result +++ b/mysql-test/r/subselect_sj_mat.result @@ -1963,7 +1963,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 Using where; Using join buffer (flat, BNL join) 2 MATERIALIZED t2 ALL NULL NULL NULL NULL 3 100.00 Warnings: -Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from <materialize> (/* select#2 */ select max(`test`.`t2`.`c`) from `test`.`t2`) join `test`.`t1` where `test`.`t1`.`b` = 7 and `test`.`t1`.`a` = `<subquery2>`.`MAX(c)` and (<cache>(`<subquery2>`.`MAX(c)` is null) or `<subquery2>`.`MAX(c)` = 7) +Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from <materialize> (/* select#2 */ select max(`test`.`t2`.`c`) from `test`.`t2` having `MAX(c)` is null or `MAX(c)` = 7) join `test`.`t1` where `test`.`t1`.`b` = 7 and `test`.`t1`.`a` = `<subquery2>`.`MAX(c)` and (<cache>(`<subquery2>`.`MAX(c)` is null) or `<subquery2>`.`MAX(c)` = 7) SELECT * FROM t1 WHERE a IN (SELECT MAX(c) FROM t2) AND b=7 AND (a IS NULL OR a=b); a b diff --git a/mysql-test/suite/sys_vars/r/optimizer_switch_basic.result b/mysql-test/suite/sys_vars/r/optimizer_switch_basic.result index 87c837986ac..bc22fe198a1 100644 --- a/mysql-test/suite/sys_vars/r/optimizer_switch_basic.result +++ b/mysql-test/suite/sys_vars/r/optimizer_switch_basic.result @@ -1,63 +1,63 @@ SET @start_global_value = @@global.optimizer_switch; SELECT @start_global_value; @start_global_value -index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on +index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on,condition_pushdown_for_subquery=on select @@global.optimizer_switch; @@global.optimizer_switch -index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on +index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on,condition_pushdown_for_subquery=on select @@session.optimizer_switch; @@session.optimizer_switch -index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on +index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on,condition_pushdown_for_subquery=on show global variables like 'optimizer_switch'; Variable_name Value -optimizer_switch index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on +optimizer_switch index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on,condition_pushdown_for_subquery=on show session variables like 'optimizer_switch'; Variable_name Value -optimizer_switch index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on +optimizer_switch index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on,condition_pushdown_for_subquery=on select * from information_schema.global_variables where variable_name='optimizer_switch'; VARIABLE_NAME VARIABLE_VALUE -OPTIMIZER_SWITCH index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on +OPTIMIZER_SWITCH index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on,condition_pushdown_for_subquery=on select * from information_schema.session_variables where variable_name='optimizer_switch'; VARIABLE_NAME VARIABLE_VALUE -OPTIMIZER_SWITCH index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on +OPTIMIZER_SWITCH index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on,condition_pushdown_for_subquery=on set global optimizer_switch=10; set session optimizer_switch=5; select @@global.optimizer_switch; @@global.optimizer_switch -index_merge=off,index_merge_union=on,index_merge_sort_union=off,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,materialization=off,in_to_exists=off,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=off,table_elimination=off,extended_keys=off,exists_to_in=off,orderby_uses_equalities=off,condition_pushdown_for_derived=off,split_materialized=off +index_merge=off,index_merge_union=on,index_merge_sort_union=off,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,materialization=off,in_to_exists=off,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=off,table_elimination=off,extended_keys=off,exists_to_in=off,orderby_uses_equalities=off,condition_pushdown_for_derived=off,split_materialized=off,condition_pushdown_for_subquery=off select @@session.optimizer_switch; @@session.optimizer_switch -index_merge=on,index_merge_union=off,index_merge_sort_union=on,index_merge_intersection=off,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,materialization=off,in_to_exists=off,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=off,table_elimination=off,extended_keys=off,exists_to_in=off,orderby_uses_equalities=off,condition_pushdown_for_derived=off,split_materialized=off +index_merge=on,index_merge_union=off,index_merge_sort_union=on,index_merge_intersection=off,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,materialization=off,in_to_exists=off,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=off,table_elimination=off,extended_keys=off,exists_to_in=off,orderby_uses_equalities=off,condition_pushdown_for_derived=off,split_materialized=off,condition_pushdown_for_subquery=off set global optimizer_switch="index_merge_sort_union=on"; set session optimizer_switch="index_merge=off"; select @@global.optimizer_switch; @@global.optimizer_switch -index_merge=off,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,materialization=off,in_to_exists=off,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=off,table_elimination=off,extended_keys=off,exists_to_in=off,orderby_uses_equalities=off,condition_pushdown_for_derived=off,split_materialized=off +index_merge=off,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,materialization=off,in_to_exists=off,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=off,table_elimination=off,extended_keys=off,exists_to_in=off,orderby_uses_equalities=off,condition_pushdown_for_derived=off,split_materialized=off,condition_pushdown_for_subquery=off select @@session.optimizer_switch; @@session.optimizer_switch -index_merge=off,index_merge_union=off,index_merge_sort_union=on,index_merge_intersection=off,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,materialization=off,in_to_exists=off,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=off,table_elimination=off,extended_keys=off,exists_to_in=off,orderby_uses_equalities=off,condition_pushdown_for_derived=off,split_materialized=off +index_merge=off,index_merge_union=off,index_merge_sort_union=on,index_merge_intersection=off,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,materialization=off,in_to_exists=off,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=off,table_elimination=off,extended_keys=off,exists_to_in=off,orderby_uses_equalities=off,condition_pushdown_for_derived=off,split_materialized=off,condition_pushdown_for_subquery=off show global variables like 'optimizer_switch'; Variable_name Value -optimizer_switch index_merge=off,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,materialization=off,in_to_exists=off,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=off,table_elimination=off,extended_keys=off,exists_to_in=off,orderby_uses_equalities=off,condition_pushdown_for_derived=off,split_materialized=off +optimizer_switch index_merge=off,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,materialization=off,in_to_exists=off,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=off,table_elimination=off,extended_keys=off,exists_to_in=off,orderby_uses_equalities=off,condition_pushdown_for_derived=off,split_materialized=off,condition_pushdown_for_subquery=off show session variables like 'optimizer_switch'; Variable_name Value -optimizer_switch index_merge=off,index_merge_union=off,index_merge_sort_union=on,index_merge_intersection=off,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,materialization=off,in_to_exists=off,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=off,table_elimination=off,extended_keys=off,exists_to_in=off,orderby_uses_equalities=off,condition_pushdown_for_derived=off,split_materialized=off +optimizer_switch index_merge=off,index_merge_union=off,index_merge_sort_union=on,index_merge_intersection=off,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,materialization=off,in_to_exists=off,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=off,table_elimination=off,extended_keys=off,exists_to_in=off,orderby_uses_equalities=off,condition_pushdown_for_derived=off,split_materialized=off,condition_pushdown_for_subquery=off select * from information_schema.global_variables where variable_name='optimizer_switch'; VARIABLE_NAME VARIABLE_VALUE -OPTIMIZER_SWITCH index_merge=off,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,materialization=off,in_to_exists=off,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=off,table_elimination=off,extended_keys=off,exists_to_in=off,orderby_uses_equalities=off,condition_pushdown_for_derived=off,split_materialized=off +OPTIMIZER_SWITCH index_merge=off,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,materialization=off,in_to_exists=off,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=off,table_elimination=off,extended_keys=off,exists_to_in=off,orderby_uses_equalities=off,condition_pushdown_for_derived=off,split_materialized=off,condition_pushdown_for_subquery=off select * from information_schema.session_variables where variable_name='optimizer_switch'; VARIABLE_NAME VARIABLE_VALUE -OPTIMIZER_SWITCH index_merge=off,index_merge_union=off,index_merge_sort_union=on,index_merge_intersection=off,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,materialization=off,in_to_exists=off,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=off,table_elimination=off,extended_keys=off,exists_to_in=off,orderby_uses_equalities=off,condition_pushdown_for_derived=off,split_materialized=off +OPTIMIZER_SWITCH index_merge=off,index_merge_union=off,index_merge_sort_union=on,index_merge_intersection=off,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,materialization=off,in_to_exists=off,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=off,table_elimination=off,extended_keys=off,exists_to_in=off,orderby_uses_equalities=off,condition_pushdown_for_derived=off,split_materialized=off,condition_pushdown_for_subquery=off set session optimizer_switch="default"; select @@session.optimizer_switch; @@session.optimizer_switch -index_merge=off,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,materialization=off,in_to_exists=off,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=off,table_elimination=off,extended_keys=off,exists_to_in=off,orderby_uses_equalities=off,condition_pushdown_for_derived=off,split_materialized=off +index_merge=off,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,materialization=off,in_to_exists=off,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=off,table_elimination=off,extended_keys=off,exists_to_in=off,orderby_uses_equalities=off,condition_pushdown_for_derived=off,split_materialized=off,condition_pushdown_for_subquery=off set optimizer_switch = replace(@@optimizer_switch, '=off', '=on'); Warnings: Warning 1681 'engine_condition_pushdown=on' is deprecated and will be removed in a future release select @@optimizer_switch; @@optimizer_switch -index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=on,engine_condition_pushdown=on,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=on,mrr_cost_based=on,mrr_sort_keys=on,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=on,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on +index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=on,engine_condition_pushdown=on,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=on,mrr_cost_based=on,mrr_sort_keys=on,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=on,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on,condition_pushdown_for_subquery=on set global optimizer_switch=1.1; ERROR 42000: Incorrect argument type to variable 'optimizer_switch' set global optimizer_switch=1e1; @@ -69,4 +69,4 @@ ERROR 42000: Variable 'optimizer_switch' can't be set to the value of 'foobar' SET @@global.optimizer_switch = @start_global_value; SELECT @@global.optimizer_switch; @@global.optimizer_switch -index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on +index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on,condition_pushdown_for_subquery=on diff --git a/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result b/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result index 9ee1d72d406..b9286aa0188 100644 --- a/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result +++ b/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result @@ -2883,17 +2883,17 @@ ENUM_VALUE_LIST NULL READ_ONLY NO COMMAND_LINE_ARGUMENT REQUIRED VARIABLE_NAME OPTIMIZER_SWITCH -SESSION_VALUE index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on -GLOBAL_VALUE index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on +SESSION_VALUE index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on,condition_pushdown_for_subquery=on +GLOBAL_VALUE index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on,condition_pushdown_for_subquery=on GLOBAL_VALUE_ORIGIN COMPILE-TIME -DEFAULT_VALUE index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on +DEFAULT_VALUE index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on,condition_pushdown_for_subquery=on VARIABLE_SCOPE SESSION VARIABLE_TYPE FLAGSET VARIABLE_COMMENT Fine-tune the optimizer behavior NUMERIC_MIN_VALUE NULL NUMERIC_MAX_VALUE NULL NUMERIC_BLOCK_SIZE NULL -ENUM_VALUE_LIST index_merge,index_merge_union,index_merge_sort_union,index_merge_intersection,index_merge_sort_intersection,engine_condition_pushdown,index_condition_pushdown,derived_merge,derived_with_keys,firstmatch,loosescan,materialization,in_to_exists,semijoin,partial_match_rowid_merge,partial_match_table_scan,subquery_cache,mrr,mrr_cost_based,mrr_sort_keys,outer_join_with_cache,semijoin_with_cache,join_cache_incremental,join_cache_hashed,join_cache_bka,optimize_join_buffer_size,table_elimination,extended_keys,exists_to_in,orderby_uses_equalities,condition_pushdown_for_derived,split_materialized,default +ENUM_VALUE_LIST index_merge,index_merge_union,index_merge_sort_union,index_merge_intersection,index_merge_sort_intersection,engine_condition_pushdown,index_condition_pushdown,derived_merge,derived_with_keys,firstmatch,loosescan,materialization,in_to_exists,semijoin,partial_match_rowid_merge,partial_match_table_scan,subquery_cache,mrr,mrr_cost_based,mrr_sort_keys,outer_join_with_cache,semijoin_with_cache,join_cache_incremental,join_cache_hashed,join_cache_bka,optimize_join_buffer_size,table_elimination,extended_keys,exists_to_in,orderby_uses_equalities,condition_pushdown_for_derived,split_materialized,condition_pushdown_for_subquery,default READ_ONLY NO COMMAND_LINE_ARGUMENT REQUIRED VARIABLE_NAME OPTIMIZER_USE_CONDITION_SELECTIVITY diff --git a/mysql-test/t/in_subq_cond_pushdown.test b/mysql-test/t/in_subq_cond_pushdown.test new file mode 100644 index 00000000000..6c63b16acd8 --- /dev/null +++ b/mysql-test/t/in_subq_cond_pushdown.test @@ -0,0 +1,759 @@ +LET $no_pushdown= + SET STATEMENT optimizer_switch='condition_pushdown_for_subquery=off' FOR; + +CREATE TABLE t1 (a INT, b INT, c INT, d INT); +CREATE TABLE t2 (e INT, f INT, g INT); +CREATE TABLE t3 (x INT, y INT); + +INSERT INTO t1 VALUES +(1,1,18,1), (2,1,25,1), (1,3,40,1), (2,3,40,4), +(4,2,24,4), (3,2,23,1), (1,2,40,2), (3,4,17,2), +(5,5,65,1), (2,3,70,3), (1,4,35,3), (2,3,25,3), +(2,2,40,4), (1,4,55,1), (5,3,72,4), (1,2,70,5); + +INSERT INTO t2 VALUES +(1,2,38), (2,3,15), (1,3,40), (1,4,35), +(2,2,70), (3,4,23), (5,5,12), (5,4,17), +(3,3,17), (4,2,24), (2,5,25), (5,1,65); + +INSERT INTO t3 VALUES +(1,25), (1,18), (2,15), (4,24), +(1,35), (3,23), (3,17), (2,15); + +CREATE VIEW v1 AS +( + SELECT t3.x AS v1_x, t3.y AS v1_y FROM t3 WHERE t3.x<=3 +); + +CREATE VIEW v2 AS +( + SELECT t2.e, t2.f, MAX(t2.g) AS max_g + FROM t2 + GROUP BY t2.e + HAVING max_g>25 +); + +--echo # conjunctive subformula : pushing into HAVING +LET $query= +SELECT * FROM t1 +WHERE t1.c<25 AND + (t1.a,t1.c) IN (SELECT t2.e,MAX(t2.g) FROM t2 WHERE t2.e<5 GROUP BY t2.e); + +EVAL $no_pushdown $query; +EVAL $query; +EVAL EXPLAIN $query; +EVAL EXPLAIN FORMAT=JSON $query; + +--echo # extracted AND formula : pushing into HAVING +LET $query= +SELECT * FROM t1 +WHERE t1.c>55 AND t1.b<4 AND + (t1.a,t1.b,t1.c) IN + ( + SELECT t2.e,t2.f,MAX(t2.g) + FROM t2 + WHERE t2.e<5 + GROUP BY t2.e + ) +; + +EVAL $no_pushdown $query; +EVAL $query; +EVAL EXPLAIN $query; +EVAL EXPLAIN FORMAT=JSON $query; + +--echo # extracted OR formula : pushing into HAVING +LET $query= +SELECT * FROM t1 +WHERE (t1.c>60 OR t1.c<25) AND + (t1.a,t1.b,t1.c) IN + ( + SELECT t2.e,t2.f,MAX(t2.g) + FROM t2 + WHERE t2.e<5 + GROUP BY t2.e + ) +; + +EVAL $no_pushdown $query; +EVAL $query; +EVAL EXPLAIN $query; +EVAL EXPLAIN FORMAT=JSON $query; + +--echo # extracted AND-OR formula : pushing into HAVING +LET $query= +SELECT * FROM t1 +WHERE ((t1.c>60 OR t1.c<25) AND t1.b>2) AND + (t1.a,t1.b,t1.c) IN + ( + SELECT t2.e,t2.f,MAX(t2.g) + FROM t2 + WHERE t2.e<5 + GROUP BY t2.e + ) +; + +EVAL $no_pushdown $query; +EVAL $query; +EVAL EXPLAIN $query; +EVAL EXPLAIN FORMAT=JSON $query; + +--echo # conjunctive subformula : pushing into HAVING +LET $query= +SELECT * FROM t1 +WHERE ((t1.a<2 OR t1.d>3) AND t1.b>1) AND + (t1.a,t1.b,t1.c) IN + ( + SELECT t2.e,t2.f,MAX(t2.g) + FROM t2 + WHERE t2.e<5 + GROUP BY t2.e + ) +; + +EVAL $no_pushdown $query; +EVAL $query; +EVAL EXPLAIN $query; +EVAL EXPLAIN FORMAT=JSON $query; + +--echo # using view IN subquery defINition : pushing into HAVING +LET $query= +SELECT * FROM t1 +WHERE t1.c>20 AND + (t1.a,t1.c) IN + ( + SELECT v1_x,MAX(v1_y) + FROM v1 + WHERE v1_x>1 + GROUP BY v1_x + ) +; + +EVAL $no_pushdown $query; +EVAL $query; +EVAL EXPLAIN $query; +EVAL EXPLAIN FORMAT=JSON $query; + +--echo # using equality : pushing into WHERE +LET $query= +SELECT * FROM t1,v1 +WHERE t1.c>20 AND t1.c=v1_y AND + (t1.a,t1.c) IN + ( + SELECT t2.e,MAX(t2.g) + FROM t2 + WHERE t2.e<5 + GROUP BY t2.e + ) +; + +EVAL $no_pushdown $query; +EVAL $query; +EVAL EXPLAIN $query; +EVAL EXPLAIN FORMAT=JSON $query; + +--echo # conjunctive subformula : pushing into WHERE +LET $query= +SELECT * FROM t1 +WHERE t1.a<2 AND + (t1.a,t1.c) IN + ( + SELECT t2.e,MAX(t2.g) + FROM t2 + WHERE t2.e<5 + GROUP BY t2.e + ) +; + +EVAL $no_pushdown $query; +EVAL $query; +EVAL EXPLAIN $query; +EVAL EXPLAIN FORMAT=JSON $query; + +--echo # extracted AND formula : pushing into WHERE +LET $query= +SELECT * FROM t1 +WHERE t1.a>2 AND t1.a<5 AND + (t1.a,t1.c) IN + ( + SELECT t2.e,MAX(t2.g) + FROM t2 + WHERE t2.e<5 + GROUP BY t2.e + ) +; + +EVAL $no_pushdown $query; +EVAL $query; +EVAL EXPLAIN $query; +EVAL EXPLAIN FORMAT=JSON $query; + +--echo # extracted OR formula : pushing into WHERE +LET $query= +SELECT * FROM t1 +WHERE (t1.a<2 OR t1.a>=4) AND + (t1.a,t1.c) IN + ( + SELECT t2.e,MAX(t2.g) + FROM t2 + WHERE t2.e<5 + GROUP BY t2.e + ) +; + +EVAL $no_pushdown $query; +EVAL $query; +EVAL EXPLAIN $query; +EVAL EXPLAIN FORMAT=JSON $query; + +--echo # extracted AND-OR formula : pushing into WHERE +LET $query= +SELECT * FROM t1 +WHERE ((t1.a<2 OR t1.a=5) AND t1.b>3) AND + (t1.a,t1.b,t1.c) IN + ( + SELECT t2.e,t2.f,MAX(t2.g) + FROM t2 + WHERE t2.e<5 + GROUP BY t2.e,t2.f + ) +; + +EVAL $no_pushdown $query; +EVAL $query; +EVAL EXPLAIN $query; +EVAL EXPLAIN FORMAT=JSON $query; + +--echo # extracted AND-OR formula : pushing into WHERE +LET $query= +SELECT * FROM t1 +WHERE ((t1.a<2 OR t1.a=5) AND t1.b>3) AND + (t1.a,t1.b,t1.c) IN + ( + SELECT t2.e,t2.f,MAX(t2.g) + FROM t2 + WHERE t2.e<5 + GROUP BY t2.e,t2.f + ) +; + +EVAL $no_pushdown $query; +EVAL $query; +EVAL EXPLAIN $query; +EVAL EXPLAIN FORMAT=JSON $query; + +--echo # conjunctive subformula : pushing into WHERE +LET $query= +SELECT * FROM t1 +WHERE ((t1.b<3 OR t1.d>2) AND t1.a<2) AND + (t1.a,t1.b,t1.c) IN + ( + SELECT t2.e,t2.f,MAX(t2.g) + FROM t2 + WHERE t2.e<5 + GROUP BY t2.e + ) +; + +EVAL $no_pushdown $query; +EVAL $query; +EVAL EXPLAIN $query; +EVAL EXPLAIN FORMAT=JSON $query; + +--echo # using equalities : pushing into WHERE +LET $query= +SELECT * FROM t1 +WHERE t1.d=1 AND t1.a=t1.d AND + (t1.a,t1.c) IN + ( + SELECT t2.e,MAX(t2.g) + FROM t2 + WHERE t2.e<5 + GROUP BY t2.e + ) +; + +EVAL $no_pushdown $query; +EVAL $query; +EVAL EXPLAIN $query; +EVAL EXPLAIN FORMAT=JSON $query; + +--echo # using equality : pushing into WHERE +LET $query= +SELECT * FROM t1 +WHERE t1.d>1 AND t1.a=t1.d AND + (t1.a,t1.c) IN + ( + SELECT t2.e,MAX(t2.g) + FROM t2 + WHERE t2.e<5 + GROUP BY t2.e + ) +; + +EVAL $no_pushdown $query; +EVAL $query; +EVAL EXPLAIN $query; +EVAL EXPLAIN FORMAT=JSON $query; + +--echo # using view IN subquery definition : pushing into WHERE +LET $query= +SELECT * FROM t1 +WHERE t1.a<3 AND + (t1.a,t1.c) IN + ( + SELECT v1_x,MAX(v1_y) + FROM v1 + WHERE v1_x>1 + GROUP BY v1_x + ) +; + +EVAL $no_pushdown $query; +EVAL $query; +EVAL EXPLAIN $query; +EVAL EXPLAIN FORMAT=JSON $query; + +--echo # using equality : pushing into WHERE +LET $query= +SELECT * FROM t1,v1 +WHERE t1.a=v1_x AND v1_x<2 AND v1_y>30 AND + (t1.a,t1.c) IN + ( + SELECT t2.e,MAX(t2.g) + FROM t2 + WHERE t2.e<5 + GROUP BY t2.e + ) +; + +EVAL $no_pushdown $query; +EVAL $query; +EVAL EXPLAIN $query; +EVAL EXPLAIN FORMAT=JSON $query; + +--echo # conjunctive subformula : pushing into WHERE +--echo # extracted OR formula : pushing into HAVING +LET $query= +SELECT * FROM t1 +WHERE ((t1.b<3 OR t1.b=4) AND t1.a<3) AND + (t1.a,t1.b,t1.c) IN + ( + SELECT t2.e,t2.f,MAX(t2.g) + FROM t2 + WHERE t2.e<5 + GROUP BY t2.e + ) +; + +EVAL $no_pushdown $query; +EVAL $query; +EVAL EXPLAIN $query; +EVAL EXPLAIN FORMAT=JSON $query; + +--echo # conjunctive subformula using addition : pushing into HAVING +LET $query= +SELECT * FROM t1 +WHERE (t1.a+t1.c>41) AND + (t1.a,t1.c) IN + ( + SELECT t2.e,MAX(t2.g) + FROM t2 + WHERE t2.e<5 + GROUP BY t2.e + ) +; + +EVAL $no_pushdown $query; +EVAL $query; +EVAL EXPLAIN $query; +EVAL EXPLAIN FORMAT=JSON $query; + +--echo # conjunctive subformula using substitution : pushing into HAVING +LET $query= +SELECT * FROM t1 +WHERE (t1.c-t1.a<35) AND + (t1.a,t1.c) IN + ( + SELECT t2.e,MAX(t2.g) + FROM t2 + WHERE t2.e<5 + GROUP BY t2.e + ) +; + +EVAL $no_pushdown $query; +EVAL $query; +EVAL EXPLAIN $query; +EVAL EXPLAIN FORMAT=JSON $query; + +--echo # conjunctive subformula using multiplication : pushing into HAVING +LET $query= +SELECT * FROM t1 +WHERE (t1.c*t1.a>100) AND + (t1.a,t1.c) IN + ( + SELECT t2.e,MAX(t2.g) + FROM t2 + WHERE t2.e<5 + GROUP BY t2.e + ) +; + +EVAL $no_pushdown $query; +EVAL $query; +EVAL EXPLAIN $query; +EVAL EXPLAIN FORMAT=JSON $query; + +--echo # conjunctive subformula using division : pushing into HAVING +LET $query= +SELECT * FROM t1 +WHERE (t1.c/t1.a>30) AND + (t1.a,t1.c) IN + ( + SELECT t2.e,MAX(t2.g) + FROM t2 + WHERE t2.e<5 + GROUP BY t2.e + ) +; + +EVAL $no_pushdown $query; +EVAL $query; +EVAL EXPLAIN $query; +EVAL EXPLAIN FORMAT=JSON $query; + +--echo # conjunctive subformula using BETWEEN : pushing into HAVING +LET $query= +SELECT * FROM t1 +WHERE (t1.c BETWEEN 50 AND 100) AND + (t1.a,t1.c) IN + ( + SELECT t2.e,MAX(t2.g) + FROM t2 + WHERE t2.e<5 + GROUP BY t2.e + ) +; + +EVAL $no_pushdown $query; +EVAL $query; +EVAL EXPLAIN $query; +EVAL EXPLAIN FORMAT=JSON $query; + +--echo # conjunctive subformula using addition : pushing into WHERE +LET $query= +SELECT * FROM t1 +WHERE (t1.a+t1.b > 5) AND + (t1.a,t1.b,t1.c) IN + ( + SELECT t2.e,t2.f,MAX(t2.g) + FROM t2 + WHERE t2.e<5 + GROUP BY t2.e,t2.f + ) +; + +EVAL $no_pushdown $query; +EVAL $query; +EVAL EXPLAIN $query; +EVAL EXPLAIN FORMAT=JSON $query; + +--echo # conjunctive subformula using substitution : pushing into WHERE +LET $query= +SELECT * FROM t1 +WHERE (t1.a-t1.b > 0) AND + (t1.a,t1.b,t1.c) IN + ( + SELECT t2.e,t2.f,MAX(t2.g) + FROM t2 + WHERE t2.e<5 + GROUP BY t2.e,t2.f + ) +; + +EVAL $no_pushdown $query; +EVAL $query; +EVAL EXPLAIN $query; +EVAL EXPLAIN FORMAT=JSON $query; + +--echo # conjunctive subformula using multiplication : pushing into WHERE +LET $query= +SELECT * FROM t1 +WHERE (t1.a*t1.b > 6) AND + (t1.a,t1.b,t1.c) IN + ( + SELECT t2.e,t2.f,MAX(t2.g) + FROM t2 + WHERE t2.e<5 + GROUP BY t2.e,t2.f + ) +; + +EVAL $no_pushdown $query; +EVAL $query; +EVAL EXPLAIN $query; +EVAL EXPLAIN FORMAT=JSON $query; + +--echo # conjunctive subformula using division : pushing into WHERE +LET $query= +SELECT * FROM t1 +WHERE (t1.b/t1.a > 2) AND + (t1.a,t1.b,t1.c) IN + ( + SELECT t2.e,t2.f,MAX(t2.g) + FROM t2 + WHERE t2.e<5 + GROUP BY t2.e,t2.f + ) +; + +EVAL $no_pushdown $query; +EVAL $query; +EVAL EXPLAIN $query; +EVAL EXPLAIN FORMAT=JSON $query; + +--echo # conjunctive subformula using BETWEEN : pushing into WHERE +LET $query= +SELECT * FROM t1 +WHERE (t1.a BETWEEN 1 AND 3) AND + (t1.a,t1.c) IN + ( + SELECT t2.e,MAX(t2.g) + FROM t2 + WHERE t2.e<5 + GROUP BY t2.e + ) +; + +EVAL $no_pushdown $query; +EVAL $query; +EVAL EXPLAIN $query; +EVAL EXPLAIN FORMAT=JSON $query; + +--echo # conjunctive subformula : pushing into HAVING of the IN subquery +--echo # conjunctive subformula : pushing into WHERE of the view from the IN subquery +LET $query= +SELECT * FROM t1 +WHERE t1.c>3 AND + (t1.a,t1.b,t1.c) IN + ( + SELECT v2.e,MAX(v2.f),v2.max_g + FROM v2 + WHERE v2.e<5 + GROUP BY v2.e + ) +; + +EVAL $no_pushdown $query; +EVAL $query; +EVAL EXPLAIN $query; +EVAL EXPLAIN FORMAT=JSON $query; + +--echo # conjunctive subformula : pushing into WHERE of the IN subquery +--echo # conjunctive subformula : pushing into WHERE of the view +--echo # from the IN subquery +LET $query= +SELECT * FROM t1 +WHERE t1.a>1 AND + (t1.a,t1.b,t1.c) IN + ( + SELECT v2.e,MAX(v2.f),v2.max_g + FROM v2 + WHERE v2.e<5 + GROUP BY v2.e + ) +; + +EVAL $no_pushdown $query; +EVAL $query; +EVAL EXPLAIN $query; +EVAL EXPLAIN FORMAT=JSON $query; + +--echo # conjunctive subformula : pushing into WHERE and HAVING +--echo # of the IN subquery +--echo # conjunctive subformula : pushing into WHERE of the view +--echo # from the IN subquery +LET $query= +SELECT * FROM t1 +WHERE t1.a>1 AND t1.c<100 AND + (t1.a,t1.b,t1.c) IN + ( + SELECT v2.e,MAX(v2.f),v2.max_g + FROM v2 + WHERE v2.e<5 + GROUP BY v2.e + ) +; + +EVAL $no_pushdown $query; +EVAL $query; +EVAL EXPLAIN $query; +EVAL EXPLAIN FORMAT=JSON $query; + +--echo # conjunctive subformula : pushing into WHERE of the IN subquery +--echo # extracted AND formula : pushing into HAVING of the derived table +--echo # from the IN subquery +LET $query= +SELECT * FROM t1 +WHERE t1.a>1 AND + (t1.a,t1.b,t1.c) IN + ( + SELECT d_tab.e,MAX(d_tab.f),d_tab.max_g + FROM + ( + SELECT t2.e, t2.f, MAX(t2.g) AS max_g + FROM t2 + GROUP BY t2.f + HAVING max_g>25 + ) as d_tab + WHERE d_tab.e<5 + GROUP BY d_tab.e + ) +; + +EVAL $no_pushdown $query; +EVAL $query; +EVAL EXPLAIN $query; +EVAL EXPLAIN FORMAT=JSON $query; + +--echo # conjunctive subformula : pushing into HAVING of the derived table +--echo # conjunctive subformula : pushing into WHERE of the IN subquery from +--echo # the derived table +SELECT * +FROM t3, +( + SELECT t1.a,t1.b,max(t1.c) as max_c + FROM t1 + WHERE t1.a>1 AND + (t1.a,t1.b,t1.c) IN + ( + SELECT t2.e,t2.f,MAX(t2.g) + FROM t2 + WHERE t2.e<5 + GROUP BY t2.e + ) + GROUP BY t1.a +) AS d_tab +WHERE d_tab.a=t3.x and d_tab.b>2; + +EVAL $no_pushdown $query; +EVAL $query; +EVAL EXPLAIN $query; +EVAL EXPLAIN FORMAT=JSON $query; + +--echo # conjunctive subformula : pushing into WHERE of the derived table +--echo # extracted AND formula : pushing into WHERE of the IN subquery from +--echo # the derived table +SELECT * +FROM t3, +( + SELECT t1.a,t1.b,max(t1.c) as max_c + FROM t1 + WHERE t1.a>1 AND + (t1.a,t1.b,t1.c) IN + ( + SELECT t2.e,t2.f,MAX(t2.g) + FROM t2 + GROUP BY t2.e + HAVING t2.f<5 + ) + GROUP BY t1.a +) AS d_tab +WHERE d_tab.a=t3.x and d_tab.a<5; + +EVAL $no_pushdown $query; +EVAL $query; +EVAL EXPLAIN $query; +EVAL EXPLAIN FORMAT=JSON $query; + +--echo # conjunctive subformula : pushing into WHERE and HAVING +--echo # of the derived table +--echo # extracted AND formula : pushing into WHERE of the IN subquery +--echo # from the derived table +LET $query= +SELECT * +FROM t3, +( + SELECT t1.a,t1.b,max(t1.c) as max_c + FROM t1 + WHERE t1.a>1 AND + (t1.a,t1.b,t1.c) IN + ( + SELECT t2.e,t2.f,MAX(t2.g) + FROM t2 + GROUP BY t2.e + HAVING t2.f<5 + ) + GROUP BY t1.a +) AS d_tab +WHERE d_tab.a=t3.x AND d_tab.a<5 AND d_tab.max_c<70; + +EVAL $no_pushdown $query; +EVAL $query; +EVAL EXPLAIN $query; +EVAL EXPLAIN FORMAT=JSON $query; + +--echo # conjunctive subformula : pushing into WHERE of the derived table +--echo # conjunctive subformula : pushing into HAVING of the IN subquery from +--echo # the derived table +SELECT * +FROM t3, +( + SELECT t1.a,t1.b,max(t1.c) as max_c + FROM t1 + WHERE (t1.a,t1.b,t1.c) IN + ( + SELECT t2.e,t2.f,MAX(t2.g) + FROM t2 + WHERE t2.f<4 + GROUP BY t2.f + ) + GROUP BY t1.a + HAVING t1.b<5 +) AS d_tab +WHERE d_tab.a=t3.x and d_tab.a<5; + +EVAL $no_pushdown $query; +EVAL $query; +EVAL EXPLAIN $query; +EVAL EXPLAIN FORMAT=JSON $query; + +--echo # conjunctive subformula : pushing into WHERE +--echo # using WINDOW FUNCTIONS : using MAX function +LET $query= +SELECT * FROM t1 +WHERE (t1.b>1) AND + (t1.b, t1.c) IN + ( + SELECT t2.f, MAX(t2.g) OVER (PARTITION BY t2.f) + FROM t2 + WHERE t2.e<5 + ) +; + +EVAL $no_pushdown $query; +EVAL $query; +EVAL EXPLAIN $query; +EVAL EXPLAIN FORMAT=JSON $query; + +--echo # conjunctive subformula : pushing into WHERE +--echo # using WINDOW FUNCTIONS : using SUM function +LET $query= +SELECT * FROM t1 +WHERE (t1.b>1) AND + (t1.b, t1.c) IN + ( + SELECT t2.f, CAST(SUM(t2.g) OVER (PARTITION BY t2.f) AS INT) + FROM t2 + WHERE t2.e<5 + ) +; + +EVAL $no_pushdown $query; +EVAL $query; +EVAL EXPLAIN $query; +EVAL EXPLAIN FORMAT=JSON $query; + +DROP TABLE t1,t2,t3; +DROP VIEW v1; diff --git a/sql/item.cc b/sql/item.cc index b36c1518eb8..f5878c502b7 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -7530,6 +7530,222 @@ Item *Item_field::update_value_transformer(THD *thd, uchar *select_arg) } +/** + @brief + Prepare AND/OR formula for extraction of a pushable condition + + @param checker the checker callback function to be applied to the nodes + of the tree of the object + @param arg parameter to be passed to the checker + + @details + This method recursively traverses this AND/OR condition and for each + subformula of the condition it checks whether it can be usable for the + extraction of a pushable condition. The criteria of pushability of + a subformula is checked by the callback function 'checker' with one + parameter arg. The subformulas that are not usable are marked with + the flag NO_EXTRACTION_FL. + @note + This method is called before any call of build_pushable_cond. + The flag NO_EXTRACTION_FL set in a subformula allows to avoid building + clones for the subformulas that are not used in the pushable condition. + @note + This method is called for pushdown conditions into materialized + derived tables/views optimization. + Item::pushable_cond_checker_for_derived() is passed as the actual callback + function. + Also it is called for pushdown conditions in materialized IN subqueries. + Item::pushable_cond_checker_for_subquery is passed as the actual + callback function. +*/ + +void Item::check_pushable_cond(Pushdown_checker checker, uchar *arg) +{ + clear_extraction_flag(); + if (type() == Item::COND_ITEM) + { + bool and_cond= ((Item_cond*) this)->functype() == Item_func::COND_AND_FUNC; + List_iterator<Item> li(*((Item_cond*) this)->argument_list()); + uint count= 0; + Item *item; + while ((item=li++)) + { + item->check_pushable_cond(checker, arg); + if (item->get_extraction_flag() != NO_EXTRACTION_FL) + count++; + else if (!and_cond) + break; + } + if ((and_cond && count == 0) || item) + { + set_extraction_flag(NO_EXTRACTION_FL); + if (and_cond) + li.rewind(); + while ((item= li++)) + item->clear_extraction_flag(); + } + } + else if (!((this->*checker) (arg))) + set_extraction_flag(NO_EXTRACTION_FL); +} + + +/** + @brief + Build condition extractable from this condition for pushdown + + @param thd the thread handle + @param checker the checker callback function to be applied to the + equal items of multiple equality items + @param arg parameter to be passed to the checker + + @details + This method finds out what condition that can be pushed down can be + extracted from this condition. If such condition C exists the + method builds the item for it. The method uses the flag NO_EXTRACTION_FL + set by the preliminary call of the method check_pushable_cond() to figure + out whether a subformula is pushable or not. + In the case when this item is a multiple equality a checker method is + called to find the equal fields to build a new equality that can be + pushed down. + @note + The built condition C is always implied by the condition cond + (cond => C). The method tries to build the most restrictive such + condition (i.e. for any other condition C' such that cond => C' + we have C => C'). + @note + The build item is not ready for usage: substitution for the field items + has to be done and it has to be re-fixed. + @note + This method is called for pushdown conditions into materialized + derived tables/views optimization. + Item::pushable_equality_checker_for_derived() is passed as the actual + callback function. + Also it is called for pushdown conditions into materialized IN subqueries. + Item::pushable_equality_checker_for_subquery() is passed as the actual + callback function. + + @retval + the built condition pushable into if such a condition exists + NULL if there is no such a condition +*/ + +Item *Item::build_pushable_cond(THD *thd, + Pushdown_checker checker, + uchar *arg) +{ + bool is_multiple_equality= type() == Item::FUNC_ITEM && + ((Item_func*) this)->functype() == Item_func::MULT_EQUAL_FUNC; + + if (get_extraction_flag() == NO_EXTRACTION_FL) + return 0; + + if (type() == Item::COND_ITEM) + { + bool cond_and= false; + Item_cond *new_cond; + if (((Item_cond*) this)->functype() == Item_func::COND_AND_FUNC) + { + cond_and= true; + new_cond= new (thd->mem_root) Item_cond_and(thd); + } + else + new_cond= new (thd->mem_root) Item_cond_or(thd); + if (!new_cond) + return 0; + List_iterator<Item> li(*((Item_cond*) this)->argument_list()); + Item *item; + + while ((item=li++)) + { + if (item->get_extraction_flag() == NO_EXTRACTION_FL) + { + if (!cond_and) + return 0; + continue; + } + Item *fix= item->build_pushable_cond(thd, checker, arg); + if (!fix && !cond_and) + return 0; + if (!fix) + continue; + if (new_cond->argument_list()->push_back(fix, thd->mem_root)) + return 0; + } + + switch (new_cond->argument_list()->elements) + { + case 0: + return 0; + case 1: + return new_cond->argument_list()->head(); + default: + return new_cond; + } + } + else if (is_multiple_equality) + { + Item *new_cond= NULL; + int i= 0; + Item_equal *item_equal= (Item_equal *) this; + Item *left_item = item_equal->get_const(); + Item_equal_fields_iterator it(*item_equal); + Item *item; + Item *right_item; + if (!left_item) + { + while ((item=it++)) + { + left_item= ((item->*checker) (arg)) ? item : NULL; + if (left_item) + break; + } + } + if (!left_item) + return 0; + while ((item=it++)) + { + right_item= ((item->*checker) (arg)) ? item : NULL; + if (!right_item) + continue; + Item_func_eq *eq= 0; + Item *left_item_clone= left_item->build_clone(thd); + Item *right_item_clone= item->build_clone(thd); + if (left_item_clone && right_item_clone) + { + left_item_clone->set_item_equal(NULL); + right_item_clone->set_item_equal(NULL); + eq= new (thd->mem_root) Item_func_eq(thd, right_item_clone, + left_item_clone); + } + if (eq) + { + i++; + switch (i) + { + case 1: + new_cond= eq; + break; + case 2: + new_cond= new (thd->mem_root) Item_cond_and(thd, new_cond, eq); + break; + default: + ((Item_cond_and*)new_cond)->argument_list()->push_back(eq, + thd->mem_root); + break; + } + } + } + if (new_cond && new_cond->fix_fields(thd, &new_cond)) + return 0; + return new_cond; + } + else if (get_extraction_flag() != NO_EXTRACTION_FL) + return build_clone(thd); + return 0; +} + + static Item *get_field_item_for_having(THD *thd, Item *item, st_select_lex *sel) { @@ -7649,18 +7865,18 @@ Item *Item_direct_view_ref::derived_field_transformer_for_where(THD *thd, } static -Grouping_tmp_field *find_matching_grouping_field(Item *item, - st_select_lex *sel) +Field_pair *find_matching_grouping_field(Item *item, + st_select_lex *sel) { DBUG_ASSERT(item->type() == Item::FIELD_ITEM || (item->type() == Item::REF_ITEM && ((Item_ref *) item)->ref_type() == Item_ref::VIEW_REF)); - List_iterator<Grouping_tmp_field> li(sel->grouping_tmp_fields); - Grouping_tmp_field *gr_field; + List_iterator<Field_pair> li(sel->grouping_tmp_fields); + Field_pair *gr_field; Item_field *field_item= (Item_field *) (item->real_item()); while ((gr_field= li++)) { - if (field_item->field == gr_field->tmp_field) + if (field_item->field == gr_field->field) return gr_field; } Item_equal *item_equal= item->get_item_equal(); @@ -7674,7 +7890,7 @@ Grouping_tmp_field *find_matching_grouping_field(Item *item, li.rewind(); while ((gr_field= li++)) { - if (field_item->field == gr_field->tmp_field) + if (field_item->field == gr_field->field) return gr_field; } } @@ -7683,26 +7899,25 @@ Grouping_tmp_field *find_matching_grouping_field(Item *item, } -Item *Item_field::derived_grouping_field_transformer_for_where(THD *thd, - uchar *arg) +Item *Item_field::grouping_field_transformer_for_where(THD *thd, uchar *arg) { st_select_lex *sel= (st_select_lex *)arg; - Grouping_tmp_field *gr_field= find_matching_grouping_field(this, sel); + Field_pair *gr_field= find_matching_grouping_field(this, sel); if (gr_field) - return gr_field->producing_item->build_clone(thd); + return gr_field->corresponding_item->build_clone(thd); return this; } Item * -Item_direct_view_ref::derived_grouping_field_transformer_for_where(THD *thd, - uchar *arg) +Item_direct_view_ref::grouping_field_transformer_for_where(THD *thd, + uchar *arg) { if (!item_equal) return this; st_select_lex *sel= (st_select_lex *)arg; - Grouping_tmp_field *gr_field= find_matching_grouping_field(this, sel); - return gr_field->producing_item->build_clone(thd); + Field_pair *gr_field= find_matching_grouping_field(this, sel); + return gr_field->corresponding_item->build_clone(thd); } void Item_field::print(String *str, enum_query_type query_type) diff --git a/sql/item.h b/sql/item.h index 82dfa3f8930..20efe659192 100644 --- a/sql/item.h +++ b/sql/item.h @@ -531,6 +531,7 @@ typedef bool (Item::*Item_processor) (void *arg); typedef bool (Item::*Item_analyzer) (uchar **argp); typedef Item* (Item::*Item_transformer) (THD *thd, uchar *arg); typedef void (*Cond_traverser) (const Item *item, void *arg); +typedef bool (Item::*Pushdown_checker) (uchar *arg); struct st_cond_statistic; @@ -563,6 +564,7 @@ public: String_copier_for_item(THD *thd): m_thd(thd) { } }; + class Item: public Value_source, public Type_all_attributes { @@ -1603,7 +1605,15 @@ public: or can be converted to such an exression using equalities. Not to be used for AND/OR formulas. */ - virtual bool excl_dep_on_grouping_fields(st_select_lex *sel) { return false; } + virtual bool excl_dep_on_grouping_fields(st_select_lex *sel) + { return false; } + /* + TRUE if the expression depends only on fields from the left part of + IN subquery or can be converted to such an expression using equalities. + Not to be used for AND/OR formulas. + */ + virtual bool excl_dep_on_in_subq_left_part(Item_in_subselect *subq_pred) + { return false; } virtual bool switch_to_nullable_fields_processor(void *arg) { return 0; } virtual bool find_function_processor (void *arg) { return 0; } @@ -1776,8 +1786,12 @@ public: { return this; } virtual Item *derived_field_transformer_for_where(THD *thd, uchar *arg) { return this; } - virtual Item *derived_grouping_field_transformer_for_where(THD *thd, - uchar *arg) + virtual Item *grouping_field_transformer_for_where(THD *thd, uchar *arg) + { return this; } + /* Now is not used. */ + virtual Item *in_subq_field_transformer_for_where(THD *thd, uchar *arg) + { return this; } + virtual Item *in_subq_field_transformer_for_having(THD *thd, uchar *arg) { return this; } virtual Item *in_predicate_to_in_subs_transformer(THD *thd, uchar *arg) { return this; } @@ -1960,6 +1974,33 @@ public: { marker &= ~EXTRACTION_MASK; } + void check_pushable_cond(Pushdown_checker excl_dep_func, uchar *arg); + bool pushable_cond_checker_for_derived(uchar *arg) + { + return excl_dep_on_table(*((table_map *)arg)); + } + bool pushable_cond_checker_for_subquery(uchar *arg) + { + return excl_dep_on_in_subq_left_part((Item_in_subselect *)arg); + } + Item *get_corresponding_field_in_insubq(Item_in_subselect *subq_pred); + Item *build_pushable_cond(THD *thd, + Pushdown_checker checker, + uchar *arg); + /* + Checks if this item depends only on the arg table + */ + bool pushable_equality_checker_for_derived(uchar *arg) + { + return (used_tables() == *((table_map *)arg)); + } + /* + Checks if this item consists in the left part of arg IN subquery predicate + */ + bool pushable_equality_checker_for_subquery(uchar *arg) + { + return get_corresponding_field_in_insubq((Item_in_subselect *)arg); + } }; MEM_ROOT *get_thd_memroot(THD *thd); @@ -2088,6 +2129,17 @@ protected: } return true; } + bool excl_dep_on_in_subq_left_part(Item_in_subselect *subq_pred) + { + for (uint i= 0; i < arg_count; i++) + { + if (args[i]->const_item()) + continue; + if (!args[i]->excl_dep_on_in_subq_left_part(subq_pred)) + return false; + } + return true; + } public: Item_args(void) :args(NULL), arg_count(0) @@ -2933,10 +2985,13 @@ public: virtual Item *update_value_transformer(THD *thd, uchar *select_arg); Item *derived_field_transformer_for_having(THD *thd, uchar *arg); Item *derived_field_transformer_for_where(THD *thd, uchar *arg); - Item *derived_grouping_field_transformer_for_where(THD *thd, uchar *arg); + Item *grouping_field_transformer_for_where(THD *thd, uchar *arg); + Item *in_subq_field_transformer_for_where(THD *thd, uchar *arg); + Item *in_subq_field_transformer_for_having(THD *thd, uchar *arg); virtual void print(String *str, enum_query_type query_type); bool excl_dep_on_table(table_map tab_map); bool excl_dep_on_grouping_fields(st_select_lex *sel); + bool excl_dep_on_in_subq_left_part(Item_in_subselect *subq_pred); bool cleanup_excluding_fields_processor(void *arg) { return field ? 0 : cleanup_processor(arg); } bool cleanup_excluding_const_fields_processor(void *arg) @@ -4744,6 +4799,8 @@ public: } bool excl_dep_on_grouping_fields(st_select_lex *sel) { return (*ref)->excl_dep_on_grouping_fields(sel); } + bool excl_dep_on_in_subq_left_part(Item_in_subselect *subq_pred) + { return (*ref)->excl_dep_on_in_subq_left_part(subq_pred); } bool cleanup_excluding_fields_processor(void *arg) { Item *item= real_item(); @@ -5058,10 +5115,12 @@ public: } bool excl_dep_on_table(table_map tab_map); bool excl_dep_on_grouping_fields(st_select_lex *sel); + bool excl_dep_on_in_subq_left_part(Item_in_subselect *subq_pred); Item *derived_field_transformer_for_having(THD *thd, uchar *arg); Item *derived_field_transformer_for_where(THD *thd, uchar *arg); - Item *derived_grouping_field_transformer_for_where(THD *thd, - uchar *arg); + Item *grouping_field_transformer_for_where(THD *thd, uchar *arg); + Item *in_subq_field_transformer_for_where(THD *thd, uchar *arg); + Item *in_subq_field_transformer_for_having(THD *thd, uchar *arg); void save_val(Field *to) { @@ -5967,7 +6026,11 @@ public: { return convert_to_basic_const_item(thd); } Item *derived_field_transformer_for_where(THD *thd, uchar *arg) { return convert_to_basic_const_item(thd); } - Item *derived_grouping_field_transformer_for_where(THD *thd, uchar *arg) + Item *grouping_field_transformer_for_where(THD *thd, uchar *arg) + { return convert_to_basic_const_item(thd); } + Item *in_subq_field_transformer_for_where(THD *thd, uchar *arg) + { return convert_to_basic_const_item(thd); } + Item *in_subq_field_transformer_for_having(THD *thd, uchar *arg) { return convert_to_basic_const_item(thd); } }; diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 8b47f09497f..38f169809dd 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -1260,7 +1260,11 @@ public: { reset_first_arg_if_needed(); return this; } Item *derived_field_transformer_for_where(THD *thd, uchar *arg) { reset_first_arg_if_needed(); return this; } - Item *derived_grouping_field_transformer_for_where(THD *thd, uchar *arg) + Item *grouping_field_transformer_for_where(THD *thd, uchar *arg) + { reset_first_arg_if_needed(); return this; } + Item *in_subq_field_transformer_for_where(THD *thd, uchar *arg) + { reset_first_arg_if_needed(); return this; } + Item *in_subq_field_transformer_for_having(THD *thd, uchar *arg) { reset_first_arg_if_needed(); return this; } }; @@ -3129,6 +3133,8 @@ public: { return used_tables() & tab_map; } + bool excl_dep_on_in_subq_left_part(Item_in_subselect *subq_pred); + friend class Item_equal_fields_iterator; bool count_sargable_conds(void *arg); friend class Item_equal_iterator<List_iterator_fast,Item>; diff --git a/sql/item_func.h b/sql/item_func.h index 1f942ab1b55..da1b73dca5a 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -330,6 +330,11 @@ public: return Item_args::excl_dep_on_grouping_fields(sel); } + bool excl_dep_on_in_subq_left_part(Item_in_subselect *subq_pred) + { + return Item_args::excl_dep_on_in_subq_left_part(subq_pred); + } + /* We assume the result of any function that has a TIMESTAMP argument to be timezone-dependent, since a TIMESTAMP value in both numeric and string diff --git a/sql/item_row.h b/sql/item_row.h index 064c1f267b4..97accd96d81 100644 --- a/sql/item_row.h +++ b/sql/item_row.h @@ -129,6 +129,11 @@ public: return Item_args::excl_dep_on_grouping_fields(sel); } + bool excl_dep_on_in_subq_left_part(Item_in_subselect *subq_pred) + { + return Item_args::excl_dep_on_in_subq_left_part(subq_pred); + } + bool check_vcol_func_processor(void *arg) {return FALSE; } Item *get_copy(THD *thd) { return get_item_copy<Item_row>(thd, this); } diff --git a/sql/item_subselect.h b/sql/item_subselect.h index 55c9d759ddf..3ab1d004ba7 100644 --- a/sql/item_subselect.h +++ b/sql/item_subselect.h @@ -33,6 +33,7 @@ class subselect_hash_sj_engine; class Item_bool_func2; class Comp_creator; class With_element; +class Field_pair; typedef class st_select_lex SELECT_LEX; @@ -568,6 +569,8 @@ public: */ bool is_registered_semijoin; + List<Field_pair> corresponding_fields; + /* Used to determine how this subselect item is represented in the item tree, in case there is a need to locate it there and replace with something else. @@ -739,6 +742,8 @@ public: return 0; }; + bool pushdown_cond_for_in_subquery(THD *thd, Item *cond); + friend class Item_ref_null_helper; friend class Item_is_not_null_test; friend class Item_in_optimizer; @@ -850,7 +855,6 @@ protected: void set_row(List<Item> &item_list, Item_cache **row); }; - class subselect_single_select_engine: public subselect_engine { bool prepared; /* simple subselect is prepared */ @@ -884,9 +888,10 @@ public: friend class subselect_hash_sj_engine; friend class Item_in_subselect; - friend bool setup_jtbm_semi_joins(JOIN *join, List<TABLE_LIST> *join_list, - Item **join_where); - + friend bool execute_degenerate_jtbm_semi_join(THD *thd, + TABLE_LIST *tbl, + Item_in_subselect *subq_pred, + List<Item> &eq_list); }; diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc index eff28d0c27d..da9159d4205 100644 --- a/sql/opt_subselect.cc +++ b/sql/opt_subselect.cc @@ -5430,31 +5430,453 @@ int select_value_catcher::send_data(List<Item> &items) } -/* - Setup JTBM join tabs for execution +/** + @brief + Conjugate conditions after optimize_cond() call + + @param thd the thread handle + @param cond the condition where to attach new conditions + @param cond_eq IN/OUT the multiple equalities of cond + @param new_conds IN/OUT the list of conditions needed to add + @param cond_value the returned value of the condition + + @details + The method creates new condition through conjunction of cond and + the conditions from new_conds list. + The method is called after optimize_cond() for cond. The result + of the conjunction should be the same as if it was done before the + the optimize_cond() call. + + @retval NULL if an error occurs + @retval otherwise the created condition +*/ + +Item *and_new_conditions_to_optimized_cond(THD *thd, Item *cond, + COND_EQUAL **cond_eq, + List<Item> &new_conds, + Item::cond_result *cond_value) +{ + COND_EQUAL new_cond_equal; + Item *item; + Item_equal *equality; + bool is_simplified_cond= false; + List_iterator<Item> li(new_conds); + List_iterator_fast<Item_equal> it(new_cond_equal.current_level); + + /* + Creates multiple equalities new_cond_equal from new_conds list + equalities. If multiple equality can't be created or the condition + from new_conds list isn't an equality the method leaves it in new_conds + list. + + The equality can't be converted into the multiple equality if it + is a knowingly false or true equality. + For example, (3 = 1) equality. + */ + while ((item=li++)) + { + if (item->type() == Item::FUNC_ITEM && + ((Item_func *) item)->functype() == Item_func::EQ_FUNC && + check_simple_equality(thd, + Item::Context(Item::ANY_SUBST, + ((Item_func_equal *)item)->compare_type_handler(), + ((Item_func_equal *)item)->compare_collation()), + ((Item_func *)item)->arguments()[0]->real_item(), + ((Item_func *)item)->arguments()[1]->real_item(), + &new_cond_equal)) + li.remove(); + } + + it.rewind(); + if (cond && cond->type() == Item::COND_ITEM && + ((Item_cond*) cond)->functype() == Item_func::COND_AND_FUNC) + { + /* + cond is an AND-condition. + The method conjugates the AND-condition cond, created multiple + equalities new_cond_equal and remain conditions from new_conds. + + First, the method disjoins multiple equalities of cond and + merges new_cond_equal multiple equalities with these equalities. + It checks if after the merge the multiple equalities are knowingly + true or false equalities. + It attaches to cond the conditions from new_conds list and the result + of the merge of multiple equalities. The multiple equalities are + attached only to the upper level of AND-condition cond. So they + should be pushed down to the inner levels of cond AND-condition + if needed. It is done by propagate_new_equalities(). + */ + COND_EQUAL *cond_equal= &((Item_cond_and *) cond)->m_cond_equal; + List<Item_equal> *cond_equalities= &cond_equal->current_level; + List<Item> *and_args= ((Item_cond_and *)cond)->argument_list(); + and_args->disjoin((List<Item> *) cond_equalities); + and_args->append(&new_conds); + + while ((equality= it++)) + { + equality->upper_levels= 0; + equality->merge_into_list(thd, cond_equalities, false, false); + } + List_iterator_fast<Item_equal> ei(*cond_equalities); + while ((equality= ei++)) + { + if (equality->const_item() && !equality->val_int()) + is_simplified_cond= true; + equality->fixed= 0; + if (equality->fix_fields(thd, NULL)) + return NULL; + } + + and_args->append((List<Item> *) cond_equalities); + *cond_eq= &((Item_cond_and *) cond)->m_cond_equal; + + propagate_new_equalities(thd, cond, cond_equalities, + cond_equal->upper_levels, + &is_simplified_cond); + cond= cond->propagate_equal_fields(thd, + Item::Context_boolean(), + cond_equal); + } + else + { + /* + cond isn't AND-condition or is NULL. + There can be several cases: + + 1. cond is a multiple equality. + In this case cond is merged with the multiple equalities of + new_cond_equal. + The new condition is created with the conjunction of new_conds + list conditions and the result of merge of multiple equalities. + 2. cond is NULL + The new condition is created from the conditions of new_conds + list and multiple equalities from new_cond_equal. + 3. Otherwise + In this case the new condition is created from cond, remain conditions + from new_conds list and created multiple equalities from + new_cond_equal. + */ + List<Item> new_conds_list; + /* Flag is set to true if cond is a multiple equality */ + bool is_mult_eq= (cond && cond->type() == Item::FUNC_ITEM && + ((Item_func*) cond)->functype() == Item_func::MULT_EQUAL_FUNC); + + if (cond && !is_mult_eq && + new_conds_list.push_back(cond, thd->mem_root)) + return NULL; + + if (new_conds.elements > 0) + { + li.rewind(); + while ((item=li++)) + { + if (!item->fixed && item->fix_fields(thd, NULL)) + return NULL; + if (item->const_item() && !item->val_int()) + is_simplified_cond= true; + } + + if (new_conds.elements > 1) + new_conds_list.append(&new_conds); + else + { + li.rewind(); + item= li++; + if (new_conds_list.push_back(item, thd->mem_root)) + return NULL; + } + } + + if (new_cond_equal.current_level.elements > 0) + { + if (is_mult_eq) + { + Item_equal *eq_cond= (Item_equal *)cond; + eq_cond->upper_levels= 0; + eq_cond->merge_into_list(thd, &new_cond_equal.current_level, + false, false); + + while ((equality= it++)) + { + if (equality->const_item() && !equality->val_int()) + is_simplified_cond= true; + } + + if (new_cond_equal.current_level.elements + + new_conds_list.elements == 1) + { + it.rewind(); + equality= it++; + equality->fixed= 0; + if (equality->fix_fields(thd, NULL)) + return NULL; + } + *cond_eq= &new_cond_equal; + } + new_conds_list.append((List<Item> *)&new_cond_equal.current_level); + } + + if (new_conds_list.elements > 1) + { + Item_cond_and *and_cond= + new (thd->mem_root) Item_cond_and(thd, new_conds_list); + + and_cond->m_cond_equal.copy(new_cond_equal); + cond= (Item *)and_cond; + *cond_eq= &((Item_cond_and *)cond)->m_cond_equal; + } + else + { + List_iterator_fast<Item> iter(new_conds_list); + cond= iter++; + } + + if (!cond->fixed && cond->fix_fields(thd, NULL)) + return NULL; + + if (new_cond_equal.current_level.elements > 0) + cond= cond->propagate_equal_fields(thd, + Item::Context_boolean(), + &new_cond_equal); + } + + /* + If it was found that some of the created condition parts are knowingly + true or false equalities the method calls removes_eq_cond() to remove them + from cond and set the cond_value to the appropriate value. + */ + if (is_simplified_cond) + cond= cond->remove_eq_conds(thd, cond_value, true); + return cond; +} + + +/** + @brief Materialize a degenerate jtbm semi join + + @param thd thread handler + @param tbl table list for the target jtbm semi join table + @param subq_pred IN subquery predicate with the degenerate jtbm semi join + @param eq_list IN/OUT the list where to add produced equalities + + @details + The method materializes the degenerate jtbm semi join for the + subquery from the IN subquery predicate subq_pred taking table + as the target for materialization. + Any degenerate table is guaranteed to produce 0 or 1 record. + Examples of both cases: + + select * from ot where col in (select ... from it where 2>3) + select * from ot where col in (select MY_MIN(it.key) from it) + + in this case, there is no necessity to create a temp.table for + materialization. + We now just need to + 1. Check whether 1 or 0 records are produced, setup this as a + constant join tab. + 2. Create a dummy temporary table, because all of the join + optimization code relies on TABLE object being present. + + In the case when materialization produces one row the function + additionally creates equalities between the expressions from the + left part of the IN subquery predicate and the corresponding + columns of the produced row. These equalities are added to the + list eq_list. They are supposed to be conjuncted with the condition + of the WHERE clause. + + @retval TRUE if an error occurs + @retval FALSE otherwise +*/ + +bool execute_degenerate_jtbm_semi_join(THD *thd, + TABLE_LIST *tbl, + Item_in_subselect *subq_pred, + List<Item> &eq_list) +{ + DBUG_ENTER("execute_degenerate_jtbm_semi_join"); + select_value_catcher *new_sink; + + DBUG_ASSERT(subq_pred->engine->engine_type() == + subselect_engine::SINGLE_SELECT_ENGINE); + subselect_single_select_engine *engine= + (subselect_single_select_engine*)subq_pred->engine; + if (!(new_sink= new (thd->mem_root) select_value_catcher(thd, subq_pred))) + DBUG_RETURN(TRUE); + if (new_sink->setup(&engine->select_lex->join->fields_list) || + engine->select_lex->join->change_result(new_sink, NULL) || + engine->exec()) + { + DBUG_RETURN(TRUE); + } + subq_pred->is_jtbm_const_tab= TRUE; + + if (new_sink->assigned) + { + /* + Subselect produced one row, which is saved in new_sink->row. + Save "left_expr[i] == row[i]" equalities into the eq_list. + */ + subq_pred->jtbm_const_row_found= TRUE; + + Item *eq_cond; + for (uint i= 0; i < subq_pred->left_expr->cols(); i++) + { + eq_cond= + new (thd->mem_root) Item_func_eq(thd, + subq_pred->left_expr->element_index(i), + new_sink->row[i]); + if (!eq_cond || eq_list.push_back(eq_cond, thd->mem_root)) + DBUG_RETURN(TRUE); + } + } + else + { + /* Subselect produced no rows. Just set the flag */ + subq_pred->jtbm_const_row_found= FALSE; + } + + TABLE *dummy_table; + if (!(dummy_table= create_dummy_tmp_table(thd))) + DBUG_RETURN(TRUE); + tbl->table= dummy_table; + tbl->table->pos_in_table_list= tbl; + /* + Note: the table created above may be freed by: + 1. JOIN_TAB::cleanup(), when the parent join is a regular join. + 2. cleanup_empty_jtbm_semi_joins(), when the parent join is a + degenerate join (e.g. one with "Impossible where"). + */ + setup_table_map(tbl->table, tbl, tbl->jtbm_table_no); + DBUG_RETURN(FALSE); +} + + +/** + @brief + Execute degenerate jtbm semi joins before optimize_cond() for parent + + @param join the parent join for jtbm semi joins + @param join_list the list of tables where jtbm semi joins are processed + @param eq_list IN/OUT the list where to add equalities produced after + materialization of single-row degenerate jtbm semi joins + + @details + The method traverses join_list trying to find any degenerate jtbm semi + joins for subqueries of IN predicates. For each degenerate jtbm + semi join execute_degenerate_jtbm_semi_join() is called. As a result + of this call new equalities that substitute for single-row materialized + jtbm semi join are added to eq_list. + + In the case when a table is nested in another table 'nested_join' the + method is recursively called for the join_list of the 'nested_join' trying + to find in the list any degenerate jtbm semi joins. Currently a jtbm semi + join may occur in a mergeable semi join nest. + + @retval TRUE if an error occurs + @retval FALSE otherwise */ -bool setup_jtbm_semi_joins(JOIN *join, List<TABLE_LIST> *join_list, - Item **join_where) +bool setup_degenerate_jtbm_semi_joins(JOIN *join, + List<TABLE_LIST> *join_list, + List<Item> &eq_list) +{ + TABLE_LIST *table; + NESTED_JOIN *nested_join; + List_iterator<TABLE_LIST> li(*join_list); + THD *thd= join->thd; + DBUG_ENTER("setup_degenerate_jtbm_semi_joins"); + + while ((table= li++)) + { + Item_in_subselect *subq_pred; + + if ((subq_pred= table->jtbm_subselect)) + { + JOIN *subq_join= subq_pred->unit->first_select()->join; + + if (!subq_join->tables_list || !subq_join->table_count) + { + if (execute_degenerate_jtbm_semi_join(thd, + table, + subq_pred, + eq_list)) + DBUG_RETURN(TRUE); + join->is_orig_degenerated= true; + } + } + if ((nested_join= table->nested_join)) + { + if (setup_degenerate_jtbm_semi_joins(join, + &nested_join->join_list, + eq_list)) + DBUG_RETURN(TRUE); + } + } + DBUG_RETURN(FALSE); +} + + +/** + @brief + Optimize jtbm semi joins for materialization + + @param join the parent join for jtbm semi joins + @param join_list the list of TABLE_LIST objects where jtbm semi join + can occur + @param eq_list IN/OUT the list where to add produced equalities + + @details + This method is called by the optimizer after the call of + optimize_cond() for parent select. + The method traverses join_list trying to find any jtbm semi joins for + subqueries from IN predicates and optimizes them. + After the optimization some of jtbm semi joins may become degenerate. + For example the subquery 'SELECT MAX(b) FROM t2' from the query + + SELECT * FROM t1 WHERE 4 IN (SELECT MAX(b) FROM t2); + + will become degenerate if there is an index on t2.b. + If a subquery becomes degenerate it is handled by the function + execute_degenerate_jtbm_semi_join(). + + Otherwise the method creates a temporary table in which the subquery + of the jtbm semi join will be materialied. + + The function saves the equalities between all pairs of the expressions + from the left part of the IN subquery predicate and the corresponding + columns of the subquery from the predicate in eq_list appending them + to the list. The equalities of eq_list will be later conjucted with the + condition of the WHERE clause. + + In the case when a table is nested in another table 'nested_join' the + method is recursively called for the join_list of the 'nested_join' trying + to find in the list any degenerate jtbm semi joins. Currently a jtbm semi + join may occur in a mergeable semi join nest. + + @retval TRUE if an error occurs + @retval FALSE otherwise +*/ + +bool setup_jtbm_semi_joins(JOIN *join, List<TABLE_LIST> *join_list, + List<Item> &eq_list) { TABLE_LIST *table; NESTED_JOIN *nested_join; List_iterator<TABLE_LIST> li(*join_list); THD *thd= join->thd; DBUG_ENTER("setup_jtbm_semi_joins"); - + while ((table= li++)) { - Item_in_subselect *item; + Item_in_subselect *subq_pred; - if ((item= table->jtbm_subselect)) + if ((subq_pred= table->jtbm_subselect)) { - Item_in_subselect *subq_pred= item; double rows; double read_time; /* - Perform optimization of the subquery, so that we know estmated + Perform optimization of the subquery, so that we know estimated - cost of materialization process - how many records will be in the materialized temp.table */ @@ -5467,103 +5889,36 @@ bool setup_jtbm_semi_joins(JOIN *join, List<TABLE_LIST> *join_list, if (!subq_join->tables_list || !subq_join->table_count) { - /* - A special case; subquery's join is degenerate, and it either produces - 0 or 1 record. Examples of both cases: - - select * from ot where col in (select ... from it where 2>3) - select * from ot where col in (select MY_MIN(it.key) from it) - - in this case, the subquery predicate has not been setup for - materialization. In particular, there is no materialized temp.table. - We'll now need to - 1. Check whether 1 or 0 records are produced, setup this as a - constant join tab. - 2. Create a dummy temporary table, because all of the join - optimization code relies on TABLE object being present (here we - follow a bad tradition started by derived tables) - */ - DBUG_ASSERT(subq_pred->engine->engine_type() == - subselect_engine::SINGLE_SELECT_ENGINE); - subselect_single_select_engine *engine= - (subselect_single_select_engine*)subq_pred->engine; - select_value_catcher *new_sink; - if (!(new_sink= - new (thd->mem_root) select_value_catcher(thd, subq_pred))) - DBUG_RETURN(TRUE); - if (new_sink->setup(&engine->select_lex->join->fields_list) || - engine->select_lex->join->change_result(new_sink, NULL) || - engine->exec()) - { + if (!join->is_orig_degenerated && + execute_degenerate_jtbm_semi_join(thd, table, subq_pred, + eq_list)) DBUG_RETURN(TRUE); - } - subq_pred->is_jtbm_const_tab= TRUE; - - if (new_sink->assigned) - { - subq_pred->jtbm_const_row_found= TRUE; - /* - Subselect produced one row, which is saved in new_sink->row. - Inject "left_expr[i] == row[i] equalities into parent's WHERE. - */ - Item *eq_cond; - for (uint i= 0; i < subq_pred->left_expr->cols(); i++) - { - eq_cond= new (thd->mem_root) - Item_func_eq(thd, subq_pred->left_expr->element_index(i), - new_sink->row[i]); - if (!eq_cond) - DBUG_RETURN(1); - - if (!((*join_where)= and_items(thd, *join_where, eq_cond)) || - (*join_where)->fix_fields(thd, join_where)) - DBUG_RETURN(1); - } - } - else - { - /* Subselect produced no rows. Just set the flag, */ - subq_pred->jtbm_const_row_found= FALSE; - } - - /* Set up a dummy TABLE*, optimizer code needs JOIN_TABs to have TABLE */ - TABLE *dummy_table; - if (!(dummy_table= create_dummy_tmp_table(thd))) - DBUG_RETURN(1); - table->table= dummy_table; - table->table->pos_in_table_list= table; - /* - Note: the table created above may be freed by: - 1. JOIN_TAB::cleanup(), when the parent join is a regular join. - 2. cleanup_empty_jtbm_semi_joins(), when the parent join is a - degenerate join (e.g. one with "Impossible where"). - */ - setup_table_map(table->table, table, table->jtbm_table_no); } else { DBUG_ASSERT(subq_pred->test_set_strategy(SUBS_MATERIALIZATION)); subq_pred->is_jtbm_const_tab= FALSE; subselect_hash_sj_engine *hash_sj_engine= - ((subselect_hash_sj_engine*)item->engine); + ((subselect_hash_sj_engine*)subq_pred->engine); table->table= hash_sj_engine->tmp_table; table->table->pos_in_table_list= table; setup_table_map(table->table, table, table->jtbm_table_no); - Item *sj_conds= hash_sj_engine->semi_join_conds; - - (*join_where)= and_items(thd, *join_where, sj_conds); - if (!(*join_where)->fixed) - (*join_where)->fix_fields(thd, join_where); + List_iterator<Item> li(*hash_sj_engine->semi_join_conds->argument_list()); + Item *item; + while ((item=li++)) + { + if (eq_list.push_back(item, thd->mem_root)) + DBUG_RETURN(TRUE); + } } table->table->maybe_null= MY_TEST(join->mixed_implicit_grouping); } - if ((nested_join= table->nested_join)) { - if (setup_jtbm_semi_joins(join, &nested_join->join_list, join_where)) + if (setup_jtbm_semi_joins(join, &nested_join->join_list, eq_list)) DBUG_RETURN(TRUE); } } @@ -5957,3 +6312,418 @@ bool JOIN::choose_tableless_subquery_plan() } return FALSE; } + + +/* + Check if the item exists in the fields list of the left part of + the IN subquery predicate subq_pred and returns its corresponding + item from the select of the right part of subq_pred. +*/ +Item *Item::get_corresponding_field_in_insubq(Item_in_subselect *subq_pred) +{ + DBUG_ASSERT(type() == Item::FIELD_ITEM || + (type() == Item::REF_ITEM && + ((Item_ref *) this)->ref_type() == Item_ref::VIEW_REF)); + + List_iterator<Field_pair> it(subq_pred->corresponding_fields); + Field_pair *ret; + Item_field *field_item= (Item_field *) (real_item()); + while ((ret= it++)) + { + if (field_item->field == ret->field) + return ret->corresponding_item; + } + return NULL; +} + + +bool Item_field::excl_dep_on_in_subq_left_part(Item_in_subselect *subq_pred) +{ + if (((Item *)this)->get_corresponding_field_in_insubq(subq_pred)) + return true; + if (item_equal) + { + Item_equal_fields_iterator it(*item_equal); + Item *equal_item; + while ((equal_item= it++)) + { + if (equal_item->const_item()) + continue; + if (equal_item->get_corresponding_field_in_insubq(subq_pred)) + return true; + } + } + return false; +} + + +bool Item_direct_view_ref::excl_dep_on_in_subq_left_part(Item_in_subselect *subq_pred) +{ + if (item_equal) + { + DBUG_ASSERT(real_item()->type() == Item::FIELD_ITEM); + if (((Item *)this)->get_corresponding_field_in_insubq(subq_pred)) + return true; + } + return (*ref)->excl_dep_on_in_subq_left_part(subq_pred); +} + + +bool Item_equal::excl_dep_on_in_subq_left_part(Item_in_subselect *subq_pred) +{ + Item *left_item = get_const(); + Item_equal_fields_iterator it(*this); + Item *item; + if (!left_item) + { + while ((item=it++)) + { + if (item->excl_dep_on_in_subq_left_part(subq_pred)) + { + left_item= item; + break; + } + } + } + if (!left_item) + return false; + while ((item=it++)) + { + if (item->excl_dep_on_in_subq_left_part(subq_pred)) + return true; + } + return false; +} + + +/** + @brief + Get corresponding item from the select of the right part of IN subquery + + @param thd the thread handle + @param item the item from the left part of subq_pred for which + corresponding item should be found + @param subq_pred the IN subquery predicate + + @details + This method looks through the fields of the select of the right part of + the IN subquery predicate subq_pred trying to find the corresponding + item 'new_item' for item. If item has equal items it looks through + the fields of the select of the right part of subq_pred for each equal + item trying to find the corresponding item. + The method assumes that the given item is either a field item or + a reference to a field item. + + @retval <item*> reference to the corresponding item + @retval NULL if item was not found +*/ + +static +Item *get_corresponding_item(THD *thd, Item *item, + Item_in_subselect *subq_pred) +{ + DBUG_ASSERT(item->type() == Item::FIELD_ITEM || + (item->type() == Item::REF_ITEM && + ((Item_ref *) item)->ref_type() == Item_ref::VIEW_REF)); + + Item *corresonding_item; + Item_equal *item_equal= item->get_item_equal(); + + if (item_equal) + { + Item_equal_fields_iterator it(*item_equal); + Item *equal_item; + while ((equal_item= it++)) + { + corresonding_item= + equal_item->get_corresponding_field_in_insubq(subq_pred); + if (corresonding_item) + return corresonding_item; + } + return NULL; + } + else + return item->get_corresponding_field_in_insubq(subq_pred); +} + + +Item *Item_field::in_subq_field_transformer_for_where(THD *thd, uchar *arg) +{ + Item_in_subselect *subq_pred= (Item_in_subselect *)arg; + Item *producing_item= get_corresponding_item(thd, this, subq_pred); + if (producing_item) + return producing_item->build_clone(thd); + return this; +} + + +Item *Item_direct_view_ref::in_subq_field_transformer_for_where(THD *thd, + uchar *arg) +{ + if (item_equal) + { + Item_in_subselect *subq_pred= (Item_in_subselect *)arg; + Item *producing_item= get_corresponding_item(thd, this, subq_pred); + DBUG_ASSERT (producing_item != NULL); + return producing_item->build_clone(thd); + } + return this; +} + + +/** + @brief + Transforms item so it can be pushed into the IN subquery HAVING clause + + @param thd the thread handle + @param in_item the item for which pushable item should be created + @param subq_pred the IN subquery predicate + + @details + This method finds for in_item that is a field from the left part of the + IN subquery predicate subq_pred its corresponding item from the right part + of subq_pred. + If corresponding item is found, a shell for this item is created. + This shell can be pushed into the HAVING part of subq_pred select. + + @retval <item*> reference to the created corresponding item shell for in_item + @retval NULL if mistake occurs +*/ + +static Item* +get_corresponding_item_for_in_subq_having(THD *thd, Item *in_item, + Item_in_subselect *subq_pred) +{ + Item *new_item= get_corresponding_item(thd, in_item, subq_pred); + + if (new_item) + { + Item_ref *ref= + new (thd->mem_root) Item_ref(thd, + &subq_pred->unit->first_select()->context, + NullS, NullS, + &new_item->name); + if (!ref) + DBUG_ASSERT(0); + return ref; + } + return new_item; +} + + +Item *Item_field::in_subq_field_transformer_for_having(THD *thd, uchar *arg) +{ + return get_corresponding_item_for_in_subq_having(thd, this, + (Item_in_subselect *)arg); +} + + +Item *Item_direct_view_ref::in_subq_field_transformer_for_having(THD *thd, + uchar *arg) +{ + if (!item_equal) + return this; + else + { + Item *new_item= get_corresponding_item_for_in_subq_having(thd, this, + (Item_in_subselect *)arg); + if (!new_item) + return this; + return new_item; + } +} + + +/** + @brief + Find fields that are used in the GROUP BY of the select + + @param thd the thread handle + @param sel the select of the IN subquery predicate + @param fields fields of the left part of the IN subquery predicate + @param grouping_list GROUP BY clause + + @details + This method traverses fields which are used in the GROUP BY of + sel and saves them with their corresponding items from fields. +*/ + +bool grouping_fields_in_the_in_subq_left_part(THD *thd, + st_select_lex *sel, + List<Field_pair> *fields, + ORDER *grouping_list) +{ + DBUG_ENTER("grouping_fields_in_the_in_subq_left_part"); + sel->grouping_tmp_fields.empty(); + List_iterator<Field_pair> it(*fields); + Field_pair *item; + while ((item= it++)) + { + for (ORDER *ord= grouping_list; ord; ord= ord->next) + { + if ((*ord->item)->eq(item->corresponding_item, 0)) + { + if (sel->grouping_tmp_fields.push_back(item, thd->mem_root)) + DBUG_RETURN(TRUE); + } + } + } + DBUG_RETURN(FALSE); +} + + +/** + @brief + Extract condition that can be pushed into select of this IN subquery + + @param thd the thread handle + @param cond current condition + + @details + This function builds the most restrictive condition depending only on + the list of fields of the left part of this IN subquery predicate + (directly or indirectly through equality) that can be extracted from the + given condition cond and pushes it into this IN subquery. + + Example of the transformation: + + SELECT * FROM t1 + WHERE a>3 AND b>10 AND + (a,b) IN (SELECT x,MAX(y) FROM t2 GROUP BY x); + + => + + SELECT * FROM t1 + WHERE a>3 AND b>10 AND + (a,b) IN (SELECT x,max(y) + FROM t2 + WHERE x>3 + GROUP BY x + HAVING MAX(y)>10); + + + In details: + 1. Check what pushable formula can be extracted from cond + 2. Build a clone PC of the formula that can be extracted + (the clone is built only if the extracted formula is a AND subformula + of cond or conjunction of such subformulas) + 3. If there is no HAVING clause prepare PC to be conjuncted with + WHERE clause of this subquery. Otherwise do 4-7. + 4. Check what formula PC_where can be extracted from PC to be pushed + into the WHERE clause of the subquery + 5. Build PC_where and if PC_where is a conjunct(s) of PC remove it from PC + getting PC_having + 6. Prepare PC_where to be conjuncted with the WHERE clause of + the IN subquery + 7. Prepare PC_having to be conjuncted with the HAVING clause of + the IN subquery + + @note + This method is similar to pushdown_cond_for_derived() + + @retval TRUE if an error occurs + @retval FALSE otherwise +*/ + +bool Item_in_subselect::pushdown_cond_for_in_subquery(THD *thd, Item *cond) +{ + DBUG_ENTER("Item_in_subselect::pushdown_cond_for_in_subquery"); + Item *remaining_cond= NULL; + + if (!cond) + DBUG_RETURN(FALSE); + + st_select_lex *sel = unit->first_select(); + + if (is_jtbm_const_tab) + DBUG_RETURN(FALSE); + + if (!sel->cond_pushdown_is_allowed()) + DBUG_RETURN(FALSE); + + /* + Create a list of Field_pair items for this IN subquery. + It consists of the pairs of fields from the left part of this IN subquery + predicate 'left_part' and the respective fields from the select of the + right part of the IN subquery 'sel' (the field from left_part with the + corresponding field from the sel projection list). + Attach this list to the IN subquery. + */ + corresponding_fields.empty(); + List_iterator_fast<Item> it(sel->join->fields_list); + Item *item; + for (uint i= 0; i < left_expr->cols(); i++) + { + item= it++; + Item *elem= left_expr->element_index(i); + + if (elem->real_item()->type() != Item::FIELD_ITEM) + continue; + + if (corresponding_fields.push_back( + new Field_pair(((Item_field *)(elem->real_item()))->field, + item))) + DBUG_RETURN(TRUE); + } + + /* 1. Check what pushable formula can be extracted from cond */ + Item *extracted_cond; + cond->check_pushable_cond(&Item::pushable_cond_checker_for_subquery, + (uchar *)this); + /* 2. Build a clone PC of the formula that can be extracted */ + extracted_cond= + cond->build_pushable_cond(thd, + &Item::pushable_equality_checker_for_subquery, + (uchar *)this); + /* Nothing to push */ + if (!extracted_cond) + { + DBUG_RETURN(FALSE); + } + + /* Collect fields that are used in the GROUP BY of sel */ + st_select_lex *save_curr_select= thd->lex->current_select; + if (sel->have_window_funcs()) + { + if (sel->group_list.first || sel->join->implicit_grouping) + goto exit; + ORDER *common_partition_fields= + sel->find_common_window_func_partition_fields(thd); + if (!common_partition_fields) + goto exit; + + if (grouping_fields_in_the_in_subq_left_part(thd, sel, &corresponding_fields, + common_partition_fields)) + DBUG_RETURN(TRUE); + } + else if (grouping_fields_in_the_in_subq_left_part(thd, sel, + &corresponding_fields, + sel->group_list.first)) + DBUG_RETURN(TRUE); + + /* Do 4-6 */ + sel->pushdown_cond_into_where_clause(thd, extracted_cond, + &remaining_cond, + &Item::in_subq_field_transformer_for_where, + (uchar *) this); + if (!remaining_cond) + goto exit; + /* + 7. Prepare PC_having to be conjuncted with the HAVING clause of + the IN subquery + */ + remaining_cond= + remaining_cond->transform(thd, + &Item::in_subq_field_transformer_for_having, + (uchar *)this); + if (!remaining_cond) + goto exit; + + remaining_cond->walk(&Item::cleanup_excluding_const_fields_processor, + 0, 0); + sel->cond_pushed_into_having= remaining_cond; + +exit: + thd->lex->current_select= save_curr_select; + DBUG_RETURN(FALSE); +} diff --git a/sql/opt_subselect.h b/sql/opt_subselect.h index 9cb19e0cc6c..031118288b9 100644 --- a/sql/opt_subselect.h +++ b/sql/opt_subselect.h @@ -26,8 +26,15 @@ int check_and_do_in_subquery_rewrites(JOIN *join); bool convert_join_subqueries_to_semijoins(JOIN *join); int pull_out_semijoin_tables(JOIN *join); bool optimize_semijoin_nests(JOIN *join, table_map all_table_map); -bool setup_jtbm_semi_joins(JOIN *join, List<TABLE_LIST> *join_list, - Item **join_where); +Item *and_new_conditions_to_optimized_cond(THD *thd, Item *cond, + COND_EQUAL **cond_eq, + List<Item> &new_conds, + Item::cond_result *cond_value); +bool setup_degenerate_jtbm_semi_joins(JOIN *join, + List<TABLE_LIST> *join_list, + List<Item> &eq_list); +bool setup_jtbm_semi_joins(JOIN *join, List<TABLE_LIST> *join_list, + List<Item> &eq_list); void cleanup_empty_jtbm_semi_joins(JOIN *join, List<TABLE_LIST> *join_list); // used by Loose_scan_opt diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc index 12f230724fb..80cb63b72bc 100644 --- a/sql/sql_derived.cc +++ b/sql/sql_derived.cc @@ -1208,25 +1208,61 @@ bool mysql_derived_reinit(THD *thd, LEX *lex, TABLE_LIST *derived) /** @brief - Extract the condition depended on derived table/view and pushed it there + Extract condition that can be pushed into a derived table/view - @param thd The thread handle - @param cond The condition from which to extract the pushed condition - @param derived The reference to the derived table/view + @param thd the thread handle + @param cond current condition + @param derived the reference to the derived table/view @details - This functiom builds the most restrictive condition depending only on - the derived table/view that can be extracted from the condition cond. - The built condition is pushed into the having clauses of the - selects contained in the query specifying the derived table/view. - The function also checks for each select whether any condition depending - only on grouping fields can be extracted from the pushed condition. - If so, it pushes the condition over grouping fields into the where - clause of the select. - - @retval - true if an error is reported - false otherwise + This function builds the most restrictive condition depending only on + the derived table/view (directly or indirectly through equality) that + can be extracted from the given condition cond and pushes it into the + derived table/view. + + Example of the transformation: + + SELECT * + FROM t1, + ( + SELECT x,MAX(y) AS max_y + FROM t2 + GROUP BY x + ) AS d_tab + WHERE d_tab.x>1 AND d_tab.max_y<30; + + => + + SELECT * + FROM t1, + ( + SELECT x,z,MAX(y) AS max_y + FROM t2 + WHERE x>1 + HAVING max_y<30 + GROUP BY x + ) AS d_tab + WHERE d_tab.x>1 AND d_tab.max_y<30; + + In details: + 1. Check what pushable formula can be extracted from cond + 2. Build a clone PC of the formula that can be extracted + (the clone is built only if the extracted formula is a AND subformula + of cond or conjunction of such subformulas) + Do for every select specifying derived table/view: + 3. If there is no HAVING clause prepare PC to be conjuncted with + WHERE clause of the select. Otherwise do 4-7. + 4. Check what formula PC_where can be extracted from PC to be pushed + into the WHERE clause of the select + 5. Build PC_where and if PC_where is a conjunct(s) of PC remove it from PC + getting PC_having + 6. Prepare PC_where to be conjuncted with the WHERE clause of the select + 7. Prepare PC_having to be conjuncted with the HAVING clause of the select + @note + This method is similar to pushdown_cond_for_in_subquery() + + @retval TRUE if an error occurs + @retval FALSE otherwise */ bool pushdown_cond_for_derived(THD *thd, Item *cond, TABLE_LIST *derived) @@ -1266,63 +1302,25 @@ bool pushdown_cond_for_derived(THD *thd, Item *cond, TABLE_LIST *derived) if (!some_select_allows_cond_pushdown) DBUG_RETURN(false); - /* - Build the most restrictive condition extractable from 'cond' - that can be pushed into the derived table 'derived'. - All subexpressions of this condition are cloned from the - subexpressions of 'cond'. - This condition has to be fixed yet. - */ + /* 1. Check what pushable formula can be extracted from cond */ Item *extracted_cond; - derived->check_pushable_cond_for_table(cond); - extracted_cond= derived->build_pushable_cond_for_table(thd, cond); + cond->check_pushable_cond(&Item::pushable_cond_checker_for_derived, + (uchar *)(&derived->table->map)); + /* 2. Build a clone PC of the formula that can be extracted */ + extracted_cond= + cond->build_pushable_cond(thd, + &Item::pushable_equality_checker_for_derived, + ((uchar *)&derived->table->map)); if (!extracted_cond) { /* Nothing can be pushed into the derived table */ DBUG_RETURN(false); } - /* Push extracted_cond into every select of the unit specifying 'derived' */ + st_select_lex *save_curr_select= thd->lex->current_select; for (; sl; sl= sl->next_select()) { Item *extracted_cond_copy; - if (!sl->cond_pushdown_is_allowed()) - continue; - thd->lex->current_select= sl; - if (sl->have_window_funcs()) - { - if (sl->join->group_list || sl->join->implicit_grouping) - continue; - ORDER *common_partition_fields= - sl->find_common_window_func_partition_fields(thd); - if (!common_partition_fields) - continue; - extracted_cond_copy= !sl->next_select() ? - extracted_cond : - extracted_cond->build_clone(thd); - if (!extracted_cond_copy) - continue; - - Item *cond_over_partition_fields;; - sl->collect_grouping_fields(thd, common_partition_fields); - sl->check_cond_extraction_for_grouping_fields(extracted_cond_copy, - derived); - cond_over_partition_fields= - sl->build_cond_for_grouping_fields(thd, extracted_cond_copy, true); - if (cond_over_partition_fields) - cond_over_partition_fields= cond_over_partition_fields->transform(thd, - &Item::derived_grouping_field_transformer_for_where, - (uchar*) sl); - if (cond_over_partition_fields) - { - cond_over_partition_fields->walk( - &Item::cleanup_excluding_const_fields_processor, 0, 0); - sl->cond_pushed_into_where= cond_over_partition_fields; - } - - continue; - } - /* For each select of the unit except the last one create a clone of extracted_cond @@ -1333,73 +1331,44 @@ bool pushdown_cond_for_derived(THD *thd, Item *cond, TABLE_LIST *derived) if (!extracted_cond_copy) continue; - if (!sl->join->group_list && !sl->with_sum_func) - { - /* extracted_cond_copy is pushed into where of sl */ - extracted_cond_copy= extracted_cond_copy->transform(thd, - &Item::derived_field_transformer_for_where, - (uchar*) sl); - if (extracted_cond_copy) - { - extracted_cond_copy->walk( - &Item::cleanup_excluding_const_fields_processor, 0, 0); - sl->cond_pushed_into_where= extracted_cond_copy; - } - - continue; - } - - /* - Figure out what can be extracted from the pushed condition - that could be pushed into the where clause of sl - */ - Item *cond_over_grouping_fields; - sl->collect_grouping_fields(thd, sl->join->group_list); - sl->check_cond_extraction_for_grouping_fields(extracted_cond_copy, - derived); - cond_over_grouping_fields= - sl->build_cond_for_grouping_fields(thd, extracted_cond_copy, true); - - /* - Transform the references to the 'derived' columns from the condition - pushed into the where clause of sl to make them usable in the new context - */ - if (cond_over_grouping_fields) - cond_over_grouping_fields= cond_over_grouping_fields->transform(thd, - &Item::derived_grouping_field_transformer_for_where, - (uchar*) sl); - - if (cond_over_grouping_fields) + /* Collect fields that are used in the GROUP BY of sl */ + if (sl->have_window_funcs()) { - /* - In extracted_cond_copy remove top conjuncts that - has been pushed into the where clause of sl - */ - extracted_cond_copy= remove_pushed_top_conjuncts(thd, extracted_cond_copy); - - cond_over_grouping_fields->walk( - &Item::cleanup_excluding_const_fields_processor, 0, 0); - sl->cond_pushed_into_where= cond_over_grouping_fields; - - if (!extracted_cond_copy) + if (sl->group_list.first || sl->join->implicit_grouping) + continue; + ORDER *common_partition_fields= + sl->find_common_window_func_partition_fields(thd); + if (!common_partition_fields) continue; + sl->collect_grouping_fields(thd, common_partition_fields); } + else + sl->collect_grouping_fields(thd, sl->group_list.first); + + Item *remaining_cond= NULL; + /* Do 4-6 */ + sl->pushdown_cond_into_where_clause(thd, extracted_cond_copy, + &remaining_cond, + &Item::derived_field_transformer_for_where, + (uchar *) sl); + if (!remaining_cond) + continue; /* - Transform the references to the 'derived' columns from the condition - pushed into the having clause of sl to make them usable in the new context + 7. Prepare PC_having to be conjuncted with the HAVING clause of + the select */ - extracted_cond_copy= extracted_cond_copy->transform(thd, - &Item::derived_field_transformer_for_having, - (uchar*) sl); - if (!extracted_cond_copy) + remaining_cond= + remaining_cond->transform(thd, + &Item::derived_field_transformer_for_having, + (uchar *) sl); + if (!remaining_cond) continue; - extracted_cond_copy->walk(&Item::cleanup_excluding_const_fields_processor, - 0, 0); - sl->cond_pushed_into_having= extracted_cond_copy; + remaining_cond->walk(&Item::cleanup_excluding_const_fields_processor, + 0, 0); + sl->cond_pushed_into_having= remaining_cond; } thd->lex->current_select= save_curr_select; DBUG_RETURN(false); } - diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 0106f189ca8..bea9fa05b6f 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -7130,9 +7130,9 @@ void st_select_lex::collect_grouping_fields(THD *thd, { if ((*ord->item)->eq((Item*)item, 0)) { - Grouping_tmp_field *grouping_tmp_field= - new Grouping_tmp_field(master_unit()->derived->table->field[i], item); - grouping_tmp_fields.push_back(grouping_tmp_field); + Field_pair *grouping_tmp_field= + new Field_pair(master_unit()->derived->table->field[i], item); + grouping_tmp_fields.push_back(grouping_tmp_field); } } } @@ -7162,8 +7162,7 @@ void st_select_lex::collect_grouping_fields(THD *thd, */ void -st_select_lex::check_cond_extraction_for_grouping_fields(Item *cond, - TABLE_LIST *derived) +st_select_lex::check_cond_extraction_for_grouping_fields(Item *cond) { cond->clear_extraction_flag(); if (cond->type() == Item::COND_ITEM) @@ -7176,7 +7175,7 @@ st_select_lex::check_cond_extraction_for_grouping_fields(Item *cond, Item *item; while ((item=li++)) { - check_cond_extraction_for_grouping_fields(item, derived); + check_cond_extraction_for_grouping_fields(item); if (item->get_extraction_flag() != NO_EXTRACTION_FL) { count++; @@ -7225,7 +7224,7 @@ st_select_lex::check_cond_extraction_for_grouping_fields(Item *cond, to figure out whether a subformula depends only on these fields or not. @note The built condition C is always implied by the condition cond - (cond => C). The method tries to build the most restictive such + (cond => C). The method tries to build the least restictive such condition (i.e. for any other condition C' such that cond => C' we have C => C'). @note @@ -7238,7 +7237,7 @@ st_select_lex::check_cond_extraction_for_grouping_fields(Item *cond, */ Item *st_select_lex::build_cond_for_grouping_fields(THD *thd, Item *cond, - bool no_top_clones) + bool no_top_clones) { if (cond->get_extraction_flag() == FULL_EXTRACTION_FL) { @@ -7266,17 +7265,17 @@ Item *st_select_lex::build_cond_for_grouping_fields(THD *thd, Item *cond, { if (item->get_extraction_flag() == NO_EXTRACTION_FL) { - DBUG_ASSERT(cond_and); - item->clear_extraction_flag(); - continue; + DBUG_ASSERT(cond_and); + item->clear_extraction_flag(); + continue; } Item *fix= build_cond_for_grouping_fields(thd, item, - no_top_clones & cond_and); + no_top_clones & cond_and); if (!fix) { - if (cond_and) - continue; - break; + if (cond_and) + continue; + break; } new_cond->argument_list()->push_back(fix, thd->mem_root); } @@ -7284,7 +7283,7 @@ Item *st_select_lex::build_cond_for_grouping_fields(THD *thd, Item *cond, if (!cond_and && item) { while((item= li++)) - item->clear_extraction_flag(); + item->clear_extraction_flag(); return 0; } switch (new_cond->argument_list()->elements) @@ -7497,3 +7496,127 @@ bool SELECT_LEX::vers_push_field(THD *thd, TABLE_LIST *table, const LEX_CSTRING return false; } + +/** + @brief + Extract from given item a condition pushable into WHERE clause + + @param thd the thread handle + @param cond the item to extract a condition to be pushed + into WHERE + @param remaining_cond the condition that will remain of cond after + the pushdown of its parts into the WHERE clause + @param transformer the transformer callback function to be + applied to the condition so it can be pushed + down into the WHERE clause of this select + @param arg parameter to be passed to the transformer + + @details + This method checks if cond entirely or its parts can be + pushed into the WHERE clause of this select and prepares it for pushing. + + First it checks wherever this select doesn't have any aggregation function + in its projection and GROUP BY clause. If so cond can be entirely + pushed into the WHERE clause of this select but before its fields should + be transformed with transformer_for_where to make it pushable. + + Otherwise the method checks wherever any condition depending only on + grouping fields can be extracted from cond. If there is any it prepares it + for pushing using grouping_field_transformer_for_where and if it happens to + be a conjunct of cond it removes it from cond. It saves the result of + removal in remaining_cond. + The extracted condition is saved in cond_pushed_into_where of this select. + + @note + When looking for pushable condition the method considers only the grouping + fields from the list grouping_tmp_fields whose elements are of the type + Field_pair. This list must be prepared before the call of the + function. + + @note + This method is called for pushdown conditions into materialized + derived tables/views optimization. + Item::derived_field_transformer_for_where is passed as the actual + callback function. + Also it is called for pushdown conditions into materialized IN subqueries. + Item::in_subq_field_transformer_for_where is passed as the actual + callback function. +*/ + +void st_select_lex::pushdown_cond_into_where_clause(THD *thd, Item *cond, + Item **remaining_cond, + Item_transformer transformer, + uchar *arg) +{ + if (!cond_pushdown_is_allowed()) + return; + thd->lex->current_select= this; + if (have_window_funcs()) + { + Item *cond_over_partition_fields; + check_cond_extraction_for_grouping_fields(cond); + cond_over_partition_fields= + build_cond_for_grouping_fields(thd, cond, true); + if (cond_over_partition_fields) + cond_over_partition_fields= cond_over_partition_fields->transform(thd, + &Item::grouping_field_transformer_for_where, + (uchar*) this); + if (cond_over_partition_fields) + { + cond_over_partition_fields->walk( + &Item::cleanup_excluding_const_fields_processor, 0, 0); + cond_pushed_into_where= cond_over_partition_fields; + } + + return; + } + + if (!join->group_list && !with_sum_func) + { + cond= + cond->transform(thd, transformer, arg); + if (cond) + { + cond->walk( + &Item::cleanup_excluding_const_fields_processor, 0, 0); + cond_pushed_into_where= cond; + } + + return; + } + + /* + Figure out what can be extracted from cond + that could be pushed into the WHERE clause of this select + */ + Item *cond_over_grouping_fields; + check_cond_extraction_for_grouping_fields(cond); + cond_over_grouping_fields= + build_cond_for_grouping_fields(thd, cond, true); + + /* + Transform the references to the columns from the cond + pushed into the WHERE clause of this select to make them usable in + the new context + */ + if (cond_over_grouping_fields) + cond_over_grouping_fields= cond_over_grouping_fields->transform(thd, + &Item::grouping_field_transformer_for_where, + (uchar*) this); + + if (cond_over_grouping_fields) + { + + /* + In cond remove top conjuncts that has been pushed into the WHERE + clause of this select + */ + cond= remove_pushed_top_conjuncts(thd, cond); + + cond_over_grouping_fields->walk( + &Item::cleanup_excluding_const_fields_processor, 0, 0); + cond_pushed_into_where= cond_over_grouping_fields; + } + + *remaining_cond= cond; +} diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 058bd639e44..55d75ff4389 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -817,19 +817,19 @@ typedef Bounds_checked_array<Item*> Ref_ptr_array; /* - Structure which consists of the field and the item which - produces this field. + Structure which consists of the field and the item that + corresponds to this field. */ - -class Grouping_tmp_field :public Sql_alloc +class Field_pair :public Sql_alloc { public: - Field *tmp_field; - Item *producing_item; - Grouping_tmp_field(Field *fld, Item *item) - :tmp_field(fld), producing_item(item) {} + Field *field; + Item *corresponding_item; + Field_pair(Field *fld, Item *item) + :field(fld), corresponding_item(item) {} }; + /* SELECT_LEX - store information of parsed SELECT statment */ @@ -1036,7 +1036,8 @@ public: nesting_map name_visibility_map; table_map with_dep; - List<Grouping_tmp_field> grouping_tmp_fields; + /* the structure to store fields that are used in the GROUP BY of this select */ + List<Field_pair> grouping_tmp_fields; /* it is for correct printing SELECT options */ thr_lock_type lock_type; @@ -1239,9 +1240,8 @@ public: With_element *find_table_def_in_with_clauses(TABLE_LIST *table); bool check_unrestricted_recursive(bool only_standard_compliant); bool check_subqueries_with_recursive_references(); - void collect_grouping_fields(THD *thd, ORDER *grouping_list); - void check_cond_extraction_for_grouping_fields(Item *cond, - TABLE_LIST *derived); + void collect_grouping_fields(THD *thd, ORDER *grouping_list); + void check_cond_extraction_for_grouping_fields(Item *cond); Item *build_cond_for_grouping_fields(THD *thd, Item *cond, bool no_to_clones); @@ -1267,6 +1267,11 @@ public: bool cond_pushdown_is_allowed() const { return !olap && !explicit_limit && !tvc; } + void pushdown_cond_into_where_clause(THD *thd, Item *extracted_cond, + Item **remaining_cond, + Item_transformer transformer, + uchar *arg); + private: bool m_non_agg_field_used; bool m_agg_func_used; diff --git a/sql/sql_priv.h b/sql/sql_priv.h index ba37d933f12..7d2e1bae741 100644 --- a/sql/sql_priv.h +++ b/sql/sql_priv.h @@ -228,6 +228,7 @@ #define OPTIMIZER_SWITCH_ORDERBY_EQ_PROP (1ULL << 29) #define OPTIMIZER_SWITCH_COND_PUSHDOWN_FOR_DERIVED (1ULL << 30) #define OPTIMIZER_SWITCH_SPLIT_MATERIALIZED (1ULL << 31) +#define OPTIMIZER_SWITCH_COND_PUSHDOWN_FOR_SUBQUERY (1ULL << 32) #define OPTIMIZER_SWITCH_DEFAULT (OPTIMIZER_SWITCH_INDEX_MERGE | \ OPTIMIZER_SWITCH_INDEX_MERGE_UNION | \ @@ -254,7 +255,8 @@ OPTIMIZER_SWITCH_EXISTS_TO_IN | \ OPTIMIZER_SWITCH_ORDERBY_EQ_PROP | \ OPTIMIZER_SWITCH_COND_PUSHDOWN_FOR_DERIVED | \ - OPTIMIZER_SWITCH_SPLIT_MATERIALIZED) + OPTIMIZER_SWITCH_SPLIT_MATERIALIZED | \ + OPTIMIZER_SWITCH_COND_PUSHDOWN_FOR_SUBQUERY) /* Replication uses 8 bytes to store SQL_MODE in the binary log. The day you diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 2c1452e8096..306a540852e 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1729,10 +1729,29 @@ JOIN::optimize_inner() if (arena) thd->restore_active_arena(arena, &backup); } - - if (setup_jtbm_semi_joins(this, join_list, &conds)) + + List<Item> eq_list; + + if (setup_degenerate_jtbm_semi_joins(this, join_list, eq_list)) DBUG_RETURN(1); + if (eq_list.elements != 0) + { + Item *new_cond; + + if (eq_list.elements == 1) + new_cond= eq_list.pop(); + else + new_cond= new (thd->mem_root) Item_cond_and(thd, eq_list); + + if (new_cond && + ((new_cond->fix_fields(thd, &new_cond) || + !(conds= and_items(thd, conds, new_cond)) || + conds->fix_fields(thd, &conds)))) + DBUG_RETURN(TRUE); + } + eq_list.empty(); + if (select_lex->cond_pushed_into_where) { conds= and_conds(thd, conds, select_lex->cond_pushed_into_where); @@ -1755,6 +1774,32 @@ JOIN::optimize_inner() &cond_value, &cond_equal, OPT_LINK_EQUAL_FIELDS); if (thd->lex->sql_command == SQLCOM_SELECT && + optimizer_flag(thd, OPTIMIZER_SWITCH_COND_PUSHDOWN_FOR_SUBQUERY)) + { + TABLE_LIST *tbl; + List_iterator_fast<TABLE_LIST> li(select_lex->leaf_tables); + while ((tbl= li++)) + if (tbl->jtbm_subselect) + { + if (tbl->jtbm_subselect->pushdown_cond_for_in_subquery(thd, conds)) + DBUG_RETURN(1); + } + } + + if (setup_jtbm_semi_joins(this, join_list, eq_list)) + DBUG_RETURN(1); + + if (eq_list.elements != 0) + { + conds= and_new_conditions_to_optimized_cond(thd, conds, &cond_equal, + eq_list, &cond_value); + + if (!conds && + cond_value != Item::COND_FALSE && cond_value != Item::COND_TRUE) + DBUG_RETURN(TRUE); + } + + if (thd->lex->sql_command == SQLCOM_SELECT && optimizer_flag(thd, OPTIMIZER_SWITCH_COND_PUSHDOWN_FOR_DERIVED)) { TABLE_LIST *tbl; @@ -1792,7 +1837,6 @@ JOIN::optimize_inner() if (select_lex->handle_derived(thd->lex, DT_OPTIMIZE)) DBUG_RETURN(1); } - if (thd->is_error()) { error= 1; @@ -13487,9 +13531,9 @@ finish: FALSE otherwise */ -static bool check_simple_equality(THD *thd, const Item::Context &ctx, - Item *left_item, Item *right_item, - COND_EQUAL *cond_equal) +bool check_simple_equality(THD *thd, const Item::Context &ctx, + Item *left_item, Item *right_item, + COND_EQUAL *cond_equal) { Item *orig_left_item= left_item; Item *orig_right_item= right_item; diff --git a/sql/sql_select.h b/sql/sql_select.h index 4642fe04dbc..75e0e2ac1f7 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -1470,6 +1470,11 @@ public: Dynamic_array<KEYUSE_EXT> *ext_keyuses_for_splitting; JOIN_TAB *sort_and_group_aggr_tab; + /* + Flag is set to true if select_lex was found to be degenerated before + the optimize_cond() call in JOIN::optimize_inner() method. + */ + bool is_orig_degenerated; JOIN(THD *thd_arg, List<Item> &fields_arg, ulonglong select_options_arg, select_result *result_arg) @@ -1564,6 +1569,7 @@ public: emb_sjm_nest= NULL; sjm_lookup_tables= 0; sjm_scan_tables= 0; + is_orig_degenerated= false; } /* True if the plan guarantees that it will be returned zero or one row */ @@ -1734,6 +1740,7 @@ public: bool fix_all_splittings_in_plan(); bool transform_in_predicates_into_in_subq(THD *thd); + bool add_equalities_to_where_condition(THD *thd, List<Item> &eq_list); private: /** Create a temporary table to be used for processing DISTINCT/ORDER @@ -2326,7 +2333,7 @@ Item_equal *find_item_equal(COND_EQUAL *cond_equal, Field *field, extern bool test_if_ref(Item *, Item_field *left_item,Item *right_item); -inline bool optimizer_flag(THD *thd, uint flag) +inline bool optimizer_flag(THD *thd, ulonglong flag) { return (thd->variables.optimizer_switch & flag); } @@ -2441,4 +2448,13 @@ int create_sort_index(THD *thd, JOIN *join, JOIN_TAB *tab, Filesort *fsort); JOIN_TAB *first_explain_order_tab(JOIN* join); JOIN_TAB *next_explain_order_tab(JOIN* join, JOIN_TAB* tab); +bool check_simple_equality(THD *thd, const Item::Context &ctx, + Item *left_item, Item *right_item, + COND_EQUAL *cond_equal); + +void propagate_new_equalities(THD *thd, Item *cond, + List<Item_equal> *new_equalities, + COND_EQUAL *inherited, + bool *is_simplifiable_cond); + #endif /* SQL_SELECT_INCLUDED */ diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index 94c77136993..ba9b295a7be 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -2480,6 +2480,7 @@ export const char *optimizer_switch_names[]= "orderby_uses_equalities", "condition_pushdown_for_derived", "split_materialized", + "condition_pushdown_for_subquery", "default", NullS }; diff --git a/sql/table.cc b/sql/table.cc index f220e21920d..2ff48980f11 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -8384,191 +8384,6 @@ double KEY::actual_rec_per_key(uint i) } -/** - @brief - Mark subformulas of a condition unusable for the condition pushed into table - - @param cond The condition whose subformulas are to be marked - - @details - This method recursively traverses the AND-OR condition cond and for each subformula - of the codition it checks whether it can be usable for the extraction of a condition - that can be pushed into this table. The subformulas that are not usable are - marked with the flag NO_EXTRACTION_FL. - @note - This method is called before any call of TABLE_LIST::build_pushable_cond_for_table. - The flag NO_EXTRACTION_FL set in a subformula allows to avoid building clone - for the subformula when extracting the pushable condition. -*/ - -void TABLE_LIST::check_pushable_cond_for_table(Item *cond) -{ - table_map tab_map= table->map; - cond->clear_extraction_flag(); - if (cond->type() == Item::COND_ITEM) - { - bool and_cond= ((Item_cond*) cond)->functype() == Item_func::COND_AND_FUNC; - List_iterator<Item> li(*((Item_cond*) cond)->argument_list()); - uint count= 0; - Item *item; - while ((item=li++)) - { - check_pushable_cond_for_table(item); - if (item->get_extraction_flag() != NO_EXTRACTION_FL) - count++; - else if (!and_cond) - break; - } - if ((and_cond && count == 0) || item) - { - cond->set_extraction_flag(NO_EXTRACTION_FL); - if (and_cond) - li.rewind(); - while ((item= li++)) - item->clear_extraction_flag(); - } - } - else if (!cond->excl_dep_on_table(tab_map)) - cond->set_extraction_flag(NO_EXTRACTION_FL); -} - - -/** - @brief - Build condition extractable from the given one depended only on this table - - @param thd The thread handle - @param cond The condition from which the pushable one is to be extracted - - @details - For the given condition cond this method finds out what condition depended - only on this table can be extracted from cond. If such condition C exists - the method builds the item for it. - The method uses the flag NO_EXTRACTION_FL set by the preliminary call of - the method TABLE_LIST::check_pushable_cond_for_table to figure out whether - a subformula depends only on this table or not. - @note - The built condition C is always implied by the condition cond - (cond => C). The method tries to build the most restictive such - condition (i.e. for any other condition C' such that cond => C' - we have C => C'). - @note - The build item is not ready for usage: substitution for the field items - has to be done and it has to be re-fixed. - - @retval - the built condition pushable into this table if such a condition exists - NULL if there is no such a condition -*/ - -Item* TABLE_LIST::build_pushable_cond_for_table(THD *thd, Item *cond) -{ - table_map tab_map= table->map; - bool is_multiple_equality= cond->type() == Item::FUNC_ITEM && - ((Item_func*) cond)->functype() == Item_func::MULT_EQUAL_FUNC; - if (cond->get_extraction_flag() == NO_EXTRACTION_FL) - return 0; - if (cond->type() == Item::COND_ITEM) - { - bool cond_and= false; - Item_cond *new_cond; - if (((Item_cond*) cond)->functype() == Item_func::COND_AND_FUNC) - { - cond_and= true; - new_cond=new (thd->mem_root) Item_cond_and(thd); - } - else - new_cond= new (thd->mem_root) Item_cond_or(thd); - if (!new_cond) - return 0; - List_iterator<Item> li(*((Item_cond*) cond)->argument_list()); - Item *item; - while ((item=li++)) - { - if (item->get_extraction_flag() == NO_EXTRACTION_FL) - { - if (!cond_and) - return 0; - continue; - } - Item *fix= build_pushable_cond_for_table(thd, item); - if (!fix && !cond_and) - return 0; - if (!fix) - continue; - new_cond->argument_list()->push_back(fix, thd->mem_root); - } - switch (new_cond->argument_list()->elements) - { - case 0: - return 0; - case 1: - return new_cond->argument_list()->head(); - default: - return new_cond; - } - } - else if (is_multiple_equality) - { - if (!(cond->used_tables() & tab_map)) - return 0; - Item *new_cond= NULL; - int i= 0; - Item_equal *item_equal= (Item_equal *) cond; - Item *left_item = item_equal->get_const(); - Item_equal_fields_iterator it(*item_equal); - Item *item; - if (!left_item) - { - while ((item=it++)) - if (item->used_tables() == tab_map) - { - left_item= item; - break; - } - } - if (!left_item) - return 0; - while ((item=it++)) - { - if (!(item->used_tables() == tab_map)) - continue; - Item_func_eq *eq= 0; - Item *left_item_clone= left_item->build_clone(thd); - Item *right_item_clone= item->build_clone(thd); - if (left_item_clone && right_item_clone) - { - left_item_clone->set_item_equal(NULL); - right_item_clone->set_item_equal(NULL); - eq= new (thd->mem_root) Item_func_eq(thd, right_item_clone, - left_item_clone); - } - if (eq) - { - i++; - switch (i) - { - case 1: - new_cond= eq; - break; - case 2: - new_cond= new (thd->mem_root) Item_cond_and(thd, new_cond, eq); - break; - default: - ((Item_cond_and*)new_cond)->argument_list()->push_back(eq, - thd->mem_root); - } - } - } - if (new_cond) - new_cond->fix_fields(thd, &new_cond); - return new_cond; - } - else if (cond->get_extraction_flag() != NO_EXTRACTION_FL) - return cond->build_clone(thd); - return 0; -} - LEX_CSTRING *fk_option_name(enum_fk_option opt) { static LEX_CSTRING names[]= diff --git a/sql/table.h b/sql/table.h index 79742ff7111..8c1dda2abd6 100644 --- a/sql/table.h +++ b/sql/table.h @@ -2598,8 +2598,6 @@ inline void init_one_table(const LEX_CSTRING *db_arg, return false; } void set_lock_type(THD* thd, enum thr_lock_type lock); - void check_pushable_cond_for_table(Item *cond); - Item *build_pushable_cond_for_table(THD *thd, Item *cond); private: bool prep_check_option(THD *thd, uint8 check_opt_type); diff --git a/storage/tokudb/mysql-test/tokudb/r/ext_key_1_innodb.result b/storage/tokudb/mysql-test/tokudb/r/ext_key_1_innodb.result index a80e1664663..2a0ee4fa3e1 100644 --- a/storage/tokudb/mysql-test/tokudb/r/ext_key_1_innodb.result +++ b/storage/tokudb/mysql-test/tokudb/r/ext_key_1_innodb.result @@ -1,7 +1,7 @@ drop table if exists t; select @@optimizer_switch; @@optimizer_switch -index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on +index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on,condition_pushdown_for_subquery=on create table t (id int not null, x int not null, y int not null, primary key(id), key(x)) engine=innodb; insert into t values (0,0,0),(1,1,1),(2,2,2),(3,2,3),(4,2,4); explain select x,id from t force index (x) where x=0 and id=0; diff --git a/storage/tokudb/mysql-test/tokudb/r/ext_key_1_tokudb.result b/storage/tokudb/mysql-test/tokudb/r/ext_key_1_tokudb.result index 96d681407fe..4580cc96404 100644 --- a/storage/tokudb/mysql-test/tokudb/r/ext_key_1_tokudb.result +++ b/storage/tokudb/mysql-test/tokudb/r/ext_key_1_tokudb.result @@ -1,7 +1,7 @@ drop table if exists t; select @@optimizer_switch; @@optimizer_switch -index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on +index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on,condition_pushdown_for_subquery=on create table t (id int not null, x int not null, y int not null, primary key(id), key(x)) engine=tokudb; insert into t values (0,0,0),(1,1,1),(2,2,2),(3,2,3),(4,2,4); explain select x,id from t force index (x) where x=0 and id=0; diff --git a/storage/tokudb/mysql-test/tokudb/r/ext_key_2_innodb.result b/storage/tokudb/mysql-test/tokudb/r/ext_key_2_innodb.result index 43737c7753e..fb998e3a6ad 100644 --- a/storage/tokudb/mysql-test/tokudb/r/ext_key_2_innodb.result +++ b/storage/tokudb/mysql-test/tokudb/r/ext_key_2_innodb.result @@ -1,7 +1,7 @@ drop table if exists t; select @@optimizer_switch; @@optimizer_switch -index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on +index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on,condition_pushdown_for_subquery=on create table t (a int not null, b int not null, c int not null, d int not null, primary key(a,b), key(c,a)) engine=innodb; insert into t values (0,0,0,0),(0,1,0,1); explain select c,a,b from t where c=0 and a=0 and b=1; diff --git a/storage/tokudb/mysql-test/tokudb/r/ext_key_2_tokudb.result b/storage/tokudb/mysql-test/tokudb/r/ext_key_2_tokudb.result index 1dcb1ee1b8b..9d9fb4ca079 100644 --- a/storage/tokudb/mysql-test/tokudb/r/ext_key_2_tokudb.result +++ b/storage/tokudb/mysql-test/tokudb/r/ext_key_2_tokudb.result @@ -1,7 +1,7 @@ drop table if exists t; select @@optimizer_switch; @@optimizer_switch -index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on +index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on,condition_pushdown_for_subquery=on create table t (a int not null, b int not null, c int not null, d int not null, primary key(a,b), key(c,a)) engine=tokudb; insert into t values (0,0,0,0),(0,1,0,1); explain select c,a,b from t where c=0 and a=0 and b=1; |