Bug #15106 EXPLAIN output differs for almost same query
Submitted: 21 Nov 2005 19:32 Modified: 21 Dec 2005 10:44
Reporter: Shane Bester (Platinum Quality Contributor) Email Updates:
Status: Closed Impact on me:
None 
Category:MySQL Server: Optimizer Severity:S3 (Non-critical)
Version:5.0.15, 5.0.17-bk OS:Linux (Linux, Windows)
Assigned to: Igor Babaev CPU Architecture:Any

[21 Nov 2005 19:32] Shane Bester
Description:
Given the same query, with subtle difference, EXPLAIN output is different. Only thing that changed is the order of operands for the equal sign in the join. e.g.
t1.id=t2.id instead of t2.id=t1.id

This problem exists on 5.0.15-nt and todays 5.0.17-bk on linux.
4.1.14-nt had correct behaviour, with both EXPLAIN outputs being identical.
No difference whether the tables are InnoDB/MyISAM.

/*BAD*/
mysql> EXPLAIN SELECT * FROM
    -> t1 JOIN t2
    -> ON
    -> t2.c1 = t1.c2
    -> JOIN t3 ON
    -> t3.c1 = t2.c1
    -> WHERE
    -> t1.c2 = '1'\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: t1
         type: ALL
possible_keys: idx1,idx2
          key: NULL <------------------See here. Didn't use an index
      key_len: NULL
          ref: NULL
         rows: 10
        Extra:
*************************** 2. row ***************************
           id: 1
  select_type: SIMPLE
        table: t2
         type: ref
possible_keys: PRIMARY
          key: PRIMARY
      key_len: 1
          ref: test.t1.c2
         rows: 1
        Extra: Using index
*************************** 3. row ***************************
           id: 1
  select_type: SIMPLE
        table: t3
         type: ref
possible_keys: PRIMARY
          key: PRIMARY
      key_len: 1
          ref: test.t1.c2
         rows: 1
        Extra: Using index
3 rows in set (0.00 sec)

/*GOOD*/
mysql> EXPLAIN SELECT * FROM
    -> t1 JOIN t2
    -> ON
    -> t1.c2 = t2.c1
    -> JOIN t3 ON
    -> t3.c1 = t2.c1
    -> WHERE
    -> t1.c2 = '1'\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: t1
         type: ref
possible_keys: idx1,idx2
          key: idx1<------------------See here. Uses an index
      key_len: 1
          ref: const
         rows: 1
        Extra: Using where
*************************** 2. row ***************************
           id: 1
  select_type: SIMPLE
        table: t2
         type: ref
possible_keys: PRIMARY
          key: PRIMARY
      key_len: 1
          ref: const
         rows: 1
        Extra: Using where; Using index
*************************** 3. row ***************************
           id: 1
  select_type: SIMPLE
        table: t3
         type: ref
possible_keys: PRIMARY
          key: PRIMARY
      key_len: 1
          ref: const
         rows: 1
        Extra: Using where; Using index
3 rows in set (0.00 sec)

mysql>

How to repeat:
Cut'n paste the below SQL, and examine the last two EXPLAIN outputs for table t1.
---------------------

DROP TABLE IF EXISTS `t1`;
CREATE TABLE `t1` (
  `c1` char(6) NOT NULL default '',
  `c2` char(1) NOT NULL default '',
  `c3` char(6) NOT NULL default '',
  `c4` int(11) default '0',
  `c5` date default NULL,
  `c6` tinyint(4) default NULL,
  PRIMARY KEY  (`c1`,`c2`,`c3`),
  KEY `idx1` (`c2`,`c5`,`c6`),
  KEY `idx2` (`c2`,`c4`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

INSERT INTO `t1` VALUES ('6Cc6C','B','HB',4469598,'1900-01-21',0),('79','5','r',-1460837217,'1952-12-31',-32),('a67cZ','L','rA8',-30263936,'1931-12-25',20),('b5b','g','N2',-192787920,'1928-02-04',-121),('FY','u','kC3',1897465773,'1956-07-10',-14),('g8I','l','mzb',38226,'1859-08-31',-60),('jjs','0','6gE',-12666654,'1845-09-19',50),('ml','D','RupR',1801032310,'1971-06-09',3),('Pv9','Q','puZ',1471135022,'1997-06-10',-20),('y9b7','Y','bj2a',158672415,'1902-05-27',48);

DROP TABLE IF EXISTS `t2`;
CREATE TABLE `t2` (
  `c1` char(1) NOT NULL default '',
  `c2` char(6) NOT NULL default '',
  `c3` char(6) NOT NULL default '',
  `c4` char(6) NOT NULL default '',
  PRIMARY KEY  (`c1`,`c2`,`c3`,`c4`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

INSERT INTO `t2` VALUES ('5','FFdo','P8','0m'),('8','r7','8is','PF'),('k','7o','OtI','c'),('k','Ql7vg','Q','hA'),('L','7','z1Dc','TAwR'),('L','Y','vn','nh7Z'),('n','ya55','ET3','Azj'),('Q','D','7oT','gw'),('R','5C','j','1i'),('u','T0BSXU','oQC84S','lx');

DROP TABLE IF EXISTS `t3`;
CREATE TABLE `t3` (
  `c1` char(1) NOT NULL default '',
  `c2` char(6) NOT NULL default '',
  `c3` char(6) NOT NULL default '',
  `c4` char(3) NOT NULL default '',
  `c5` char(6) NOT NULL default '',
  PRIMARY KEY  (`c1`,`c2`,`c3`,`c4`,`c5`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

INSERT INTO `t3` VALUES ('7','Xplh','lnB','7','Au'),('h','iMCp','sJ','j','Fr'),('I','mIbp','PiAr','L','mzqG'),('j','SQZ','N','7','rjGG'),('m','VFn','fCg','v','9P'),('P','cs','fYz','U','mhq8'),('p','iQV','GmZtu7','W','lzYiK'),('Q','Rev','dn','NVn','lR'),('S','di','p','BM','C0b'),('Y','FwHri','qsm','Si','yrb');

EXPLAIN SELECT * FROM
t1 JOIN t2
ON
t2.c1 = t1.c2 
JOIN t3 ON
t3.c1 = t2.c1
WHERE
t1.c2 = '1'\G

EXPLAIN SELECT * FROM
t1 JOIN t2
ON
t1.c2 = t2.c1
JOIN t3 ON
t3.c1 = t2.c1
WHERE
t1.c2 = '1'\G

-------------

Suggested fix:
not sure...
[22 Nov 2005 0:17] Hartmut Holzgraefe
verified, i also get different result sets:

mysql> SELECT * FROM t1 JOIN t2 ON t2.c1 = t1.c2  JOIN t3 ON t3.c1 = t2.c1 WHERE t1.c2 = '1';
+-----+----+-----+------------+------------+------+----+----+-----+----+----+-----+----+-----+----+
| c1  | c2 | c3  | c4         | c5         | c6   | c1 | c2 | c3  | c4 | c1 | c2  | c3 | c4  | c5 |
+-----+----+-----+------------+------------+------+----+----+-----+----+----+-----+----+-----+----+
| Pv9 | Q  | puZ | 1471135022 | 1997-06-10 |  -20 | Q  | D  | 7oT | gw | Q  | Rev | dn | NVn | lR |
+-----+----+-----+------------+------------+------+----+----+-----+----+----+-----+----+-----+----+
1 row in set (0.00 sec)

mysql> SELECT * FROM t1 JOIN t2 ON t1.c2 = t2.c1 JOIN t3 ON t3.c1 = t2.c1 WHERE t1.c2 = '1';
Empty set (0.00 sec)
[24 Nov 2005 23:01] Connor Harty
In regards to the comment above, the column used in the join would appear to be optimized away:
SELECT t1.* FROM t1 JOIN t2 ON t2.c1 = t1.c2  JOIN t3 ON t3.c1 = t2.c1 where t1.c1 = 'PV9' and t1.c2='I feel ignored';
+-----+----+-----+------------+------------+------+
| c1  | c2 | c3  | c4         | c5         | c6   |
+-----+----+-----+------------+------------+------+
| Pv9 | Q  | puZ | 1471135022 | 1997-06-10 |  -20 |
+-----+----+-----+------------+------------+------+
While 
SELECT t1.* FROM t1 JOIN t2 ON t2.c1 = t1.c2  JOIN t3 ON t3.c1 = t2.c1 where t1.c1 = 'Not me' and t1.c2='Q';
yields:
Empty set (0.00 sec)

Another example:
DROP TABLE IF EXISTS `a`;
CREATE table a (key_a int4 not null, optimus varchar(32), PRIMARY KEY(key_a));
INSERT INTO a VALUES (0,'');
INSERT INTO a VALUES (1,'i');
INSERT INTO a VALUES (2,'j');
INSERT INTO a VALUES (3,'k');

DROP TABLE IF EXISTS `aprime`;
CREATE table aprime (key_a int4 not null, prime varchar(32), PRIMARY KEY(key_a));
INSERT INTO aprime VALUES (1,'r');
INSERT INTO aprime VALUES (2,'s');
INSERT INTO aprime VALUES (3,'t');

DROP TABLE IF EXISTS `b`;
CREATE table b (key_a int4 not null, key_b int4 not null, foo varchar(32)  , PRIMARY KEY(key_a,key_b));
INSERT INTO b VALUES (1,5,'x');
INSERT INTO b VALUES (1,6,'y');
INSERT INTO b VALUES (2,5,'xx');
INSERT INTO b VALUES (2,6,'yy');
INSERT INTO b VALUES (2,7,'zz');
INSERT INTO b VALUES (3,5,'xxx');

SELECT aprime.key_a,foo 
FROM   a inner join aprime on a.key_a = aprime.key_a
         inner join b      on a.key_a = b.key_a   WHERE aprime.key_a = 2 and key_b=5;
gives:
+-------+------+
| key_a | foo  |
+-------+------+
|     1 | x    |
|     2 | xx   |
|     3 | xxx  |
+-------+------+

EXPLAIN: 
+----+-------------+--------+--------+---------------+---------+---------+-----------------------------+------+--------------------------+
| id | select_type | table  | type   | possible_keys | key     | key_len | ref                         | rows | Extra                    |
+----+-------------+--------+--------+---------------+---------+---------+-----------------------------+------+--------------------------+
|  1 | SIMPLE      | a      | index  | PRIMARY       | PRIMARY | 4       | NULL                        |    4 | Using index              |
|  1 | SIMPLE      | b      | eq_ref | PRIMARY       | PRIMARY | 8       | mysql_bugtest.a.key_a,const |    1 |                          |
|  1 | SIMPLE      | aprime | index  | PRIMARY       | PRIMARY | 4       | NULL                        |    3 | Using where; Using index |
+----+-------------+--------+--------+---------------+---------+---------+-----------------------------+------+--------------------------+

while:

SELECT aprime.key_a,foo 
FROM   a inner join aprime on aprime.key_a = a.key_a
         inner join b      on a.key_a = b.key_a   WHERE aprime.key_a = 2 and key_b=5;
gives:
+-------+------+
| key_a | foo  |
+-------+------+
|     2 | xx   |
+-------+------+

EXPLAIN:
+----+-------------+--------+-------+---------------+---------+---------+-------------+------+-------------+
| id | select_type | table  | type  | possible_keys | key     | key_len | ref         | rows | Extra       |
+----+-------------+--------+-------+---------------+---------+---------+-------------+------+-------------+
|  1 | SIMPLE      | a      | const | PRIMARY       | PRIMARY | 4       | const       |    1 | Using index |
|  1 | SIMPLE      | aprime | const | PRIMARY       | PRIMARY | 4       | const       |    1 | Using index |
|  1 | SIMPLE      | b      | const | PRIMARY       | PRIMARY | 8       | const,const |    1 |             |
+----+-------------+--------+-------+---------------+---------+---------+-------------+------+-------------+
[26 Nov 2005 2:52] Bugs System
A patch for this bug has been committed. After review, it may
be pushed to the relevant source trees for release in the next
version. You can access the patch from:

  http://lists.mysql.com/internals/32731
[12 Dec 2005 6:43] Igor Babaev
ChangeSet
  1.2012 05/11/25 18:51:44 igor@rurik.mysql.com +3 -0
  Fixed bug #15106.
  A typo bug caused loss of a predicate of the form field=const in some cases.

  sql/item_cmpfunc.cc
    1.186 05/11/25 18:51:39 igor@rurik.mysql.com +1 -1
    Fixed bug #15106.
    A typo bug caused loss of a predicate of the form field=const in some cases.

  mysql-test/t/select.test
    1.93 05/11/25 18:51:39 igor@rurik.mysql.com +45 -0
    Added a test case for bug #15106.

  mysql-test/r/select.result
    1.114 05/11/25 18:51:39 igor@rurik.mysql.com +46 -0
    Added a test case for bug #15106.

The fix will appear in 5.0.18.
[21 Dec 2005 10:44] Jon Stephens
Thank you for your bug report. This issue has been committed to our
source repository of that product and will be incorporated into the
next release.

If necessary, you can access the source repository and build the latest
available version, including the bugfix, yourself. More information 
about accessing the source trees is available at
    http://www.mysql.com/doc/en/Installing_source_tree.html

Additional info:

Documented in 5.0.18 changelog. Closed.