Bug #70588 Index merge used on partitionned table can return wrong result set
Submitted: 10 Oct 2013 12:09 Modified: 5 Nov 2013 17:05
Reporter: Joffrey MICHAIE Email Updates:
Status: Closed Impact on me:
None 
Category: Server: Partition Severity: S2 (Serious)
Version: 5.6.14,5.5 OS: Any
Assigned to: Target Version:
Tags: index merge, intersect, partition, wrong resultset
Triage: Needs Triage: D2 (Serious)
ViewAdd CommentFilesDeveloperEdit SubmissionView Progress LogContributions
[10 Oct 2013 12:09] Joffrey MICHAIE
Description:
Simple query where 
indexed_col = 'x' and indexed_date_column = 'yyyy-mm-aa'
 returns wrong resultset, when run on partitionned table, and using index_merge (indexed_col,indexed_date_column)
Found on 5.5, repeated on 5.6.14, didn't test on 5.1
How to repeat:
Start MySQL with 100% default settings.
CREATE TABLE `poll` (
  `id_key` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `id` int(6) NOT NULL DEFAULT '0',
  `id_poll` int(6) NOT NULL DEFAULT '0',
  `date_long` datetime NOT NULL,
  `date_short` date NOT NULL,
  PRIMARY KEY (`id_key`,`id_poll`),
  KEY `id` (`id`),
  KEY `date_creation` (`date_short`)
) ENGINE=InnoDB AUTO_INCREMENT=14101389 DEFAULT CHARSET=latin1
/*!50100 PARTITION BY HASH (id_poll)
PARTITIONS 20 */;
INSERT INTO `poll` VALUES (NULL,1718848,580660,'2013-10-09 18:21:00','2013-10-09');
INSERT INTO `poll` VALUES (NULL,39369,869049,'2013-10-09 18:21:02','2013-10-09');
INSERT INTO `poll` VALUES (NULL,70,1916580,'2013-10-09 18:21:09','2013-10-09');
INSERT INTO `poll` VALUES (NULL,70,1333222,'2013-10-09 18:20:31','2013-10-09');
INSERT INTO `poll` VALUES (NULL,1557405,869555,'2013-10-09 18:20:32','2013-10-09');
INSERT INTO `poll` VALUES (NULL,70,1343938,'2013-10-09 18:20:32','2013-10-09');
INSERT INTO `poll` VALUES (NULL,70,1157259,'2013-10-09 18:20:40','2013-10-09');
INSERT INTO `poll` VALUES (NULL,70,1800441,'2013-10-09 18:20:50','2013-10-09');
INSERT INTO `poll` VALUES (NULL,70,60,'2013-10-09 18:20:53','2013-10-09');
INSERT INTO `poll` VALUES (NULL,1718848,580660,'2013-10-09 18:21:00','2013-10-09');
INSERT INTO `poll` VALUES (NULL,39369,869049,'2013-10-09 18:21:02','2013-10-09');
INSERT INTO `poll` VALUES (NULL,70,1916580,'2013-10-09 18:21:09','2013-10-09');
INSERT INTO `poll` VALUES (NULL,70,1916580,'2013-10-0Query OK, 1 row affected (0,01 sec)
explain SELECT date_short FROM poll WHERE id =70 AND date_short =  '2013-10-10';                                                                                                                                                      +----+-------------+-------+-------------+------------------+------------------+---------+------+------+-------------------------------------------------------------+
| id | select_type | table | type        | possible_keys    | key              | key_len | ref  | rows | Extra                                                       |
+----+-------------+-------+-------------+------------------+------------------+---------+------+------+-------------------------------------------------------------+
|  1 | SIMPLE      | poll  | index_merge | id,date_creation | date_creation,id | 3,4     | NULL |    2 | Using intersect(date_creation,id); Using where; Using index |
+----+-------------+-------+-------------+------------------+------------------+---------+------+------+-------------------------------------------------------------+
1 row in set (0,00 sec)
(data sample is small, you can run ANALYZE TABLE if intersect is not shown)
mysql>  SELECT date_short FROM poll WHERE id =70 AND date_short =  '2013-10-10';
Empty set (0,01 sec)
mysql>  SELECT date_short FROM poll WHERE id =70 AND date_short like  '2013-10-10';
+------------+
| date_short |
+------------+
| 2013-10-10 |
+------------+
1 row in set (0,00 sec)
Other examples:
mysql>  SELECT date_short FROM poll IGNORE INDEX (date_creation) WHERE id =70 AND date_short =  '2013-10-10';
+------------+
| date_short |
+------------+
| 2013-10-10 |
+------------+
1 row in set (0,00 sec)
mysql>  SELECT date_short FROM poll IGNORE INDEX (id) WHERE id =70 AND date_short =  '2013-10-10';
+------------+
| date_short |
+------------+
| 2013-10-10 |
+------------+
1 row in set (0,00 sec)
mysql> alter table poll remove partitioning;
Query OK, 13 rows affected (0,08 sec)
Records: 13  Duplicates: 0  Warnings: 0
mysql>  SELECT date_short FROM poll WHERE id =70 AND date_short =  '2013-10-10';
+------------+
| date_short |
+------------+
| 2013-10-10 |
+------------+
1 row in set (0,00 sec)
Suggested fix:
Return correct resultset, or do not use intersection merge on hash partitionned tables
[10 Oct 2013 12:30] Miguel Solorzano
Thank you for the bug report.
C:\dbs>c:\dbs\5.6\bin\mysql -uroot --port=3560 --prompt="mysql 5.6 > "
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 3
Server version: 5.6.15 Source distribution
Copyright (c) 2000, 2013, 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 > use xd
Database changed
mysql 5.6 > CREATE TABLE `poll` (
    ->   `id_key` int(10) unsigned NOT NULL AUTO_INCREMENT,
    ->   `id` int(6) NOT NULL DEFAULT '0',
    ->   `id_poll` int(6) NOT NULL DEFAULT '0',
    ->   `date_long` datetime NOT NULL,
    ->   `date_short` date NOT NULL,
    ->   PRIMARY KEY (`id_key`,`id_poll`),
    ->   KEY `id` (`id`),
    ->   KEY `date_creation` (`date_short`)
    -> ) ENGINE=InnoDB AUTO_INCREMENT=14101389 DEFAULT CHARSET=latin1
    -> /*!50100 PARTITION BY HASH (id_poll)
    -> PARTITIONS 20 */;
Query OK, 0 rows affected (4.76 sec)
mysql 5.6 >
mysql 5.6 > INSERT INTO `poll` VALUES (NULL,1718848,580660,'2013-10-09 18:21:00','2013-10-09');
Query OK, 1 row affected (0.20 sec)
<CUT>
mysql 5.6 > SELECT date_short FROM poll WHERE id =70 AND date_short =  '2013-10-10';
Empty set (0.00 sec)
mysql 5.6 > alter table poll remove partitioning;
Query OK, 13 rows affected (3.76 sec)
Records: 13  Duplicates: 0  Warnings: 0
mysql 5.6 > SELECT date_short FROM poll WHERE id =70 AND date_short =  '2013-10-10';
+------------+
| date_short |
+------------+
| 2013-10-10 |
+------------+
1 row in set (0.02 sec)
mysql 5.6 >
[10 Oct 2013 12:55] Joffrey MICHAIE
From:
http://dev.mysql.com/doc/relnotes/mysql/5.6/en/news-5-6-14.html
For partitioned tables, queries could return different results depending on whether Index Merge was used. (Bug #16862316)
[5 Nov 2013 17:05] Jonathan Stephens
Fixed in 5.5+. Documented in the 5.5.36, 5.6.16, and 5.7.4 changelogs, as follows:
      Queries using index_merge optimization (see 
      http://dev.mysql.com/doc/refman/5.5/en/index-merge-optimization.html) 
      could return invalid results when run against tables that were 
      partitioned by HASH. 
Closed.
[2 Feb 17:20] Laurynas Biveinis
5.5$ bzr log -r 4538
------------------------------------------------------------
revno: 4538
committer: Aditya A <aditya.a@oracle.com>
branch nick: mysql-5.5
timestamp: Tue 2013-11-05 19:25:26 +0530
message:
  Bug#17588348: INDEX MERGE USED ON PARTITIONED TABLE 
                 CAN RETURN WRONG RESULT SET
  
  PROBLEM
  -------
  In ha_partition::cmp_ref() we were only calling the 
  underlying cmp_ref() of storage engine if the records
  are in the same partiton,else we sort by partition and
  returns the result.But the index merge intersect 
  algorithm expects first to sort by row-id first and 
  then by partition id.
  
  FIX
  ---
  Compare the refernces first using storage engine cmp_ref
  and then if references are equal(only happens if 
  non clustered index is used) then sort it by partition id.
  
  [Approved by Mattiasj #rb3755]
  -