【问题标题】:What's the difference between NOT EXISTS vs. NOT IN vs. LEFT JOIN WHERE IS NULL?NOT EXISTS vs. NOT IN vs. LEFT JOIN WHERE IS NULL 之间有什么区别?
【发布时间】:2011-01-15 20:22:25
【问题描述】:

在我看来,您可以在 SQL 查询中使用 NOT EXISTS、NOT IN 或 LEFT JOIN WHERE IS NULL 来执行相同的操作。例如:

SELECT a FROM table1 WHERE a NOT IN (SELECT a FROM table2)

SELECT a FROM table1 WHERE NOT EXISTS (SELECT * FROM table2 WHERE table1.a = table2.a)

SELECT a FROM table1 LEFT JOIN table2 ON table1.a = table2.a WHERE table1.a IS NULL

我不确定我的所有语法是否正确,但这些是我见过的一般技术。为什么我会选择使用其中一种?性能不同吗...?其中哪一个是最快/最有效的? (如果取决于实现,我什么时候会使用每个?)

【问题讨论】:

  • 许多常见的 SQL 引擎让您能够查看执行计划。通过这种方式,您通常可以发现逻辑等效查询的效率显着差异。任何方法的成功都取决于表大小、存在的索引等因素。
  • @wich:没有数据库关心您在EXISTS 子句中返回的确切内容。您可以返回 *NULL 或其他任何内容:所有这些都将被优化掉。
  • @wich - 为什么?这里:techonthenet.com/sql/exists.php 和这里:msdn.microsoft.com/en-us/library/ms188336.aspx 似乎都使用 *...
  • @wich:这不是“表达兴趣”。这是关于查询解析器要求您在SELECTFROM 之间放置一些内容。 * 更容易输入。是的,SQL 确实与自然语言有一些相似之处,但它是由一台机器解析和执行的,一台经过编程的机器。并不是说它会突然闯入您的隔间并大喊“停止要求EXISTS 查询中的额外字段,因为我已经厌倦了解析它们然后将它们扔掉!”。用电脑没问题,真的。
  • @Quassnoi 如果您编写代码的唯一目的是让机器解释它,那么代码看起来会很糟糕,不幸的是,很多人都是这样工作的。但是,如果您用另一种方式编写代码,编写代码来表达您希望机器执行的操作作为与您的同行的公报,您将编写更好、更易于维护的代码。聪明点,为人写代码,而不是为电脑写代码。

标签: sql


【解决方案1】:

简而言之:

NOT IN 有点不同:如果列表中只有一个 NULL,它永远不会匹配。

  • MySQL 中,NOT EXISTS 的效率有点低

  • SQL Server 中,LEFT JOIN / IS NULL 效率较低

  • PostgreSQL 中,NOT IN 效率较低

  • Oracle中,三个方法都是一样的。

【讨论】:

  • 感谢您的链接!感谢您的快速概述...我的办公室出于某种原因阻止了该链接:P 但我会在使用普通计算机时立即检查。
  • 另一点是,如果table1 .a 包含NULL,则EXISTS 查询将不会返回此行,但如果table2 为空,则NOT IN 查询将返回。 NOT IN vs. NOT EXISTS Nullable Columns: SQL Server
  • @MartinSmith: NULL NOT IN () 评估为真(不是NULL),就像NOT EXISTS (NULL = column)
  • @Quassnoi - 呃,好点子,弄错了。 NOT EXISTS 将始终返回该行,但 NOT IN 仅在子查询不返回任何行时才会这样做。
【解决方案2】:

如果数据库擅长优化查询,那么第一个将转换为接近第三个。

对于像您提出的问题这样的简单情况,应该几乎没有区别,因为它们都将作为连接执行。在更复杂的查询中,数据库可能无法连接 not innot exists 查询。在这种情况下,查询会变得慢很多。另一方面,如果没有可以使用的索引,连接也可能表现不佳,因此仅仅因为您使用了连接并不意味着您是安全的。您必须检查查询的执行计划以确定是否可能存在任何性能问题。

【讨论】:

    【解决方案3】:

    假设您避免使用空值,它们都是使用标准 SQL 编写 anti-join 的方法。

    一个明显的省略是使用EXCEPT

    SELECT a FROM table1
    EXCEPT
    SELECT a FROM table2
    

    注意在 Oracle 中您需要使用 MINUS 运算符(可以说是一个更好的名称):

    SELECT a FROM table1
    MINUS
    SELECT a FROM table2
    

    谈到专有语法,根据您使用的产品,可能还存在值得研究的非标准等价物,例如SQL Server 中的OUTER APPLY(类似):

    SELECT t1.a
      FROM table1 t1
           OUTER APPLY 
           (
            SELECT t2.a
              FROM table2 t2
             WHERE t2.a = t1.a
           ) AS dt1
     WHERE dt1.a IS NULL;
    

    【讨论】:

      【解决方案4】:

      当需要在具有多字段主键的表中插入数据时,考虑它会更快(我在 Access 中尝试过,但我认为在任何数据库中)不检查“不存在具有‘此类’值的记录table", - 而只是插入到表中,多余的记录(通过键)不会被插入两次。

      【讨论】:

        【解决方案5】:

        性能角度始终避免使用反向关键字,例如 NOT IN、NOT EXISTS、... 因为要检查逆向项,DBMS 需要遍历所有可用并删除逆向选择。

        【讨论】:

        • 当您真正需要NOT 时,您提出什么解决方法?
        • 好吧,当没有选择的原因时,我们需要使用 NOT 操作,这就是它们存在的原因。最佳做法是在我们有任何其他替代解决方案时避免使用它们。
        • @onedaywhen,如果优化器转换查询并返回错误结果那么这是一个错误
        • @DuduMarkovitz:是的,如果你联系 SQL Server 团队并且他们承认了这个错误但拒绝修复它,因为他们说这样做可能会使查询运行速度变慢,那么这是一个错误 你需要处理
        • @onedaywhen - 我认为这不是一个假设的场景 :-) 你还记得错误细节吗?
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-06-18
        • 2018-02-09
        • 2014-07-18
        相关资源
        最近更新 更多