Commit ba9cf8ef authored by Yuchen Pei's avatar Yuchen Pei

MDEV-22534 Decorrelate IN subquery

Transform

in (select inner_col' from inner_table where inner_col = outer_col)

to

, outer_col in (select inner_col', inner_col from inner_table)

Achieved by implementing Item_in_subselect::exists2in_processor(),
accompanied with comprehensive test coverage.

Caveat:

- The fix of 2nd ps execution segfault requires
  HAVE_PSI_STATEMENT_INTERFACE because it checks
  thd->m_statement_state.m_parent_prepared_stmt to determine whether we
  are inside a ps execution. Is there a better way to determine this?
- Cannot recognise bad item mismatch in equalities that causes
  materialization to not materialize down the road
parent 3ef11161
......@@ -906,7 +906,7 @@ EXPLAIN
"buffer_type": "flat",
"buffer_size": "141",
"join_type": "BNL",
"attached_condition": "t1.b = t2.b and t1.a = t2.a"
"attached_condition": "t1.a = t2.a and t1.b = t2.b"
}
}
]
......@@ -921,7 +921,8 @@ explain
select * from t2 where t2.a in ( select a from t1 where t1.b=t2.b);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t2 ALL NULL NULL NULL NULL 10
1 PRIMARY t1 ALL NULL NULL NULL NULL 10 Using where; Start temporary; End temporary; Using join buffer (flat, BNL join)
1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 8 func,func 1
2 MATERIALIZED t1 ALL NULL NULL NULL NULL 10
explain format=json
select * from t2 where t2.a in ( select a from t1 where t1.b=t2.b);
EXPLAIN
......@@ -929,6 +930,7 @@ EXPLAIN
"query_block": {
"select_id": 1,
"cost": "COST_REPLACED",
"const_condition": "1",
"nested_loop": [
{
"table": {
......@@ -941,25 +943,36 @@ EXPLAIN
}
},
{
"duplicates_removal": [
"table": {
"table_name": "<subquery2>",
"access_type": "eq_ref",
"possible_keys": ["distinct_key"],
"key": "distinct_key",
"key_length": "8",
"used_key_parts": ["a", "b"],
"ref": ["func", "func"],
"rows": 1,
"filtered": 100,
"materialized": {
"unique": 1,
"query_block": {
"select_id": 2,
"nested_loop": [
{
"block-nl-join": {
"table": {
"table_name": "t1",
"access_type": "ALL",
"loops": 10,
"loops": 1,
"rows": 10,
"cost": "COST_REPLACED",
"filtered": 10
},
"buffer_type": "flat",
"buffer_size": "206",
"join_type": "BNL",
"attached_condition": "t1.b = t2.b and t1.a = t2.a"
"filtered": 100
}
}
]
}
}
}
}
]
}
}
......
......@@ -384,15 +384,16 @@ EXPLAIN
SELECT a FROM t1 AS t, t2 as t2_out
WHERE t2_out.c = t.a AND t.b IN (SELECT b FROM t1, t2 WHERE b = t.b);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 index b b 7 NULL 10 Using index; Start temporary
1 PRIMARY t ref a,b b 3 test.t1.b 2 Using index
1 PRIMARY t2 index NULL PRIMARY 4 NULL 11 Using index; End temporary; Using join buffer (flat, BNL join)
1 PRIMARY t index a,b b 7 NULL 10 Using index
1 PRIMARY t2_out eq_ref PRIMARY PRIMARY 4 test.t.a 1 Using index
1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 8 func,func 1
2 MATERIALIZED t1 index b b 7 NULL 10 Using index
2 MATERIALIZED t2 index NULL PRIMARY 4 NULL 11 Using index; Using join buffer (flat, BNL join)
SELECT a FROM t1 AS t, t2 as t2_out
WHERE t2_out.c = t.a AND t.b IN (SELECT b FROM t1, t2 WHERE b = t.b);
a
24
Last_query_cost 0.120558
Last_query_cost 0.083937
DROP TABLE t1,t2;
#
# LP Bug #923236: hash join + extended_keys = on
......
......@@ -3433,7 +3433,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra
2 DEPENDENT SUBQUERY a1 ALL NULL NULL NULL NULL 60 100.00 Using join buffer (flat, BNL join)
Warnings:
Note 1276 Field or reference 'test.t1.pk' of SELECT #2 was resolved in SELECT #1
Note 1003 /* select#1 */ select `test`.`t1`.`pk` AS `pk`,`test`.`t1`.`c1` AS `c1` from `test`.`t1` where !<expr_cache><`test`.`t1`.`c1`,`test`.`t1`.`pk`>(<in_optimizer>(`test`.`t1`.`c1`,<exists>(/* select#2 */ select `test`.`t2`.`c1` from `test`.`t2` join `test`.`t1` `a1` where `test`.`t2`.`i1` = `test`.`t1`.`pk` and `test`.`t2`.`i1` between 3 and 5 and trigcond(<cache>(`test`.`t1`.`c1`) = `test`.`t2`.`c1`))))
Note 1003 /* select#1 */ select `test`.`t1`.`pk` AS `pk`,`test`.`t1`.`c1` AS `c1` from `test`.`t1` where !<expr_cache><`test`.`t1`.`c1`,`test`.`t1`.`pk`>(<in_optimizer>((`test`.`t1`.`c1`,`test`.`t1`.`pk`),<exists>(/* select#2 */ select `test`.`t2`.`c1`,`test`.`t2`.`i1` from `test`.`t2` join `test`.`t1` `a1` where `test`.`t2`.`i1` between 3 and 5 and trigcond(<cache>(`test`.`t1`.`c1`) = `test`.`t2`.`c1`) and (<cache>(`test`.`t1`.`pk`) = `test`.`t2`.`i1` or `test`.`t2`.`i1` is null) having `test`.`t2`.`i1` is null)))
SELECT * FROM t1
WHERE t1.c1 NOT IN (SELECT t2.c1 FROM t2, t1 AS a1
WHERE t2.i1 = t1.pk AND t2.i1 BETWEEN 3 AND 5);
......
......@@ -630,7 +630,7 @@ aa 1
explain select oref, a from t2 where a not in (select ie from t1 where oref=t2.oref);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t2 ALL NULL NULL NULL NULL 7 Using where
2 DEPENDENT SUBQUERY t1 unique_subquery PRIMARY PRIMARY 4 func 1 Using where; Full scan on NULL key
2 DEPENDENT SUBQUERY t1 eq_ref PRIMARY PRIMARY 4 func 1 Using where; Full scan on NULL key
select oref, a from t2 where a not in (select ie from t1 where oref=t2.oref);
oref a
ee NULL
......
......@@ -633,7 +633,7 @@ aa 1
explain select oref, a from t2 where a not in (select ie from t1 where oref=t2.oref);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t2 ALL NULL NULL NULL NULL 7 Using where
2 DEPENDENT SUBQUERY t1 unique_subquery PRIMARY PRIMARY 4 func 1 Using where; Full scan on NULL key
2 DEPENDENT SUBQUERY t1 eq_ref PRIMARY PRIMARY 4 func 1 Using where; Full scan on NULL key
select oref, a from t2 where a not in (select ie from t1 where oref=t2.oref);
oref a
ee NULL
......
......@@ -225,7 +225,7 @@ EXPLAIN
SELECT * FROM t1 WHERE NULL NOT IN (SELECT t2a.i FROM t2a WHERE t2a.pk = t1.pk);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 4 Using where
2 DEPENDENT SUBQUERY t2a unique_subquery PRIMARY PRIMARY 8 const,test.t1.pk 1 Using index; Using where; Full scan on NULL key
2 DEPENDENT SUBQUERY t2a unique_subquery PRIMARY PRIMARY 8 const,func 1 Using index; Using where; Full scan on NULL key
SELECT * FROM t1 WHERE NULL NOT IN (SELECT t2a.i FROM t2a WHERE t2a.pk = t1.pk);
pk i
SELECT * FROM t1 WHERE 1+NULL NOT IN (SELECT t2a.i FROM t2a WHERE t2a.pk = t1.pk);
......@@ -265,7 +265,7 @@ EXPLAIN
SELECT * FROM t1 WHERE NULL NOT IN (SELECT t2c.i FROM t2c WHERE t2c.pk = t1.pk);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 4 Using where
2 DEPENDENT SUBQUERY t2c index_subquery it2c it2c 8 const,test.t1.pk 1 Using index; Using where; Full scan on NULL key
2 DEPENDENT SUBQUERY t2c index_subquery it2c it2c 8 const,func 1 Using index; Using where; Full scan on NULL key
SELECT * FROM t1 WHERE NULL NOT IN (SELECT t2c.i FROM t2c WHERE t2c.pk = t1.pk);
pk i
SELECT * FROM t1 WHERE NULL IN (SELECT t2c.i FROM t2c WHERE t2c.pk = t1.pk) IS UNKNOWN;
......@@ -303,7 +303,7 @@ EXPLAIN
SELECT * FROM t1 WHERE (NULL, 1) NOT IN (SELECT t2a.i, t2a.pk FROM t2a WHERE t2a.pk = t1.pk);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 4 Using where
2 DEPENDENT SUBQUERY t2a unique_subquery PRIMARY PRIMARY 8 const,test.t1.pk 1 Using index; Using where; Full scan on NULL key
2 DEPENDENT SUBQUERY t2a const PRIMARY PRIMARY 8 const,const 1 Using where; Using index; Full scan on NULL key
SELECT * FROM t1 WHERE (NULL, 1) NOT IN (SELECT t2a.i, t2a.pk FROM t2a WHERE t2a.pk = t1.pk);
pk i
0 10
......@@ -335,7 +335,7 @@ EXPLAIN
SELECT * FROM t1 WHERE (NULL, 1) NOT IN (SELECT t2c.i, t2c.pk FROM t2c WHERE t2c.pk = t1.pk);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 4 Using where
2 DEPENDENT SUBQUERY t2c index_subquery it2c it2c 8 const,test.t1.pk 1 Using index; Using where; Full scan on NULL key
2 DEPENDENT SUBQUERY t2c index_subquery it2c it2c 8 const,const 0 Using index; Using where; Full scan on NULL key
SELECT * FROM t1 WHERE (NULL, 1) NOT IN (SELECT t2c.i, t2c.pk FROM t2c WHERE t2c.pk = t1.pk);
pk i
0 10
......
This diff is collapsed.
This diff is collapsed.
......@@ -454,7 +454,7 @@ WHERE t2.c = v1.c AND t2.c = v1.b AND v1.b = t3.c);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t3 ALL NULL NULL NULL NULL 2 Using where
2 DEPENDENT SUBQUERY t2 system NULL NULL NULL NULL 1
2 DEPENDENT SUBQUERY <derived3> ref key1 key1 8 const,const 0 Using where
2 DEPENDENT SUBQUERY <derived3> ref key0 key0 8 const,const 0 Using where
3 DERIVED t1 ALL NULL NULL NULL NULL 3 Using where
SELECT * FROM t3
WHERE t3.b IN (SELECT v1.b FROM v1, t2
......@@ -476,7 +476,7 @@ EXPLAIN
SELECT * FROM t1 WHERE t1.b IN (SELECT v2.a FROM v2 WHERE v2.b = t1.a);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 2 Using where
2 DEPENDENT SUBQUERY <derived3> ref key0 key0 5 test.t1.a 1 Using where
2 DEPENDENT SUBQUERY <derived3> index_subquery key0 key0 10 func,func 1 Using where
3 DERIVED t2 ALL NULL NULL NULL NULL 2
SELECT * FROM t1 WHERE t1.b IN (SELECT v2.a FROM v2 WHERE v2.b = t1.a);
a b
......
......@@ -390,7 +390,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra
3 DEPENDENT SUBQUERY t3a ALL NULL NULL NULL NULL 4 100.00 Using where
Warnings:
Note 1276 Field or reference 'test.t1.a1' of SELECT #3 was resolved in SELECT #1
Note 1003 /* select#1 */ select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2` from `test`.`t1` where <expr_cache><`test`.`t1`.`a1`,`test`.`t1`.`a2`>(<in_optimizer>((`test`.`t1`.`a1`,`test`.`t1`.`a2`),<exists>(/* select#2 */ select `test`.`t2`.`b1`,`test`.`t2`.`b2` from `test`.`t2` where (<expr_cache><`test`.`t2`.`b2`,`test`.`t1`.`a1`>(<in_optimizer>(`test`.`t2`.`b2`,<exists>(/* select#3 */ select `test`.`t3a`.`c2` from `test`.`t3` `t3a` where `test`.`t3a`.`c1` = `test`.`t1`.`a1` and <cache>(`test`.`t2`.`b2`) = `test`.`t3a`.`c2`))) or <expr_cache><`test`.`t2`.`b2`>(<in_optimizer>(`test`.`t2`.`b2`,`test`.`t2`.`b2` in ( <materialize> (/* select#4 */ select `test`.`t3b`.`c2` from `test`.`t3` `t3b` where `test`.`t3b`.`c2` like '%03' ), <primary_index_lookup>(`test`.`t2`.`b2` in <temporary table> on distinct_key where `test`.`t2`.`b2` = `<subquery4>`.`c2`))))) and <cache>(`test`.`t1`.`a1`) = `test`.`t2`.`b1` and <cache>(`test`.`t1`.`a2`) = `test`.`t2`.`b2`))) and <expr_cache><`test`.`t1`.`a1`,`test`.`t1`.`a2`>(<in_optimizer>((`test`.`t1`.`a1`,`test`.`t1`.`a2`),(`test`.`t1`.`a1`,`test`.`t1`.`a2`) in ( <materialize> (/* select#5 */ select `test`.`t3c`.`c1`,`test`.`t3c`.`c2` from `test`.`t3` `t3c` where <expr_cache><`test`.`t3c`.`c1`,`test`.`t3c`.`c2`>(<in_optimizer>((`test`.`t3c`.`c1`,`test`.`t3c`.`c2`),(`test`.`t3c`.`c1`,`test`.`t3c`.`c2`) in ( <materialize> (/* select#6 */ select `test`.`t2i`.`b1`,`test`.`t2i`.`b2` from `test`.`t2i` where `test`.`t2i`.`b2` > '0' ), <primary_index_lookup>(`test`.`t3c`.`c1` in <temporary table> on distinct_key where `test`.`t3c`.`c1` = `<subquery6>`.`b1` and `test`.`t3c`.`c2` = `<subquery6>`.`b2`)))) ), <primary_index_lookup>(`test`.`t1`.`a1` in <temporary table> on distinct_key where `test`.`t1`.`a1` = `<subquery5>`.`c1` and `test`.`t1`.`a2` = `<subquery5>`.`c2`))))
Note 1003 /* select#1 */ select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2` from `test`.`t1` where <expr_cache><`test`.`t1`.`a1`,`test`.`t1`.`a2`>(<in_optimizer>((`test`.`t1`.`a1`,`test`.`t1`.`a2`),<exists>(/* select#2 */ select `test`.`t2`.`b1`,`test`.`t2`.`b2` from `test`.`t2` where (<expr_cache><`test`.`t2`.`b2`,`test`.`t1`.`a1`>(<in_optimizer>((`test`.`t2`.`b2`,`test`.`t1`.`a1`),<exists>(/* select#3 */ select `test`.`t3a`.`c2`,`test`.`t3a`.`c1` from `test`.`t3` `t3a` where <cache>(`test`.`t2`.`b2`) = `test`.`t3a`.`c2` and <cache>(`test`.`t1`.`a1`) = `test`.`t3a`.`c1`))) or <expr_cache><`test`.`t2`.`b2`>(<in_optimizer>(`test`.`t2`.`b2`,`test`.`t2`.`b2` in ( <materialize> (/* select#4 */ select `test`.`t3b`.`c2` from `test`.`t3` `t3b` where `test`.`t3b`.`c2` like '%03' ), <primary_index_lookup>(`test`.`t2`.`b2` in <temporary table> on distinct_key where `test`.`t2`.`b2` = `<subquery4>`.`c2`))))) and <cache>(`test`.`t1`.`a1`) = `test`.`t2`.`b1` and <cache>(`test`.`t1`.`a2`) = `test`.`t2`.`b2`))) and <expr_cache><`test`.`t1`.`a1`,`test`.`t1`.`a2`>(<in_optimizer>((`test`.`t1`.`a1`,`test`.`t1`.`a2`),(`test`.`t1`.`a1`,`test`.`t1`.`a2`) in ( <materialize> (/* select#5 */ select `test`.`t3c`.`c1`,`test`.`t3c`.`c2` from `test`.`t3` `t3c` where <expr_cache><`test`.`t3c`.`c1`,`test`.`t3c`.`c2`>(<in_optimizer>((`test`.`t3c`.`c1`,`test`.`t3c`.`c2`),(`test`.`t3c`.`c1`,`test`.`t3c`.`c2`) in ( <materialize> (/* select#6 */ select `test`.`t2i`.`b1`,`test`.`t2i`.`b2` from `test`.`t2i` where `test`.`t2i`.`b2` > '0' ), <primary_index_lookup>(`test`.`t3c`.`c1` in <temporary table> on distinct_key where `test`.`t3c`.`c1` = `<subquery6>`.`b1` and `test`.`t3c`.`c2` = `<subquery6>`.`b2`)))) ), <primary_index_lookup>(`test`.`t1`.`a1` in <temporary table> on distinct_key where `test`.`t1`.`a1` = `<subquery5>`.`c1` and `test`.`t1`.`a2` = `<subquery5>`.`c2`))))
select * from t1
where (a1, a2) in (select b1, b2 from t2
where b2 in (select c2 from t3 t3a where c1 = a1) or
......@@ -524,7 +524,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra
Warnings:
Note 1276 Field or reference 'test.t1.a1' of SELECT #3 was resolved in SELECT #1
Note 1276 Field or reference 'test.t1.a2' of SELECT #6 was resolved in SELECT #1
Note 1003 /* select#1 */ select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2` from `test`.`t1` where <expr_cache><`test`.`t1`.`a1`,`test`.`t1`.`a2`>(<in_optimizer>((`test`.`t1`.`a1`,`test`.`t1`.`a2`),<exists>(/* select#2 */ select `test`.`t2`.`b1`,`test`.`t2`.`b2` from `test`.`t2` where (<expr_cache><`test`.`t2`.`b2`,`test`.`t1`.`a1`>(<in_optimizer>(`test`.`t2`.`b2`,<exists>(/* select#3 */ select `test`.`t3a`.`c2` from `test`.`t3` `t3a` where `test`.`t3a`.`c1` = `test`.`t1`.`a1` and <cache>(`test`.`t2`.`b2`) = `test`.`t3a`.`c2`))) or <expr_cache><`test`.`t2`.`b2`>(<in_optimizer>(`test`.`t2`.`b2`,`test`.`t2`.`b2` in ( <materialize> (/* select#4 */ select `test`.`t3b`.`c2` from `test`.`t3` `t3b` where `test`.`t3b`.`c2` like '%03' ), <primary_index_lookup>(`test`.`t2`.`b2` in <temporary table> on distinct_key where `test`.`t2`.`b2` = `<subquery4>`.`c2`))))) and <cache>(`test`.`t1`.`a1`) = `test`.`t2`.`b1` and <cache>(`test`.`t1`.`a2`) = `test`.`t2`.`b2`))) and <expr_cache><`test`.`t1`.`a1`,`test`.`t1`.`a2`>(<in_optimizer>((`test`.`t1`.`a1`,`test`.`t1`.`a2`),<exists>(/* select#5 */ select `test`.`t3c`.`c1`,`test`.`t3c`.`c2` from `test`.`t3` `t3c` where <expr_cache><`test`.`t3c`.`c1`,`test`.`t3c`.`c2`,`test`.`t1`.`a2`>(<in_optimizer>((`test`.`t3c`.`c1`,`test`.`t3c`.`c2`),<exists>(<index_lookup>(<cache>(`test`.`t3c`.`c1`) in t2i on it2i3 where (`test`.`t2i`.`b2` > '0' or `test`.`t2i`.`b2` = `test`.`t1`.`a2`) and <cache>(`test`.`t3c`.`c1`) = `test`.`t2i`.`b1` and <cache>(`test`.`t3c`.`c2`) = `test`.`t2i`.`b2`)))) and <cache>(`test`.`t1`.`a1`) = `test`.`t3c`.`c1` and <cache>(`test`.`t1`.`a2`) = `test`.`t3c`.`c2`)))
Note 1003 /* select#1 */ select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2` from `test`.`t1` where <expr_cache><`test`.`t1`.`a1`,`test`.`t1`.`a2`>(<in_optimizer>((`test`.`t1`.`a1`,`test`.`t1`.`a2`),<exists>(/* select#2 */ select `test`.`t2`.`b1`,`test`.`t2`.`b2` from `test`.`t2` where (<expr_cache><`test`.`t2`.`b2`,`test`.`t1`.`a1`>(<in_optimizer>((`test`.`t2`.`b2`,`test`.`t1`.`a1`),<exists>(/* select#3 */ select `test`.`t3a`.`c2`,`test`.`t3a`.`c1` from `test`.`t3` `t3a` where <cache>(`test`.`t2`.`b2`) = `test`.`t3a`.`c2` and <cache>(`test`.`t1`.`a1`) = `test`.`t3a`.`c1`))) or <expr_cache><`test`.`t2`.`b2`>(<in_optimizer>(`test`.`t2`.`b2`,`test`.`t2`.`b2` in ( <materialize> (/* select#4 */ select `test`.`t3b`.`c2` from `test`.`t3` `t3b` where `test`.`t3b`.`c2` like '%03' ), <primary_index_lookup>(`test`.`t2`.`b2` in <temporary table> on distinct_key where `test`.`t2`.`b2` = `<subquery4>`.`c2`))))) and <cache>(`test`.`t1`.`a1`) = `test`.`t2`.`b1` and <cache>(`test`.`t1`.`a2`) = `test`.`t2`.`b2`))) and <expr_cache><`test`.`t1`.`a1`,`test`.`t1`.`a2`>(<in_optimizer>((`test`.`t1`.`a1`,`test`.`t1`.`a2`),<exists>(/* select#5 */ select `test`.`t3c`.`c1`,`test`.`t3c`.`c2` from `test`.`t3` `t3c` where <expr_cache><`test`.`t3c`.`c1`,`test`.`t3c`.`c2`,`test`.`t1`.`a2`>(<in_optimizer>((`test`.`t3c`.`c1`,`test`.`t3c`.`c2`),<exists>(<index_lookup>(<cache>(`test`.`t3c`.`c1`) in t2i on it2i3 where (`test`.`t2i`.`b2` > '0' or `test`.`t2i`.`b2` = `test`.`t1`.`a2`) and <cache>(`test`.`t3c`.`c1`) = `test`.`t2i`.`b1` and <cache>(`test`.`t3c`.`c2`) = `test`.`t2i`.`b2`)))) and <cache>(`test`.`t1`.`a1`) = `test`.`t3c`.`c1` and <cache>(`test`.`t1`.`a2`) = `test`.`t3c`.`c2`)))
explain extended
select * from t1 where (a1, a2) in (select '1 - 01', '2 - 01');
id select_type table type possible_keys key key_len ref rows filtered Extra
......
......@@ -446,8 +446,8 @@ SELECT i2 FROM t2 RIGHT JOIN t3 ON (c3 = c2) WHERE pk3 = i1
);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 system NULL NULL NULL NULL 1
2 DEPENDENT SUBQUERY t3 const PRIMARY PRIMARY 4 const 1
2 DEPENDENT SUBQUERY t2 index i2 i2 11 NULL 2 Using where; Using index
2 DEPENDENT SUBQUERY t3 eq_ref PRIMARY PRIMARY 4 func 1 Using where; Full scan on NULL key
2 DEPENDENT SUBQUERY t2 index NULL i2 11 NULL 2 Using where; Using index; Using join buffer (flat, BNL join)
DROP TABLE t1,t2,t3;
#
# MDEV-7599: in-to-exists chosen after min/max optimization
......
......@@ -466,7 +466,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 ref a a 5 test.t0.a 1 100.00 Using where; FirstMatch(t2)
Warnings:
Note 1276 Field or reference 'test.t0.a' of SELECT #2 was resolved in SELECT #1
Note 1003 select `test`.`t0`.`a` AS `a` from `test`.`t2` semi join (`test`.`t1`) join `test`.`t0` where `test`.`t2`.`a` = `test`.`t0`.`a` and `test`.`t1`.`a` = `test`.`t0`.`a` and `test`.`t1`.`b` = `test`.`t2`.`b`
Note 1003 select `test`.`t0`.`a` AS `a` from `test`.`t2` semi join (`test`.`t1`) join `test`.`t0` where `test`.`t1`.`b` = `test`.`t2`.`b` and `test`.`t2`.`a` = `test`.`t0`.`a` and `test`.`t1`.`a` = `test`.`t0`.`a`
select * from t0
where t0.a in ( select t1.a from t1,t2 where t2.a=t0.a and
t1.b=t2.b);
......
......@@ -472,7 +472,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 ref a a 5 test.t0.a 1 100.00 Using where; FirstMatch(t2); Using join buffer (incremental, BKA join); Key-ordered Rowid-ordered scan
Warnings:
Note 1276 Field or reference 'test.t0.a' of SELECT #2 was resolved in SELECT #1
Note 1003 select `test`.`t0`.`a` AS `a` from `test`.`t2` semi join (`test`.`t1`) join `test`.`t0` where `test`.`t2`.`a` = `test`.`t0`.`a` and `test`.`t1`.`a` = `test`.`t0`.`a` and `test`.`t1`.`b` = `test`.`t2`.`b`
Note 1003 select `test`.`t0`.`a` AS `a` from `test`.`t2` semi join (`test`.`t1`) join `test`.`t0` where `test`.`t1`.`b` = `test`.`t2`.`b` and `test`.`t2`.`a` = `test`.`t0`.`a` and `test`.`t1`.`a` = `test`.`t0`.`a`
select * from t0
where t0.a in ( select t1.a from t1,t2 where t2.a=t0.a and
t1.b=t2.b);
......
......@@ -468,7 +468,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 ref a a 5 test.t0.a 1 100.00 Using where; FirstMatch(t2)
Warnings:
Note 1276 Field or reference 'test.t0.a' of SELECT #2 was resolved in SELECT #1
Note 1003 select `test`.`t0`.`a` AS `a` from `test`.`t2` semi join (`test`.`t1`) join `test`.`t0` where `test`.`t2`.`a` = `test`.`t0`.`a` and `test`.`t1`.`a` = `test`.`t0`.`a` and `test`.`t1`.`b` = `test`.`t2`.`b`
Note 1003 select `test`.`t0`.`a` AS `a` from `test`.`t2` semi join (`test`.`t1`) join `test`.`t0` where `test`.`t1`.`b` = `test`.`t2`.`b` and `test`.`t2`.`a` = `test`.`t0`.`a` and `test`.`t1`.`a` = `test`.`t0`.`a`
select * from t0
where t0.a in ( select t1.a from t1,t2 where t2.a=t0.a and
t1.b=t2.b);
......
......@@ -504,11 +504,13 @@ test.t1 analyze status OK
explain select * from t1 where c2 in (select distinct a.c2 from t1 a where t1.c1=a.c1);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 32
1 PRIMARY a ALL NULL NULL NULL NULL 32 Using where; FirstMatch(t1); Using join buffer (flat, BNL join)
1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 8 func,func 1
2 MATERIALIZED a ALL NULL NULL NULL NULL 32
explain update t1 set c3=c3+110 where c2 in (select distinct a.c2 from t1 a where t1.c1=a.c1);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 32
1 PRIMARY a ALL NULL NULL NULL NULL 32 Using where; FirstMatch(t1)
1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 8 func,func 1
2 MATERIALIZED a ALL NULL NULL NULL NULL 32
update t1 set c3=c3+110 where c2 in (select distinct a.c2 from t1 a where t1.c1=a.c1);
affected rows: 32
info: Rows matched: 32 Changed: 32 Warnings: 0
......@@ -1777,11 +1779,13 @@ test.t1 analyze status OK
explain select * from t1 where c2 in (select distinct a.c2 from t1 a where t1.c1=a.c1);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 32
1 PRIMARY a ALL NULL NULL NULL NULL 32 Using where; FirstMatch(t1); Using join buffer (flat, BNL join)
1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 8 func,func 1
2 MATERIALIZED a ALL NULL NULL NULL NULL 32
explain update t1 set c3=c3+110 where c2 in (select distinct a.c2 from t1 a where t1.c1=a.c1);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 32
1 PRIMARY a ALL NULL NULL NULL NULL 32 Using where; FirstMatch(t1)
1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 8 func,func 1
2 MATERIALIZED a ALL NULL NULL NULL NULL 32
update t1 set c3=c3+110 where c2 in (select distinct a.c2 from t1 a where t1.c1=a.c1);
affected rows: 32
info: Rows matched: 32 Changed: 32 Warnings: 0
......@@ -3051,11 +3055,13 @@ test.t1 analyze status OK
explain select * from t1 where c2 in (select distinct a.c2 from t1 a where t1.c1=a.c1);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 32
1 PRIMARY a ALL NULL NULL NULL NULL 32 Using where; FirstMatch(t1); Using join buffer (flat, BNL join)
1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 8 func,func 1
2 MATERIALIZED a ALL NULL NULL NULL NULL 32
explain update t1 set c3=c3+110 where c2 in (select distinct a.c2 from t1 a where t1.c1=a.c1);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 32
1 PRIMARY a ALL NULL NULL NULL NULL 32 Using where; FirstMatch(t1)
1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 8 func,func 1
2 MATERIALIZED a ALL NULL NULL NULL NULL 32
update t1 set c3=c3+110 where c2 in (select distinct a.c2 from t1 a where t1.c1=a.c1);
affected rows: 32
info: Rows matched: 32 Changed: 32 Warnings: 0
......@@ -4324,11 +4330,13 @@ test.t1 analyze status OK
explain select * from t1 where c2 in (select distinct a.c2 from t1 a where t1.c1=a.c1);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 32
1 PRIMARY a ALL NULL NULL NULL NULL 32 Using where; FirstMatch(t1); Using join buffer (flat, BNL join)
1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 8 func,func 1
2 MATERIALIZED a ALL NULL NULL NULL NULL 32
explain update t1 set c3=c3+110 where c2 in (select distinct a.c2 from t1 a where t1.c1=a.c1);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 32
1 PRIMARY a ALL NULL NULL NULL NULL 32 Using where; FirstMatch(t1)
1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 8 func,func 1
2 MATERIALIZED a ALL NULL NULL NULL NULL 32
update t1 set c3=c3+110 where c2 in (select distinct a.c2 from t1 a where t1.c1=a.c1);
affected rows: 32
info: Rows matched: 32 Changed: 32 Warnings: 0
......@@ -5598,11 +5606,13 @@ test.t1 analyze status OK
explain select * from t1 where c2 in (select distinct a.c2 from t1 a where t1.c1=a.c1);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 32
1 PRIMARY a ALL NULL NULL NULL NULL 32 Using where; FirstMatch(t1); Using join buffer (flat, BNL join)
1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 8 func,func 1
2 MATERIALIZED a ALL NULL NULL NULL NULL 32
explain update t1 set c3=c3+110 where c2 in (select distinct a.c2 from t1 a where t1.c1=a.c1);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 32
1 PRIMARY a ALL NULL NULL NULL NULL 32 Using where; FirstMatch(t1)
1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 8 func,func 1
2 MATERIALIZED a ALL NULL NULL NULL NULL 32
update t1 set c3=c3+110 where c2 in (select distinct a.c2 from t1 a where t1.c1=a.c1);
affected rows: 32
info: Rows matched: 32 Changed: 32 Warnings: 0
......@@ -6871,11 +6881,13 @@ test.t1 analyze status OK
explain select * from t1 where c2 in (select distinct a.c2 from t1 a where t1.c1=a.c1);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 32
1 PRIMARY a ALL NULL NULL NULL NULL 32 Using where; FirstMatch(t1); Using join buffer (flat, BNL join)
1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 8 func,func 1
2 MATERIALIZED a ALL NULL NULL NULL NULL 32
explain update t1 set c3=c3+110 where c2 in (select distinct a.c2 from t1 a where t1.c1=a.c1);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 32
1 PRIMARY a ALL NULL NULL NULL NULL 32 Using where; FirstMatch(t1)
1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 8 func,func 1
2 MATERIALIZED a ALL NULL NULL NULL NULL 32
update t1 set c3=c3+110 where c2 in (select distinct a.c2 from t1 a where t1.c1=a.c1);
affected rows: 32
info: Rows matched: 32 Changed: 32 Warnings: 0
......@@ -8145,11 +8157,13 @@ test.t1 analyze note The storage engine for the table doesn't support analyze
explain select * from t1 where c2 in (select distinct a.c2 from t1 a where t1.c1=a.c1);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 32
1 PRIMARY a ALL NULL NULL NULL NULL 32 Using where; FirstMatch(t1); Using join buffer (flat, BNL join)
1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 8 func,func 1
2 MATERIALIZED a ALL NULL NULL NULL NULL 32
explain update t1 set c3=c3+110 where c2 in (select distinct a.c2 from t1 a where t1.c1=a.c1);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 32
1 PRIMARY a ALL NULL NULL NULL NULL 32 Using where; FirstMatch(t1)
1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 8 func,func 1
2 MATERIALIZED a ALL NULL NULL NULL NULL 32
update t1 set c3=c3+110 where c2 in (select distinct a.c2 from t1 a where t1.c1=a.c1);
affected rows: 32
info: Rows matched: 32 Changed: 32 Warnings: 0
......@@ -9410,11 +9424,13 @@ test.t1 analyze note The storage engine for the table doesn't support analyze
explain select * from t1 where c2 in (select distinct a.c2 from t1 a where t1.c1=a.c1);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 32
1 PRIMARY a ALL NULL NULL NULL NULL 32 Using where; FirstMatch(t1); Using join buffer (flat, BNL join)
1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 8 func,func 1
2 MATERIALIZED a ALL NULL NULL NULL NULL 32
explain update t1 set c3=c3+110 where c2 in (select distinct a.c2 from t1 a where t1.c1=a.c1);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 32
1 PRIMARY a ALL NULL NULL NULL NULL 32 Using where; FirstMatch(t1)
1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 8 func,func 1
2 MATERIALIZED a ALL NULL NULL NULL NULL 32
update t1 set c3=c3+110 where c2 in (select distinct a.c2 from t1 a where t1.c1=a.c1);
affected rows: 32
info: Rows matched: 32 Changed: 32 Warnings: 0
......
......@@ -3099,6 +3099,132 @@ static bool find_inner_outer_equalities(Item **conds,
return TRUE;
}
/* Checks whether item tree intersects with the free list */
static bool intersects_free_list(Item *item, THD *thd)
{
for (const Item *to_find= thd->free_list; to_find; to_find= to_find->next)
if (item->walk(&Item::find_item_processor, 1, (void *) to_find))
return true;
return false;
}
/* De-correlate where conditions in an IN subquery */
bool Item_in_subselect::exists2in_processor(void *opt_arg)
{
THD *thd= (THD *)opt_arg;
SELECT_LEX *first_select= unit->first_select();
JOIN *join= first_select->join;
bool will_be_correlated;
Dynamic_array<EQ_FIELD_OUTER> eqs(PSI_INSTRUMENT_MEM, 5, 5);
List<Item> outer;
Query_arena *arena= NULL, backup;
int res= FALSE;
DBUG_ENTER("Item_in_subselect::exists2in_processor");
if (!optimizer_flag(thd, OPTIMIZER_SWITCH_EXISTS_TO_IN) ||
/* proceed only if I'm a toplevel IN or a toplevel NOT IN */
!(is_top_level_item() ||
(upper_not && upper_not->is_top_level_item())) ||
first_select->is_part_of_union() || /* skip if part of a union */
first_select->group_list.elements || /* skip if with group by */
first_select->with_sum_func || /* skip if aggregation */
join->having || /* skip if with having */
!join->conds || /* skip if no conds */
/* skip if left expr is a single nonscalar subselect */
(left_expr->type() == Item::SUBSELECT_ITEM &&
!left_expr->type_handler()->is_scalar_type()))
DBUG_RETURN(FALSE);
/* iterate over conditions, and check whether they can be moved out. */
if (find_inner_outer_equalities(&join->conds, eqs))
DBUG_RETURN(FALSE);
/* If we are in the execution of a prepared statement, check for
intersection with the free list to avoid segfault. Note that the
check for prepared statement execution is necessary, otherwise it
will likely always find intersection thus abort the
transformation.
fixme: this only works when HAVE_PSI_STATEMENT_INTERFACE is
defined. It causes CI's like amd64-debian-10-debug-embedded to
fail. Are there other ways to find out we are in the execution of a
prepared statement? */
if (thd->m_statement_state.m_parent_prepared_stmt)
{
for (uint i= 0; i < (uint) eqs.elements(); i++)
{
if (intersects_free_list(*eqs.at(i).eq_ref, thd))
DBUG_RETURN(FALSE);
}
}
/* Determines whether the result will be correlated */
{
List<Item> unused;
Collect_deps_prm prm= {&unused, // parameters
unit->first_select()->nest_level_base, // nest_level_base
0, // count
unit->first_select()->nest_level, // nest_level
FALSE // collect
};
walk(&Item::collect_outer_ref_processor, TRUE, &prm);
DBUG_ASSERT(prm.count > 0);
DBUG_ASSERT(prm.count >= (uint)eqs.elements());
will_be_correlated= prm.count > (uint)eqs.elements();
}
/* Back up the free list */
arena= thd->activate_stmt_arena_if_needed(&backup);
/* Construct the items for left_expr */
if (left_expr->type() == Item::ROW_ITEM)
for (uint i= 0; i < left_expr->cols(); i++)
outer.push_back(left_expr->element_index(i));
else
outer.push_back(left_expr);
const uint offset= first_select->item_list.elements;
/* Move items to outer and select item list */
for (uint i= 0; i < (uint)eqs.elements(); i++)
{
Item **eq_ref= eqs.at(i).eq_ref;
Item_ident *local_field= eqs.at(i).local_field;
Item *outer_exp= eqs.at(i).outer_exp;
first_select->item_list.push_back(local_field, thd->mem_root);
first_select->ref_pointer_array[offset + i]= (Item *)local_field;
outer.push_back(outer_exp);
*eq_ref= new (thd->mem_root) Item_int(thd, 1);
if((*eq_ref)->fix_fields(thd, (Item **)eq_ref))
{
res= TRUE;
goto out;
}
}
/* Update the left_expr */
left_expr= new (thd->mem_root) Item_row(thd, outer);
if (left_expr->fix_fields(thd, &left_expr))
{
res= TRUE;
goto out;
}
left_expr_orig= left_expr;
is_correlated= will_be_correlated;
/* Update any Item_in_optimizer wrapper if exists */
if (optimizer)
{
optimizer->reset_cache();
if (optimizer->fix_left(thd))
{
res= TRUE;
goto out;
}
}
{
OPT_TRACE_TRANSFORM(thd, trace_wrapper, trace_transform,
get_select_lex()->select_number, "IN (SELECT)",
"decorrelation");
}
out:
/* Restores the free list */
if (arena)
thd->restore_active_arena(arena, &backup);
DBUG_RETURN(res);
}
/**
Converts EXISTS subquery to IN subquery if it is possible and has sense
......
......@@ -757,10 +757,7 @@ class Item_in_subselect :public Item_exists_subselect
Item_subselect::walk(processor, walk_subquery, arg);
}
bool exists2in_processor(void *opt_arg __attribute__((unused))) override
{
return 0;
};
bool exists2in_processor(void *opt_arg) override;
bool pushdown_cond_for_in_subquery(THD *thd, Item *cond);
......@@ -804,6 +801,7 @@ class Item_allany_subselect :public Item_in_subselect
bool is_maxmin_applicable(JOIN *join);
bool transform_into_max_min(JOIN *join);
void no_rows_in_result();
bool exists2in_processor(void *arg) override { return FALSE; }
};
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment