使用“NOT IN”优化 MySQL 查询

Posted

技术标签:

【中文标题】使用“NOT IN”优化 MySQL 查询【英文标题】:Optimizing MySQL Query with "NOT IN" 【发布时间】:2014-06-05 14:22:27 【问题描述】:

我已经看到一些涉及 mysql 查询中“NOT IN”效率低下的问题,但我没有设法重现建议的解决方案。

所以我有某种搜索引擎。它从非常简单的查询开始,如果找不到足够的结果,则尝试更复杂的查询。这是它在伪代码中的工作原理

list_of_ids = do_simple_search()
nb_results = size_of(list_of_ids)

if nb_results < max_nb_results :
    list_of_ids .= do_search_where_id_not_in(list_of_ids)

    if nb_results < max_nb_results :
         list_of_ids .= do_complicated_search_where_id_not_in(list_of_ids)

希望我很清楚。 无论如何,这里是慢查询,如 MySQL-slow 所示:

SELECT DISTINCT c.id 
FROM clients c LEFT JOIN communications co ON c.id = co.client_id 
WHERE (co.titre LIKE 'S' OR co.contenu LIKE 'S') AND c.id NOT IN(N)
LIMIT N, N

这里是对该查询的解释:

id  select_type     table   type    possible_keys               key         key_len ref             rows    Extra
1   SIMPLE          c       index   PRIMARY                     PRIMARY     2       NULL            25250   Using where; Using index; Using temporary
1   SIMPLE          co      ref     qui_com,id_client,titre     id_client   2       klients.c.id    8       Using where; Distinct

MySQL 版本为 5.1.63-0ubuntu0.11.04.1-log

也许我的方法在这里是错误的?你会怎么做?谢谢。

【问题讨论】:

您有性能问题吗? 如果您希望我们帮助优化查询,您需要向我们展示表和索引定义,以及每个表的行数。也许您的表格定义不佳。也许索引没有正确创建。也许您认为您在该列上没有索引。没有看到表和索引定义,我们无法判断。我们还需要行计数,因为这会极大地影响查询优化。如果您知道如何执行EXPLAIN 或获取执行计划,请将结果也放入问题中。如果您没有索引,请尽快访问use-the-index-luke.com。 感谢您的提醒,我会尝试自己弄清楚然后回来 【参考方案1】:

几点说明:

1) 为什么要进行 LEFT JOIN i/o (INNER) JOIN? LEFT JOIN 表示您还想获得与客户不匹配的记录,这是故意的吗?如果没有,那么 JOIN i/o LEFT JOIN 会更快。

2) 如果你可以简单地做,为什么还需要 JOIN:

SELECT DISTINCT co.client_id from communications co 
WHERE (co.titre LIKE 'S' OR co.contenu LIKE 'S') AND co.id!=N LIMIT N,N;

另外,如果你做一个 JOIN,两个连接的字段都必须是索引,否则也很慢。

更重要的是,您从通信表中同时设置了 client_id 和 id,但是这两者没有共同的索引,这意味着执行查询需要更多的工作(因此using temporary 这通常不是一个好兆头)。

3) 你在 co.titre 和 co.contenu 上都做了一个复杂的条件,你似乎有索引但它们没有被使用。这意味着这部分可能会很慢。

【讨论】:

哦,哇,我不敢相信我忽略了我不需要那个加入。非常感谢,这确实更简单。 该死,我才意识到为什么我必须做 JOIN。在某些情况下,我也会检查客户的状态。所以你建议我用 JOIN 替换我的 LEFT JOIN。 SQL 从来都不是我的强项:/ 我是这么想的。当然,您仍然可以加入客户表并使用那里的字段。

以上是关于使用“NOT IN”优化 MySQL 查询的主要内容,如果未能解决你的问题,请参考以下文章

MySQL 子查询优化 - where not in(子查询)

没有 Not In 和 In 使用连接的 SQL 查询优化

使用 NOT IN 优化查询(选择...)

如何使用子查询优化“WHERE NOT IN”

使用 NOT IN(Oracle Sql Developer)的查询性能优化

使用 JOIN 而不是 NOT IN 优化 SQL 查询