如何使用 EXIST 而不是 IN 使用 MySQL

Posted

技术标签:

【中文标题】如何使用 EXIST 而不是 IN 使用 MySQL【英文标题】:how to use EXIST instead of IN using MySQL 【发布时间】:2014-02-16 00:28:14 【问题描述】:

如何将这个查询“转换”为不使用 IN,我读到的 in 与存在相比很慢

SELECT * FROM kx_examenes_diagnostico.examenes t1 WHERE NOT EXISTS (
SELECT * FROM kx_examenes_diagnostico.examenes_aplicados t2 WHERE t2.alumno_id=812 AND t2.examen_id=t1.examen_id
) AND t1.examen_id IN (1,2,3,4,5,10,11,12,13,,50,159,635,456,780,12,63,45);

我使用 mysql,我不知道如何使用我比较的值(在 in 子句内部)我必须使用 OR 的存在吗?有可能吗?

谢谢

【问题讨论】:

in 当你有一个常量列表时很好。性能问题是存在子查询时。 IN 子句在主键/索引列上选择时,它几乎是尽可能快的,因为该行可以直接从索引中获取,应该可以通过二进制搜索进行排序。跨度> “In”和“exists”不一定做同样的事情。两者都有时间和地点。获得正确的结果应该是最重要的。然后你就可以担心速度了。 【参考方案1】:

不清楚为什么要重写查询以消除 IN 列表。可以重写查询以替换 col IN (literal list) 谓词,但这不会提高性能。


如果您希望提高性能,则更有可能想要消除

 NOT EXISTS (correlated_subquery)

谓词,并使用“反连接”模式替换它,如下所示:

SELECT t1.* 
  FROM kx_examenes_diagnostico.examenes t1
  LEFT
  JOIN kx_examenes_diagnostico.examenes_aplicados t2
    ON t2.examen_id=t1.examen_id
   AND t2.alumno_id=812
 WHERE t1.examen_id IN (1,2,3,4,5,10,11,12,13,50,159,635,456,780,12,63,45)
   AND t2.examen_id IS NULL

“反连接”模式是一个外连接(包括来自t1 且在t2 中没有任何匹配行的行)与一个谓词(WHERE 子句)相结合,该谓词消除了确实有匹配。

为了这个特定查询的最佳性能,您可能需要索引

... ON examenes (examen_id)

... ON examenes_aplicados (examen_id, alumno_id)

根据alumno_id 列的基数,此索引可能会更好:

... ON examenes_aplicados (alumno_id, examen_id)

examenes_aplicados 上的这两个索引中的任何一个都是“覆盖索引”,这意味着 MySQL 可以通过访问索引页面来满足查询,而无需访问基础表中的页面。我们希望 MySQL EXPLAIN 显示“Using index”以访问该表。


更新:

我避免回答您提出的问题,而是回答了一个完全不同的问题。要回答您提出的问题:

问:我必须使用 OR 吗?

不,您不必使用 OR 关键字。 IN 列表可以替换为不使用任何 OR 关键字的等效谓词。

问:有可能吗?

是的,可以用EXISTS 子句替换IN (list) 谓词。但是您确实想这样做,除非您的目标是可怕的表现,并且您希望 DBA 追捕您以惩罚您,公开羞辱您,并殴打您。

【讨论】:

以上是关于如何使用 EXIST 而不是 IN 使用 MySQL的主要内容,如果未能解决你的问题,请参考以下文章

oracle中in和exist的区别

in exist,not in ,not exist

In 和Exists

sql优化,in与exist , not in与not exist 的区别

SQL优化- 数据库SQL优化——使用EXIST代替IN

SQL语句中 in和exist区别