Mysql select with in 子句不使用索引

Posted

技术标签:

【中文标题】Mysql select with in 子句不使用索引【英文标题】:Mysql select with in clause does not use index 【发布时间】:2011-12-22 22:15:03 【问题描述】:

我有一个联系人表,其主键为 id。它还有一个二级索引idx_id_del_user(id,deleted,user_id)。

以下查询使用索引,因此非常快 -

select id
from jts_contacts
where id = '00000402-25c8-7375-e3df-4ec5b66de11d'
and deleted = 0;

0.0098 秒内取出 1 行

但是,当我使用 in 子句时,外部查询会进入全表扫描。我希望它使用主键或 idx_id_del_user。

select  *
from jts_contacts FORCE INDEX (idx_id_del_user)
where id in
(select id
from jts_contacts
where id = '00000402-25c8-7375-e3df-4ec5b66de11d')
and deleted = 0

9 秒内取出 1 行

解释计划-

id, select_type,          table,         type, possible_keys,                 key, key_len, ref, rows, Extra
------------------------------------------------------------------------------------
1, 'PRIMARY',            'jts_contacts', 'ALL', '',                           '',   '',     '', 1127275, 'Using where'
2, 'DEPENDENT SUBQUERY', 'jts_contacts', 'const', 'PRIMARY,idx_id_del_user', 'PRIMARY', '108', 'const', 1, 'Using index'

此表有 120 万条记录,并且已对该表进行了分析。我在没有 FORCE INDEX 选项的情况下尝试过,但它仍然没有使用索引。关于使这个查询更快的任何建议?


警告:使用联接而不是 in 子句将起作用,但是由于这是从现有产品生成的查询 - 它不能更改为使用联接。

【问题讨论】:

【参考方案1】:

据我所知,IN 遍历所有匹配记录,并将它们与子句中的值进行比较,一次一行。

因此,您能做的最好的事情就是在deleted 上使用索引,而您只会浏览deleted = 0 所在的记录。

【讨论】:

谢谢。我也试过了。但是,deleted 只有两个值 0 和 1(它不是很有选择性)。我实际上将响应时间增加到 12 秒。我同意这个答案,但是它不起作用,因为删除的索引不是很有选择性。【参考方案2】:

我刚刚遇到了同样的问题,在阅读了 Marcus Adams 的帖子后,我想到了一些我从基于同一张表的数据对表运行 UPDATE 中学到的东西:创建一个派生表首先,像这样:

SELECT * FROM jts_contacts WHERE id IN
(SELECT id FROM
    (SELECT id FROM jts_contacts WHERE id = '00000402-25c8-7375-e3df-4ec5b66de11d')
temp)
AND deleted = 0

这将首先将内部查询的完整结果提取到派生的temp 表中,然后基于此运行外部查询。

这种模式将我的类似查询的速度从几分钟提高到不到一秒。我不骗你。

【讨论】:

以上是关于Mysql select with in 子句不使用索引的主要内容,如果未能解决你的问题,请参考以下文章

SELECT * FROM X WHERE id IN (...) with Dapper ORM

MySQL Select 语句,WHERE 'IN' 子句

按mysql中select语句“in”子句中的值顺序排序

MySQL UNION SELECT 和 IN 子句

MySQL select in join 子句扫描太多行

MySQL使用select in or子句的结果[重复]