You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Bug#31376809 PERFORMANCE REGRESSION FROM 5.7->8.0, DUE TO ANTIJOIN OF NOT EXISTS SUBQUERY
Disable antijoin transformation if this is:
- NOT EXISTS, or <constant> NOT IN,
- and the subquery is not correlated.
Otherwise we got this type of plan:
nested loop antijoin
-> outer
-> inner
and we would read each row of "outer", only to find, every time, that
there is a row in "inner" and that we should not emit the row of "outer".
Instead, we evaluate the subquery during optimization, leading to an always
true or false condition.
This does not cancel Steinar's patch for the same bug report; however it
makes "case 2" (see his commit comment) apply only to antijoin coming from
LEFT JOIN, as antijoin coming from NOT EXISTS will not reach the executor
anymore, due to the present patch.
Approved by: Roy Lyseng <[email protected]>
Change-Id: I59a887456a56039a6b1480b3ec8f7ac188d1ce58
2 SUBQUERY t1b NULL ALL NULL NULL NULL NULL 1 100.00 Using where
720
720
3 DEPENDENT SUBQUERY t2 NULL unique_subquery PRIMARY PRIMARY 4 func 1 100.00 Using where; Full scan on NULL key
721
721
Warnings:
722
722
Note 1276 Field or reference 'test.t1b.t1_time' of SELECT #3 was resolved in SELECT #2
723
723
Note 1276 Field or reference 'test.t1b.t1_int' of SELECT #3 was resolved in SELECT #2
724
724
Note 1276 Field or reference 'test.t1b.t1_time' of SELECT #3 was resolved in SELECT #2
725
-
Note 1003 /* select#1 */ select `test`.`t1a`.`t1_int` AS `t1_int`,`test`.`t1a`.`t1_time` AS `t1_time` from `test`.`t1` `t1a` anti join (`test`.`t1` `t1b`) on((<in_optimizer>(`test`.`t1b`.`t1_int`,<exists>(<primary_index_lookup>(<cache>(`test`.`t1b`.`t1_int`) in t2 on PRIMARY where ((`test`.`t1b`.`t1_time` like `test`.`t1b`.`t1_int`) and <if>(outer_field_is_not_null, (<cache>(`test`.`t1b`.`t1_int`) = `test`.`t2`.`t2_int`), true)))) is false))) where true
725
+
Note 1003 /* select#1 */ select `test`.`t1a`.`t1_int` AS `t1_int`,`test`.`t1a`.`t1_time` AS `t1_time` from `test`.`t1` `t1a` where false
Note 1276 Field or reference 'test.t1b.t1_time' of SELECT #3 was resolved in SELECT #2
721
721
Note 1276 Field or reference 'test.t1b.t1_int' of SELECT #3 was resolved in SELECT #2
722
722
Note 1276 Field or reference 'test.t1b.t1_time' of SELECT #3 was resolved in SELECT #2
723
-
Note 1003 /* select#1 */ select NULL AS `t1_int`,NULL AS `t1_time` from <constant table> anti join (`test`.`t1` `t1b`) on((<in_optimizer>(`test`.`t1b`.`t1_int`,<exists>(/* select#3 */ select '0' from dual where ((`test`.`t1b`.`t1_time` like `test`.`t1b`.`t1_int`) and <if>(outer_field_is_not_null, (<cache>(`test`.`t1b`.`t1_int`) = '0'), true))) is false))) where true
723
+
Note 1003 /* select#1 */ select `test`.`t1a`.`t1_int` AS `t1_int`,`test`.`t1a`.`t1_time` AS `t1_time` from `test`.`t1` `t1a` where false
2 SUBQUERY t2 NULL ALL NULL NULL NULL NULL 2 100.00 Using where
5340
5340
3 DEPENDENT SUBQUERY NULL NULL NULL NULL NULL NULL NULL NULL NULL no matching row in const table
5341
5341
Warnings:
5342
5342
Note 1276 Field or reference 'test.t2.b' of SELECT #3 was resolved in SELECT #2
5343
-
Note 1003 /* select#1 */ select count(0) AS `COUNT(*)` from `test`.`t1` anti join (`test`.`t2`) on(((1 = (/* select#3 */ select min(`test`.`t2`.`b`) from `test`.`t3`)))) where true
5343
+
Note 1003 /* select#1 */ select count(0) AS `COUNT(*)` from `test`.`t1` where true
5344
5344
# should not crash the next statement
5345
5345
SELECT COUNT(*) FROM t1
5346
5346
WHERE NOT EXISTS (SELECT 1 FROM t2 WHERE 1 = (SELECT MIN(t2.b) FROM t3))
2 SUBQUERY t2 NULL ALL NULL NULL NULL NULL 2 100.00 Using where
5341
5341
3 DEPENDENT SUBQUERY NULL NULL NULL NULL NULL NULL NULL NULL NULL no matching row in const table
5342
5342
Warnings:
5343
5343
Note 1276 Field or reference 'test.t2.b' of SELECT #3 was resolved in SELECT #2
5344
-
Note 1003 /* select#1 */ select count(0) AS `COUNT(*)` from `test`.`t1` anti join (`test`.`t2`) on(((1 = (/* select#3 */ select min(`test`.`t2`.`b`) from `test`.`t3`)))) where true
5344
+
Note 1003 /* select#1 */ select count(0) AS `COUNT(*)` from `test`.`t1` where true
5345
5345
# should not crash the next statement
5346
5346
SELECT COUNT(*) FROM t1
5347
5347
WHERE NOT EXISTS (SELECT 1 FROM t2 WHERE 1 = (SELECT MIN(t2.b) FROM t3))
2 SUBQUERY t2 NULL ALL NULL NULL NULL NULL 2 100.00 Using where
5341
5341
3 DEPENDENT SUBQUERY NULL NULL NULL NULL NULL NULL NULL NULL NULL no matching row in const table
5342
5342
Warnings:
5343
5343
Note 1276 Field or reference 'test.t2.b' of SELECT #3 was resolved in SELECT #2
5344
-
Note 1003 /* select#1 */ select count(0) AS `COUNT(*)` from `test`.`t1` anti join (`test`.`t2`) on(((1 = (/* select#3 */ select min(`test`.`t2`.`b`) from `test`.`t3`)))) where true
5344
+
Note 1003 /* select#1 */ select count(0) AS `COUNT(*)` from `test`.`t1` where true
5345
5345
# should not crash the next statement
5346
5346
SELECT COUNT(*) FROM t1
5347
5347
WHERE NOT EXISTS (SELECT 1 FROM t2 WHERE 1 = (SELECT MIN(t2.b) FROM t3))
3 SUBQUERY sj1 NULL index NULL PRIMARY 4 NULL 1 100.00 Using index
731
726
Warnings:
732
727
Note 1249 Select 5 was reduced during optimization
733
-
Note 1003 /* select#1 */ select `test`.`alias1`.`pk` AS `pk` from `test`.`t1` `alias1` left join (`test`.`t1` join `test`.`t1` `alias2` anti join (`test`.`t1` `sj1`) on(true)) on(((`test`.`alias2`.`pk` = `test`.`alias1`.`col_int`))) where true
728
+
Note 1003 /* select#1 */ select `test`.`alias1`.`pk` AS `pk` from `test`.`t1` `alias1` left join (`test`.`t1` join `test`.`t1` `alias2`) on(((`test`.`alias2`.`pk` = `test`.`alias1`.`col_int`) and exists(/* select#4 */ select 1 from `test`.`t1` `sj2` where false) is false and exists(/* select#3 */ select `test`.`sj1`.`pk` from `test`.`t1` `sj1`) is false)) where true
734
729
SELECT alias1.pk
735
730
FROM t1 AS alias1 LEFT JOIN
736
731
(SELECT alias2.*
@@ -905,25 +900,26 @@ NOT EXISTS ( SELECT * FROM t1 as t4);
905
900
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t2 NULL ALL NULL NULL NULL NULL 1 100.00 Using where
908
-
1 PRIMARY <subquery3> NULL const <auto_distinct_key> <auto_distinct_key> 8 const 1 100.00 Using where; Not exists
909
-
3 MATERIALIZED t4 NULL index NULL PRIMARY 4 NULL 1 100.00 Using where; Using index
903
+
3 SUBQUERY t4 NULL index NULL PRIMARY 4 NULL 1 100.00 Using index
910
904
2 UNCACHEABLE SUBQUERY t3 NULL index NULL PRIMARY 4 NULL 1 100.00 Using index
911
905
Warnings:
912
-
Note 1003 /* select#1 */ select `test`.`t1`.`pk` AS `pk`,`test`.`t1`.`col_int` AS `col_int`,`test`.`t2`.`pk` AS `pk`,`test`.`t2`.`col_int` AS `col_int` from `test`.`t1` left join (`test`.`t1` `t2` anti join (`test`.`t1` `t4`) on((1 = 1))) on(((`test`.`t1`.`col_int` > (/* select#2 */ select (@`var`) from `test`.`t1` `t3`)) and true)) where true
906
+
Note 1003 /* select#1 */ select `test`.`t1`.`pk` AS `pk`,`test`.`t1`.`col_int` AS `col_int`,`test`.`t2`.`pk` AS `pk`,`test`.`t2`.`col_int` AS `col_int` from `test`.`t1` left join `test`.`t1` `t2` on(((`test`.`t1`.`col_int` > (/* select#2 */ select (@`var`) from `test`.`t1` `t3`)) and exists(/* select#3 */ select 1 from `test`.`t1` `t4`) is false)) where true
913
907
EXPLAIN FORMAT=TREE SELECT * FROM t1 LEFT JOIN t1 AS t2
914
908
ON 1 AND t1.col_int > ( SELECT @var FROM t1 as t3 ) AND
915
909
NOT EXISTS ( SELECT * FROM t1 as t4);
916
910
EXPLAIN
917
-
-> Nested loop left join
911
+
-> Nested loop left join (cost=0.70 rows=1)
918
912
-> Table scan on t1 (cost=0.35 rows=1)
919
-
-> Filter: (t1.col_int > (select #2))
920
-
-> Nested loop antijoin
921
-
-> Table scan on t2 (cost=0.35 rows=1)
922
-
-> Constant row from <subquery3>
923
-
-> Materialize with deduplication
924
-
-> Index scan on t4 using PRIMARY (cost=0.35 rows=1)
913
+
-> Filter: (exists(select #3) is false and ((t1.col_int > (select #2)) and exists(select #3) is false)) (cost=0.35 rows=1)
914
+
-> Table scan on t2 (cost=0.35 rows=1)
915
+
-> Select #3 (subquery in condition; run only once)
916
+
-> Limit: 1 row(s)
917
+
-> Index scan on t4 using PRIMARY (cost=0.35 rows=1)
925
918
-> Select #2 (subquery in condition; uncacheable)
926
919
-> Index scan on t3 using PRIMARY (cost=0.35 rows=1)
920
+
-> Select #3 (subquery in condition; run only once)
921
+
-> Limit: 1 row(s)
922
+
-> Index scan on t4 using PRIMARY (cost=0.35 rows=1)
927
923
928
924
SELECT * FROM t1 LEFT JOIN t1 AS t2
929
925
ON 1 AND t1.col_int > ( SELECT @var FROM t1 as t3 ) AND
@@ -1010,11 +1006,12 @@ alias1.col_datetime_key AS field3
1010
1006
FROM t1 AS alias1 LEFT JOIN t1 AS alias2
1011
1007
ON NOT EXISTS ( SELECT * FROM t1 AS alias3 WHERE ( SELECT 1 FROM DUAL ) IS NULL );
1012
1008
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
Note 1249 Select 3 was reduced during optimization
1017
-
Note 1003 /* select#1 */ select `test`.`alias1`.`col_int` AS `field1`,`test`.`alias2`.`col_varchar_key` AS `field2`,`test`.`alias1`.`col_datetime_key` AS `field3` from `test`.`t1` `alias1` left join `test`.`t1` `alias2` on(true) where true
1014
+
Note 1003 /* select#1 */ select `test`.`alias1`.`col_int` AS `field1`,`test`.`alias2`.`col_varchar_key` AS `field2`,`test`.`alias1`.`col_datetime_key` AS `field3` from `test`.`t1` `alias1` left join `test`.`t1` `alias2` on(exists(/* select#2 */ select 1 from `test`.`t1` `alias3` where false) is false) where true
1018
1015
SELECT alias1.col_int AS field1 , alias2.col_varchar_key AS field2 ,
1019
1016
alias1.col_datetime_key AS field3
1020
1017
FROM t1 AS alias1 LEFT JOIN t1 AS alias2
@@ -1081,3 +1078,21 @@ SELECT MAX(t1.a) FROM t1 WHERE a NOT IN (SELECT a FROM t2);
1081
1078
MAX(t1.a)
1082
1079
1
1083
1080
DROP TABLE t1, t2;
1081
+
#
1082
+
# Bug#31376809 PERFORMANCE REGRESSION FROM 5.7->8.0, DUE TO ANTIJOIN OF NOT EXISTS SUBQUERY
1083
+
#
1084
+
create table t(a int, b int);
1085
+
insert into t values(1,1),(2,2),(3,3),(4,4),(5,5);
1086
+
explain format=tree select a from t where (not exists (select b from t));
1087
+
EXPLAIN
1088
+
-> Zero rows (Impossible WHERE)
1089
+
1090
+
select a from t where (not exists (select b from t));
1091
+
a
1092
+
explain format=tree select a from t where 1 not in (select 1 from t);
0 commit comments