为啥 MySQL 不使用复合 WHERE IN 的索引?

Posted

技术标签:

【中文标题】为啥 MySQL 不使用复合 WHERE IN 的索引?【英文标题】:Why is MySQL not using indexes with composite WHERE IN?为什么 MySQL 不使用复合 WHERE IN 的索引? 【发布时间】:2012-03-23 19:11:30 【问题描述】:

我正在尝试通过复合索引从具有 PRIMARY KEY (a, b) 的表中获取几条记录

SELECT * FROM table WHERE (a, b) IN ((1,2), (2,4), (1,3))

问题是,即使我 FORCE INDEX (PRIMARY),mysql 也没有使用索引。 EXPLAIN SELECT 显示 null possible_keys。

为什么没有 possible_keys?

通过复合键检索多行的最佳方法是什么:

使用 OR 使用 UNION ALL 使用 WHERE () IN ((),())

附:查询结果等于

SELECT * FROM table WHERE (a = 1 AND b = 2) OR (a = 2 AND b = 4) OR (a = 1 AND b = 3)

谢谢

【问题讨论】:

【参考方案1】:

如果查询通过组合WHERE ... IN仅从索引中选择字段(或者如果表没有其他字段),则将使用索引:

SELECT a,b FROM `table` WHERE (a, b) IN ((1,2), (2,4), (1,3))

否则将不会被使用。 解决方法是使用派生查询:

SELECT t.* FROM (SELECT a, b FROM `table` WHERE (a, b) IN ((1,2), (2,4), (1,3))) AS o INNER JOIN `table` AS t ON (t.a = o.a AND t.b = o.b)

解释选择:

id  select_type table   type    possible_keys   key key_len ref rows    Extra
1   PRIMARY <derived2>  ALL NULL    NULL    NULL    NULL    2   
1   PRIMARY t   eq_ref  PRIMARY PRIMARY 2   o.a,o.b 1   
2   DERIVED table   index   NULL    PRIMARY 2   NULL    6   Using where; Using index

【讨论】:

【参考方案2】:

强烈希望为某个列建立索引,您是否考虑过创建一个新列:a_b,基本上是CONCAT(a, '-', b),然后比较一下(WHERE a_b = $id1-$id2)?

每个表只能有一个 PRIMARY 列。您不能同时“索引主要”ab

【讨论】:

使用CONCAT(a, '-', b) 对我来说不是一个好选择,因为如果我在字段值中有'-',它可能会失败。我的 PRIMARY KEY 是多列的,所以它同时包含 ab CONCAT(a, '!-!', b) - 你曾经使用过这个值吗? :) 我的表包含数亿条记录,我认为索引字符串列不会提高性能。我宁愿使用 UNION ALL 进行批量复合选择。【参考方案3】:

尝试在 a、b 列上创建组合索引。

索引不需要是主键,它仍然可以提供很多帮助。

在此处了解有关您的问题的更多信息:http://dev.mysql.com/doc/refman/5.0/en/multiple-column-indexes.html

【讨论】:

以上是关于为啥 MySQL 不使用复合 WHERE IN 的索引?的主要内容,如果未能解决你的问题,请参考以下文章

MySQL - SELECT WHERE field IN(子查询) - 为啥非常慢?

WHERE col1,col2 IN (...) [使用复合主键的 SQL 子查询]

MySQL 不使用带有 WHERE IN 子句的索引?

Mysql容易忽视的基础杂记

为啥当@val IS NULL 时SELECT 'A' WHERE @val IN (1, 2, 3, NULL) 不返回值? [复制]

MYSQL -- 联合索引