mysql可以使用row constructor来做compound in 查询:select * from t where (col1,col2) in ((colt1,colt2),(colt11,colt22)).这种查询在批量查询的时候就会显得比较方便:业务上可以批量操作,提高效率。但是explain之后却发现,这种sql却使用了全表扫描。
首先看一下mysql是怎么处理in查询的:mysql处理 in(value list)查询时会对value list做一次quick-sort,但是如果value list里的元素是tuple就无法进行排序(按哪个col排序)。bug#16081对value list中只有一个tuple情况,做了优化:将select * from t where (col1,col2) in ((colt1,colt2))转换为select * from t where col1=colt1 and col2=colt2,explain的结果也也可以看到:(count(*)是可以使用到覆盖索引的)
mysql> show create table t7\G *************************** 1. row *************************** Table: t7 Create Table: CREATE TABLE `t7` ( `a` int(11) DEFAULT NULL, `b` varchar(20) DEFAULT NULL, `c` varchar(20) DEFAULT 'ccccc', KEY `idx_a_b` (`a`,`b`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 1 row in set (0.00 sec) mysql> explain select * from t7 where (a,b) in ((1,'kangaroo'),(2,'dolphin')); +----+-------------+-------+------+---------------+------+---------+------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+------+---------------+------+---------+------+------+-------------+ | 1 | SIMPLE | t7 | ALL | NULL | NULL | NULL | NULL | 16 | Using where | +----+-------------+-------+------+---------------+------+---------+------+------+-------------+ 1 row in set (0.00 sec) mysql> explain select * from t7 where (a,b) in ((1,'kangaroo')); +----+-------------+-------+------+---------------+---------+---------+-------------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+------+---------------+---------+---------+-------------+------+-------------+ | 1 | SIMPLE | t7 | ref | idx_a_b | idx_a_b | 68 | const,const | 4 | Using where | +----+-------------+-------+------+---------------+---------+---------+-------------+------+-------------+ 1 row in set (0.00 sec) mysql> explain select * from t7 where a=1 and b='kangaroo'; +----+-------------+-------+------+---------------+---------+---------+-------------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+------+---------------+---------+---------+-------------+------+-------------+ | 1 | SIMPLE | t7 | ref | idx_a_b | idx_a_b | 68 | const,const | 4 | Using where | +----+-------------+-------+------+---------------+---------+---------+-------------+------+-------------+ 1 row in set (0.00 sec) mysql> explain select * from t7 where (a=1 and b='kangaroo') or (a=2 and b='dolphin'); +----+-------------+-------+------+---------------+------+---------+------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+------+---------------+------+---------+------+------+-------------+ | 1 | SIMPLE | t7 | ALL | idx_a_b | NULL | NULL | NULL | 16 | Using where | +----+-------------+-------+------+---------------+------+---------+------+------+-------------+ 1 row in set (0.00 sec) mysql> explain select count(*) from t7 where (a,b) in ((1,'kangaroo'),(2,'dolphin')); +----+-------------+-------+-------+---------------+---------+---------+------+------+--------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+-------+---------------+---------+---------+------+------+--------------------------+ | 1 | SIMPLE | t7 | index | NULL | idx_a_b | 68 | NULL | 16 | Using where; Using index | +----+-------------+-------+-------+---------------+---------+---------+------+------+--------------------------+ 1 row in set (0.00 sec)
在这种需求下,如果一定要做批量查询,那就只能改成select * from t where (col1=colt1 and col2=colt2) or (col1=colt11 and col2=colt2).
参考链接:
http://www.facebook.com/note.php?note_id=243134480932
http://dev.mysql.com/doc/refman/5.5/en/row-subqueries.html
http://bugs.mysql.com/bug.php?id=16081
http://bugs.mysql.com/bug.php?id=31188
http://bugs.mysql.com/bug.php?id=35819
http://bugs.mysql.com/bug.php?id=16247
http://www.mysqlperformanceblog.com/2008/04/04/multi-column-in-clause-unexpected-mysql-issue/
http://dev.mysql.com/doc/refman/5.5/en/comparison-operators.html#function_in