| Bug #79675 | index_merge_intersection optimization causes wrong query results | ||
|---|---|---|---|
| Submitted: | 16 Dec 2015 16:48 | Modified: | 19 May 2017 18:43 |
| Reporter: | Saverio Miroddi | Email Updates: | |
| Status: | Closed | Impact on me: | |
| Category: | MySQL Server: Optimizer | Severity: | S1 (Critical) |
| Version: | 5.7/8.0 | OS: | Any |
| Assigned to: | CPU Architecture: | Any | |
[16 Dec 2015 16:48]
Saverio Miroddi
[18 Mar 2016 13:12]
MySQL Verification Team
Are you able to provide a dump file (create table + insert data)?. Thanks.
[22 Mar 2016 14:59]
Saverio Miroddi
Hello, unfortunately, the data is not available anymore.
I've just noticed that the comment:
[...] when I tried to copy the table to a copy, and execute the query against the copy, I wasn't able to reproduce the issue.
Should be:
[...] when I tried to create a copy of the table, and execute the query against the copy, I wasn't able to reproduce the issue.
[26 Mar 2016 1:04]
Rick James
Yet another argument for using a composite index instead of depending on index_merge_intersection ?
[29 Mar 2016 9:31]
Saverio Miroddi
> Yet another argument for using a composite index instead of depending on index_merge_intersection ? The query doesn't depend on this optimization; independently accessing the available indices is enough.
[6 Apr 2016 11:54]
Justinas Urbanavičius
i also encountered the same issue also the query uses index_intersect and if i force a certain index it provides the desired resultset, otherwise an empty resultset is returned. Server version: 5.6.29 MySQL Community Server (GPL) Centos kernel 2.6.32-573.22.1.el6.x86_64
[6 Apr 2016 13:13]
Justinas Urbanavičius
disabling index_merge_intersection solves the problem and at least benchmarking my query it also improves performance a little bit.
without with index_merge_intersect
concurent: 50
iterations: 100
Benchmark
Average number of seconds to run all queries: 0.013 seconds
Minimum number of seconds to run all queries: 0.012 seconds
Maximum number of seconds to run all queries: 0.017 seconds
Number of clients running queries: 50
Average number of queries per client: 1
with index_merge_intersect
concurent: 50
iterations: 100
Benchmark
Average number of seconds to run all queries: 0.016 seconds
Minimum number of seconds to run all queries: 0.015 seconds
Maximum number of seconds to run all queries: 0.021 seconds
Number of clients running queries: 50
Average number of queries per client: 1
[6 Apr 2016 13:14]
Justinas Urbanavičius
forgot to mention, that to disable index_merge_intersection in my.cnf you need to specify: optimizer_switch=index_merge_intersection=off
[6 Jul 2016 19:17]
Robert Mirabelle
I can confirm this bug is still present in 5.7
The following query, which should return a single row, returns empty:
Select record #100 from main table and perform an exists subquery:
SELECT *
FROM main_table
WHERE id = 100
AND EXISTS (
SELECT NULL FROM main_table t
LEFT OUTER JOIN subtable ON subtable.main_table_id = t.id
WHERE subtable.my_column= 10
AND t.id = main_table.id #scope to parent
)
In MySQL 5.5, the query works properly and a single row (id = 100) is returned.
In MySQL 5.7 the same query incorrectly returns no results.
This issue is caused/effected by the MySQL optimizer switch: index_merge_intersection.
If I change this setting to OFF:
SET optimizer_switch="index_merge_intersection=off";
the query then works as expected in 5.7
There are individual indexes on subtable.maint_table_id and subtable.my_column
EXPLAIN shows intersection of these 2 indexes. If I create an index hint:
LEFT OUTER JOIN subtable USE INDEX(main_table_id)
The intersection optimization disappears and the correct result is returned.
Also, If I change the outer WHERE from
WHERE id = 100
to
WHERE id BETWEEN 100 and 101
then the correct results are also returned.
[11 Oct 2016 12:33]
Yegor Strelkov
Hi! I'm also faced with this problem in 5.7 Steps to reproduce: CREATE TABLE `table1` ( `ID` bigint(20) NOT NULL, PRIMARY KEY (`ID`) ) ENGINE=InnoDB; CREATE TABLE `table2` ( `ID` bigint(20) NOT NULL, `c1` bigint(20) DEFAULT NULL, `c2` bigint(20) NOT NULL, PRIMARY KEY (`ID`), KEY `c1_INDEX` (`c1`), KEY `c2_INDEX` (`c2`) ) ENGINE=InnoDB; insert into table1 values (1),(2); insert into table2 values (1,1,20),(2,1,20),(3,1,30),(4,2,20),(5,2,20),(6,2,30); mysql> select * from table1 t1 where exists (select 1 from table2 t2 where t2.c2=30 and t2.c1=t1.ID); +----+ | ID | +----+ | 1 | | 2 | +----+ 2 rows in set (0.00 sec) But the following query which should return (1) returns empty set: mysql> select * from table1 t1 where t1.ID=1 and exists (select 1 from table2 t2 where t2.c2=30 and t2.c1=t1.ID); Empty set (0.00 sec) mysql> select version(); +-------------------------+ | version() | +-------------------------+ | 5.7.15-0ubuntu0.16.04.1 | +-------------------------+ 1 row in set (0.00 sec)
[11 Oct 2016 14:23]
MySQL Verification Team
Thanks Yegor Strelkov for the test case:
c:\dbs>c:\dbs\5.7\bin\mysql -uroot --port=3570 -p --prompt="mysql 5.7 > "
Enter password: ******
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 2
Server version: 5.7.17 Source distribution PULL: 2016-OCT-03
Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql 5.7 > CREATE DATABASE xbug
-> ;
Query OK, 1 row affected (0.02 sec)
mysql 5.7 > USE xbug
Database changed
mysql 5.7 > CREATE TABLE `table1` (
-> `ID` bigint(20) NOT NULL,
-> PRIMARY KEY (`ID`)
-> ) ENGINE=InnoDB;
Query OK, 0 rows affected (0.41 sec)
mysql 5.7 >
mysql 5.7 > CREATE TABLE `table2` (
-> `ID` bigint(20) NOT NULL,
-> `c1` bigint(20) DEFAULT NULL,
-> `c2` bigint(20) NOT NULL,
-> PRIMARY KEY (`ID`),
-> KEY `c1_INDEX` (`c1`),
-> KEY `c2_INDEX` (`c2`)
-> ) ENGINE=InnoDB;
Query OK, 0 rows affected (0.25 sec)
mysql 5.7 >
mysql 5.7 > insert into table1 values (1),(2);
Query OK, 2 rows affected (0.08 sec)
Records: 2 Duplicates: 0 Warnings: 0
mysql 5.7 > insert into table2 values (1,1,20),(2,1,20),(3,1,30),(4,2,20),(5,2,20),(6,2,30);
Query OK, 6 rows affected (0.11 sec)
Records: 6 Duplicates: 0 Warnings: 0
mysql 5.7 > select * from table1 t1 where exists (select 1 from table2 t2 where t2.c2=30 and t2.c1=t1.ID);
+----+
| ID |
+----+
| 1 |
| 2 |
+----+
2 rows in set (0.03 sec)
mysql 5.7 > select * from table1 t1 where t1.ID=1 and exists (select 1 from table2 t2 where t2.c2=30 and t2.c1=t1.ID);
Empty set (0.03 sec)
mysql 5.7 > SET optimizer_switch="index_merge_intersection=off";
Query OK, 0 rows affected (0.00 sec)
mysql 5.7 > select * from table1 t1 where t1.ID=1 and exists (select 1 from table2 t2 where t2.c2=30 and t2.c1=t1.ID);
+----+
| ID |
+----+
| 1 |
+----+
1 row in set (0.00 sec)
mysql 5.7 > SET optimizer_switch="index_merge_intersection=on";
Query OK, 0 rows affected (0.00 sec)
mysql 5.7 > select * from table1 t1 where t1.ID=1 and exists (select 1 from table2 t2 where t2.c2=30 and t2.c1=t1.ID);
Empty set (0.00 sec)
[11 Oct 2016 14:30]
MySQL Verification Team
Thank you for the bug report. With current source server I was able to repeat only with 5.7 server and not anymore with 5.6:
c:\dbs>c:\dbs\5.6\bin\mysql -uroot --port=3560 -p --prompt="mysql 5.6 > "
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 1
Server version: 5.6.35 Source distribution PULL: 2016-OCT-03
Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql 5.6 > CREATE DATABASE xbug;
Query OK, 1 row affected (0.00 sec)
mysql 5.6 > USE xbug
Database changed
mysql 5.6 > CREATE TABLE `table1` (
-> `ID` bigint(20) NOT NULL,
-> PRIMARY KEY (`ID`)
-> ) ENGINE=InnoDB;
Query OK, 0 rows affected (0.25 sec)
mysql 5.6 >
mysql 5.6 > CREATE TABLE `table2` (
-> `ID` bigint(20) NOT NULL,
-> `c1` bigint(20) DEFAULT NULL,
-> `c2` bigint(20) NOT NULL,
-> PRIMARY KEY (`ID`),
-> KEY `c1_INDEX` (`c1`),
-> KEY `c2_INDEX` (`c2`)
-> ) ENGINE=InnoDB;
Query OK, 0 rows affected (0.28 sec)
mysql 5.6 >
mysql 5.6 > insert into table1 values (1),(2);
Query OK, 2 rows affected (0.03 sec)
Records: 2 Duplicates: 0 Warnings: 0
mysql 5.6 > insert into table2 values (1,1,20),(2,1,20),(3,1,30),(4,2,20),(5,2,20),(6,2,30);
Query OK, 6 rows affected (0.08 sec)
Records: 6 Duplicates: 0 Warnings: 0
mysql 5.6 > select * from table1 t1 where exists (select 1 from table2 t2 where t2.c2=30 and t2.c1=t1.ID);
+----+
| ID |
+----+
| 1 |
| 2 |
+----+
2 rows in set (0.02 sec)
mysql 5.6 > select * from table1 t1 where t1.ID=1 and exists (select 1 from table2 t2 where t2.c2=30 and t2.c1=t1.ID);
+----+
| ID |
+----+
| 1 |
+----+
1 row in set (0.00 sec)
mysql 5.6 > SET optimizer_switch="index_merge_intersection=on";
Query OK, 0 rows affected (0.06 sec)
mysql 5.6 > select * from table1 t1 where t1.ID=1 and exists (select 1 from table2 t2 where t2.c2=30 and t2.c1=t1.ID);
+----+
| ID |
+----+
| 1 |
+----+
1 row in set (0.00 sec)
[11 Oct 2016 14:38]
MySQL Verification Team
Server version 8.0 affected too:
c:\dbs>c:\dbs\8.0\bin\mysql -uroot --port=3580 -p --prompt="mysql 8.0 > "
Enter password: ******
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 4
Server version: 8.0.0-dmr MySQL Community Server (GPL)
Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql 8.0 > CREATE DATABASE xbug;
Query OK, 1 row affected (0.07 sec)
mysql 8.0 > USE xbug
Database changed
mysql 8.0 > CREATE TABLE `table1` (
-> `ID` bigint(20) NOT NULL,
-> PRIMARY KEY (`ID`)
-> ) ENGINE=InnoDB;
Query OK, 0 rows affected (0.41 sec)
mysql 8.0 >
mysql 8.0 > CREATE TABLE `table2` (
-> `ID` bigint(20) NOT NULL,
-> `c1` bigint(20) DEFAULT NULL,
-> `c2` bigint(20) NOT NULL,
-> PRIMARY KEY (`ID`),
-> KEY `c1_INDEX` (`c1`),
-> KEY `c2_INDEX` (`c2`)
-> ) ENGINE=InnoDB;
Query OK, 0 rows affected (0.27 sec)
mysql 8.0 >
mysql 8.0 > insert into table1 values (1),(2);
Query OK, 2 rows affected (0.07 sec)
Records: 2 Duplicates: 0 Warnings: 0
mysql 8.0 > insert into table2 values (1,1,20),(2,1,20),(3,1,30),(4,2,20),(5,2,20),(6,2,30);
Query OK, 6 rows affected (0.04 sec)
Records: 6 Duplicates: 0 Warnings: 0
mysql 8.0 > select * from table1 t1 where exists (select 1 from table2 t2 where t2.c2=30 and t2.c1=t1.ID);
+----+
| ID |
+----+
| 1 |
| 2 |
+----+
2 rows in set (0.02 sec)
mysql 8.0 > select * from table1 t1 where t1.ID=1 and exists (select 1 from table2 t2 where t2.c2=30 and t2.c1=t1.ID);
Empty set (0.02 sec)
mysql 8.0 > SET optimizer_switch="index_merge_intersection=off";
Query OK, 0 rows affected (0.00 sec)
mysql 8.0 > select * from table1 t1 where t1.ID=1 and exists (select 1 from table2 t2 where t2.c2=30 and t2.c1=t1.ID);
+----+
| ID |
+----+
| 1 |
+----+
1 row in set (0.00 sec)
[19 May 2017 18:43]
Paul DuBois
Posted by developer: Noted in 5.7.19, 8.0.2 changelog. Certain queries against InnoDB tables that used a primary key and a subquery could return incorrect results if the index_merge_intersection flag of the optimization_switch system variable was enabled.
[28 Jun 2019 19:42]
Chris Muench
This exists in 5.6; will this be patched?
