Description:
In some even not so complicated cases Index Merge optimization is not used. For example:
mysql> CREATE TABLE tmerge2 (
-> `c1` int(11) NOT NULL auto_increment,
-> `c2` decimal(10,0) default NULL,
-> `c3` decimal(10,0) default NULL,
-> `c4` decimal(10,0) default NULL,
-> `c5` decimal(10,0) default NULL,
-> `cp` decimal(1,0) default NULL,
-> `ce` decimal(10,0) default NULL,
-> `cdata` char(20),
-> PRIMARY KEY (`c1`),
-> KEY `k1` (`c2`,`c3`,`cp`,`ce`),
-> KEY `k2` (`c4`,`c5`,`cp`,`ce`)
-> ) ENGINE=InnoDB DEFAULT CHARSET=latin1;
Query OK, 0 rows affected (0.01 sec)
mysql> insert into tmerge2 (c2, c3, c4, c5, cp) values(1,1,1,1,1);
Query OK, 1 row affected (0.01 sec)
...
see "How to repeat"
...
mysql> explain select * from tmerge2 where (c2 = 1 and c3 = 1) or (c4 =2 and c5=1)\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: tmerge2
type: index_merge
possible_keys: k1,k2
key: k1,k2
key_len: 12,12
ref: NULL
rows: 2
Extra: Using sort_union(k1,k2); Using where
1 row in set (0.00 sec)
mysql> explain select * from tmerge2 where (c2 = 1 and c3 = 1 and cp=1) or (c4=2 and c5=1 and cp=1)\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: tmerge2
type: index_merge
possible_keys: k1,k2
key: k1,k2
key_len: 14,14
ref: NULL
rows: 2
Extra: Using sort_union(k1,k2); Using where
1 row in set (0.00 sec)
mysql> explain select * from tmerge2 where ((c2 = 1 and c3 = 1) or (c4 =2 and c5=1)) and cp=1\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: tmerge2
type: ALL
possible_keys: k1,k2
key: NULL
key_len: NULL
ref: NULL
rows: 5699
Extra: Using where
1 row in set (0.00 sec)
The last 2 queries are semantically the same and should be optimized in the same way. Moreover, they are both more "selective" than the first one.
How to repeat:
CREATE TABLE tmerge2 (
`c1` int(11) NOT NULL auto_increment,
`c2` decimal(10,0) default NULL,
`c3` decimal(10,0) default NULL,
`c4` decimal(10,0) default NULL,
`c5` decimal(10,0) default NULL,
`cp` decimal(1,0) default NULL,
`ce` decimal(10,0) default NULL,
`cdata` char(20),
PRIMARY KEY (`c1`),
KEY `k1` (`c2`,`c3`,`cp`,`ce`),
KEY `k2` (`c4`,`c5`,`cp`,`ce`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
insert into tmerge2 (c2, c3, c4, c5, cp) values(1,1,1,1,1);
insert into tmerge2 (c2, c3, c4, c5, cp) values(2,1,1,1,4);
insert into tmerge2 (c2, c3, c4, c5, cp) values(2,1,2,1,1);
insert into tmerge2 (c2, c3, c4, c5, cp) values(2,1,3,1,4);
insert into tmerge2 (c2, c3, c4, c5, cp) values(3,1,4,1,4);
insert into tmerge2 (c2, c3, c4, c5, cp) select c2, c3, c4, c5, cp from
tmerge2 where cp = 4;
...
I repeated the above until I got:
Query OK, 3072 rows affected (0.12 sec)
Records: 3072 Duplicates: 0 Warnings: 0
Then:
explain select * from tmerge2 where (c2 = 1 and c3 = 1) or (c4 =2 and c5
= 1)\G
explain select * from tmerge2 where (c2 = 1 and c3 = 1 and cp = 1) or (c4
=2 and c5 = 1 and cp=1)\G
explain select * from tmerge2 where ((c2 = 1 and c3 = 1) or (c4 =2 and c5
= 1)) and cp = 1\G
Suggested fix:
Add some additional checks for possible (great!) Index Merge optimization.