Bug #75121 | IN clause subquery optimization | ||
---|---|---|---|
Submitted: | 5 Dec 2014 18:25 | Modified: | 5 Dec 2014 21:42 |
Reporter: | Raghbir Banwait | Email Updates: | |
Status: | Verified | Impact on me: | |
Category: | MySQL Server: Optimizer | Severity: | S2 (Serious) |
Version: | 5.6.21 | OS: | Linux (CentOS 5.11) |
Assigned to: | CPU Architecture: | Any | |
Tags: | regression |
[5 Dec 2014 18:25]
Raghbir Banwait
[5 Dec 2014 21:35]
MySQL Verification Team
mysql 5.6 > SELECT * FROM a WHERE a.f = 'B' AND a.id IN (SELECT a_id FROM b WHERE b.f = 'B' AND DATE(ts) > (DATE(SYSDATE()) - INTERVAL 30 DAY)); +----+---+ | id | f | +----+---+ | 4 | B | | 6 | B | | 8 | B | | 14 | B | | 16 | B | | 18 | B | | 24 | B | | 26 | B | | 28 | B | +----+---+ 9 rows in set (0.05 sec) mysql 5.6 > mysql 5.6 > SELECT * FROM a WHERE a.f = 'B' AND EXISTS (SELECT a_id FROM b WHERE b.f = 'B' AND DATE(ts) > (DATE(SYSDATE()) - INTERVAL 30 DAY) AND b.a_id = a.id); +----+---+ | id | f | +----+---+ | 4 | B | | 6 | B | | 8 | B | | 14 | B | | 16 | B | | 18 | B | | 24 | B | | 26 | B | | 28 | B | +----+---+ 9 rows in set (0.00 sec) mysql 5.6 > mysql 5.6 > SELECT * FROM a USE INDEX (PRIMARY) WHERE a.f = 'B' AND a.id IN (SELECT a_id FROM b WHERE b.f = 'B' AND DATE(ts) > (DATE(SYSDATE()) - INTERVAL 30 DAY)); +----+---+ | id | f | +----+---+ | 4 | B | | 6 | B | | 8 | B | | 10 | B | | 12 | B | | 14 | B | | 16 | B | | 18 | B | | 20 | B | | 22 | B | | 24 | B | | 26 | B | | 28 | B | | 30 | B | +----+---+ 14 rows in set (0.00 sec) mysql 5.6 > mysql 5.6 > SELECT * FROM a USE INDEX (IDX_A_F) WHERE a.f = 'B' AND EXISTS (SELECT a_id FROM b WHERE b.f = 'B' AND DATE(ts) > (DATE(SYSDATE()) - INTERVAL 30 DAY) AND b.a_id = a.id); +----+---+ | id | f | +----+---+ | 4 | B | | 6 | B | | 8 | B | | 14 | B | | 16 | B | | 18 | B | | 24 | B | | 26 | B | | 28 | B | +----+---+ 9 rows in set (0.00 sec) mysql 5.6 > SHOW VARIABLES LIKE "%VERSION%"; +-------------------------+--------------------------------+ | Variable_name | Value | +-------------------------+--------------------------------+ | innodb_version | 5.6.23 | | protocol_version | 10 | | slave_type_conversions | | | version | 5.6.23 | | version_comment | Source distribution 2014.12.02 | | version_compile_machine | x86_64 | | version_compile_os | Win64 | +-------------------------+--------------------------------+ 7 rows in set (0.00 sec) *************************************************5.0************************************************************ mysql 5.0 > SELECT * FROM a WHERE a.f = 'B' AND a.id IN (SELECT a_id FROM b WHERE b.f = 'B' AND DATE(ts) > (DATE(SYSDATE()) - INTERVAL 30 DAY)); +----+---+ | id | f | +----+---+ | 4 | B | | 6 | B | | 8 | B | | 14 | B | | 16 | B | | 18 | B | | 24 | B | | 26 | B | | 28 | B | +----+---+ 9 rows in set (0.00 sec) mysql 5.0 > mysql 5.0 > SELECT * FROM a WHERE a.f = 'B' AND EXISTS (SELECT a_id FROM b WHERE b.f = 'B' AND DATE(ts) > (DATE(SYSDATE()) - INTERVAL 30 DAY) AND b.a_id = a.id); +----+---+ | id | f | +----+---+ | 4 | B | | 6 | B | | 8 | B | | 14 | B | | 16 | B | | 18 | B | | 24 | B | | 26 | B | | 28 | B | +----+---+ 9 rows in set (0.00 sec) mysql 5.0 > mysql 5.0 > SELECT * FROM a USE INDEX (PRIMARY) WHERE a.f = 'B' AND a.id IN (SELECT a_id FROM b WHERE b.f = 'B' AND DATE(ts) > (DATE(SYSDATE()) - INTERVAL 30 DAY)); +----+---+ | id | f | +----+---+ | 4 | B | | 6 | B | | 8 | B | | 14 | B | | 16 | B | | 18 | B | | 24 | B | | 26 | B | | 28 | B | +----+---+ 9 rows in set (0.00 sec) mysql 5.0 > mysql 5.0 > SELECT * FROM a USE INDEX (IDX_A_F) WHERE a.f = 'B' AND EXISTS (SELECT a_id FROM b WHERE b.f = 'B' AND DATE(ts) > (DATE(SYSDATE()) - INTERVAL 30 DAY) AND b.a_id = a.id); +----+---+ | id | f | +----+---+ | 4 | B | | 6 | B | | 8 | B | | 14 | B | | 16 | B | | 18 | B | | 24 | B | | 26 | B | | 28 | B | +----+---+ 9 rows in set (0.00 sec) mysql 5.0 > SHOW VARIABLES LIKE "%VERSION%"; +-------------------------+---------------------+ | Variable_name | Value | +-------------------------+---------------------+ | protocol_version | 10 | | version | 5.0.97-Win X64 | | version_comment | Source distribution | | version_compile_machine | unknown | | version_compile_os | Win64 | +-------------------------+---------------------+ 5 rows in set (0.00 sec) mysql 5.0 >
[5 Dec 2014 21:38]
MySQL Verification Team
mysql 5.5 > SELECT * FROM a WHERE a.f = 'B' AND a.id IN (SELECT a_id FROM b WHERE b.f = 'B' AND DATE(ts) > (DATE(SYSDATE()) - INTERVAL 30 DAY)); +----+---+ | id | f | +----+---+ | 4 | B | | 6 | B | | 8 | B | | 14 | B | | 16 | B | | 18 | B | | 24 | B | | 26 | B | | 28 | B | +----+---+ 9 rows in set (0.01 sec) mysql 5.5 > mysql 5.5 > SELECT * FROM a WHERE a.f = 'B' AND EXISTS (SELECT a_id FROM b WHERE b.f = 'B' AND DATE(ts) > (DATE(SYSDATE()) - INTERVAL 30 DAY) AND b.a_id = a.id); +----+---+ | id | f | +----+---+ | 4 | B | | 6 | B | | 8 | B | | 14 | B | | 16 | B | | 18 | B | | 24 | B | | 26 | B | | 28 | B | +----+---+ 9 rows in set (0.00 sec) mysql 5.5 > mysql 5.5 > SELECT * FROM a USE INDEX (PRIMARY) WHERE a.f = 'B' AND a.id IN (SELECT a_id FROM b WHERE b.f = 'B' AND DATE(ts) > (DATE(SYSDATE()) - INTERVAL 30 DAY)); +----+---+ | id | f | +----+---+ | 4 | B | | 6 | B | | 8 | B | | 14 | B | | 16 | B | | 18 | B | | 24 | B | | 26 | B | | 28 | B | +----+---+ 9 rows in set (0.00 sec) mysql 5.5 > mysql 5.5 > SELECT * FROM a USE INDEX (IDX_A_F) WHERE a.f = 'B' AND EXISTS (SELECT a_id FROM b WHERE b.f = 'B' AND DATE(ts) > (DATE(SYSDATE()) - INTERVAL 30 DAY) AND b.a_id = a.id); +----+---+ | id | f | +----+---+ | 4 | B | | 6 | B | | 8 | B | | 14 | B | | 16 | B | | 18 | B | | 24 | B | | 26 | B | | 28 | B | +----+---+ 9 rows in set (0.02 sec) mysql 5.5 > SHOW VARIABLES LIKE "%VERSION%"; +-------------------------+--------------------------------+ | Variable_name | Value | +-------------------------+--------------------------------+ | innodb_version | 5.5.42 | | protocol_version | 10 | | slave_type_conversions | | | version | 5.5.42 | | version_comment | Source distribution 2014.12.02 | | version_compile_machine | AMD64 | | version_compile_os | Win64 | +-------------------------+--------------------------------+ 7 rows in set (0.00 sec)
[5 Dec 2014 21:42]
MySQL Verification Team
Thank you for the bug report. Only 5.6 server affected. mysql 5.7 > SELECT * FROM a WHERE a.f = 'B' AND a.id IN (SELECT a_id FROM b WHERE b.f = 'B' AND DATE(ts) > (DATE(SYSDATE()) - INTERVAL 30 DAY)); +----+---+ | id | f | +----+---+ | 4 | B | | 6 | B | | 8 | B | | 14 | B | | 16 | B | | 18 | B | | 24 | B | | 26 | B | | 28 | B | +----+---+ 9 rows in set (0.01 sec) mysql 5.7 > mysql 5.7 > SELECT * FROM a WHERE a.f = 'B' AND EXISTS (SELECT a_id FROM b WHERE b.f = 'B' AND DATE(ts) > (DATE(SYSDATE()) - INTERVAL 30 DAY) AND b.a_id = a.id); +----+---+ | id | f | +----+---+ | 4 | B | | 6 | B | | 8 | B | | 14 | B | | 16 | B | | 18 | B | | 24 | B | | 26 | B | | 28 | B | +----+---+ 9 rows in set (0.00 sec) mysql 5.7 > mysql 5.7 > SELECT * FROM a USE INDEX (PRIMARY) WHERE a.f = 'B' AND a.id IN (SELECT a_id FROM b WHERE b.f = 'B' AND DATE(ts) > (DATE(SYSDATE()) - INTERVAL 30 DAY)); +----+---+ | id | f | +----+---+ | 4 | B | | 6 | B | | 8 | B | | 14 | B | | 16 | B | | 18 | B | | 24 | B | | 26 | B | | 28 | B | +----+---+ 9 rows in set (0.00 sec) mysql 5.7 > mysql 5.7 > SELECT * FROM a USE INDEX (IDX_A_F) WHERE a.f = 'B' AND EXISTS (SELECT a_id FROM b WHERE b.f = 'B' AND DATE(ts) > (DATE(SYSDATE()) - INTERVAL 30 DAY) AND b.a_id = a.id); +----+---+ | id | f | +----+---+ | 4 | B | | 6 | B | | 8 | B | | 14 | B | | 16 | B | | 18 | B | | 24 | B | | 26 | B | | 28 | B | +----+---+ 9 rows in set (0.00 sec) mysql 5.7 > SHOW VARIABLES LIKE "%VERSION%"; +-------------------------+--------------------------------+ | Variable_name | Value | +-------------------------+--------------------------------+ | innodb_version | 5.7.6 | | protocol_version | 10 | | slave_type_conversions | | | version | 5.7.6-m16 | | version_comment | Source distribution 2014.12.02 | | version_compile_machine | x86_64 | | version_compile_os | Win64 | +-------------------------+--------------------------------+ 7 rows in set (0.00 sec)
[8 Dec 2014 8:26]
Øystein Grøvlen
Query that gives wrong result uses semijoin materialization: mysql> EXPLAIN SELECT * FROM a USE INDEX (PRIMARY) WHERE a.f = 'B' AND a.id IN (SELECT a_id FROM b WHERE b.f = 'B' AND DATE(ts) > (DATE(SYSDATE()) - INTERVAL 30 DAY)); +----+--------------+-------------+--------+---------------+------------+---------+------------------+------+-----------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+--------------+-------------+--------+---------------+------------+---------+------------------+------+-----------------------+ | 1 | SIMPLE | a | ALL | PRIMARY | NULL | NULL | NULL | 30 | Using where | | 1 | SIMPLE | <subquery2> | eq_ref | <auto_key> | <auto_key> | 5 | bug20164684.a.id | 1 | NULL | | 2 | MATERIALIZED | b | ref | B_FK,IDX_B_F | IDX_B_F | 3 | const | 28 | Using index condition | +----+--------------+-------------+--------+---------------+------------+---------+------------------+------+-----------------------+ 3 rows in set (0.00 sec) After turning off materialization, query gives the correct result: mysql> set optimizer_switch='materialization=off'; Query OK, 0 rows affected (0.00 sec) mysql> EXPLAIN SELECT * FROM a USE INDEX (PRIMARY) WHERE a.f = 'B' AND a.id IN (SELECT a_id FROM b WHERE b.f = 'B' AND DATE(ts) > (DATE(SYSDATE()) - INTERVAL 30 DAY)); +----+-------------+-------+------+---------------+------+---------+------------------+------+----------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+------+---------------+------+---------+------------------+------+----------------------------+ | 1 | SIMPLE | a | ALL | PRIMARY | NULL | NULL | NULL | 30 | Using where | | 1 | SIMPLE | b | ref | B_FK,IDX_B_F | B_FK | 5 | bug20164684.a.id | 1 | Using where; FirstMatch(a) | +----+-------------+-------+------+---------------+------+---------+------------------+------+----------------------------+ 2 rows in set (0.00 sec) mysql> SELECT * FROM a USE INDEX (PRIMARY) WHERE a.f = 'B' AND a.id IN (SELECT a_id FROM b WHERE b.f = 'B' AND DATE(ts) > (DATE(SYSDATE()) - INTERVAL 30 DAY)); +----+---+ | id | f | +----+---+ | 4 | B | | 6 | B | | 8 | B | | 14 | B | | 16 | B | | 18 | B | | 24 | B | | 26 | B | | 28 | B | +----+---+ 9 rows in set (0.00 sec)