为啥 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 列。您不能同时“索引主要”a
和 b
【讨论】:
使用CONCAT(a, '-', b)
对我来说不是一个好选择,因为如果我在字段值中有'-'
,它可能会失败。我的 PRIMARY KEY 是多列的,所以它同时包含 a
和 b
。
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 子查询]
为啥当@val IS NULL 时SELECT 'A' WHERE @val IN (1, 2, 3, NULL) 不返回值? [复制]