【问题标题】:Difference between these two SQL queries这两个 SQL 查询之间的区别
【发布时间】:2017-01-30 04:28:20
【问题描述】:

所以我正在测试 2 个查询,我得到了不同的结果。我想纠正/补充我的理解。这是两个通用 SQL 查询,据我了解,它们是相同的,但执行时会得到不同的结果。请注意,这不是关于 diff between ANSI and non-ANSI SQL 的问题。

查询 1(使用 LEFT JOIN):

SELECT * FROM person p LEFT JOIN person_log pl
ON p.person_id = pl.person_id
WHERE pl.person_id IS NULL
AND p.is_active = 1;

查询 2(使用 2 个查询):

SELECT * FROM person
WHERE person.is_active = 1
AND person_id NOT IN (SELECT person_id FROM person_log);

据我了解,两者都是represent this in venn diagram form。另外,一个比另一个更有效吗? JOIN 的查询结果与 2 个查询?

编辑:在查询 1 中将 = 更改为 IS。感谢 @Justin Samuel 发现导致不同结果的 = 错误!

【问题讨论】:

  • 在没有优化器介入的情况下,在 lees 高级数据库上,#1 应该更快且可扩展。优化器应该将 #2 转换为 #1
  • 连接不能用维恩图正确表示,只是直观解释的一种简化方式
  • @Bohemian 这并不总是正确的。如果person_log表的person_id列中有NULLs,那么结果会完全不同
  • 同意它们通常是相同的,但是正如 Lamak 指出的那样,如果 person_id 在 person_log 中可能为空,那么您将不会得到您想要的结果。 NOT EXISTS 可能比这两种方法都快。加上这种是重复的:stackoverflow.com/questions/173041/not-in-vs-not-exists
  • @Matt 您的链接适用于 SQL Server,如果我在 MySQL 中没记错的话,NOT EXISTS 解决方案通常比LEFT JOIN

标签: mysql sql join


【解决方案1】:

上面的查询有一个bug 1.不能用“=”判断是否为NULL

SELECT * FROM person p LEFT JOIN person_log pl
ON p.person_id = pl.person_id
WHERE pl.person_id = NULL
AND p.is_active = 1;

理想情况下,您应该使用 IS NULL

SELECT * FROM person p LEFT JOIN person_log pl
ON p.person_id = pl.person_id
WHERE pl.person_id IS NULL
AND p.is_active = 1;

您可以在https://www.simple-talk.com/sql/t-sql-programming/how-to-get-nulls-horribly-wrong-in-sql-server/ 中查看 NULL 检查

【讨论】:

  • 太酷了!由于这种变化,现在两个查询都返回相同的结果,并且上述答案更有意义。我希望我能有两个答案。也许一些管理员可以将您的答案与接受的答案合并。 (如果他们注意到这一点)
  • @Sticky - 很高兴听到您的问题已解决。至于这两种方法之间的比较,它会根据情况和索引等细节而有所不同。所以我没有评论那部分。
  • 糟糕,我错过了 Sticky 告诉我们查询不会给出相同结果的部分。 (嗯,像“为什么第一个查询没有返回任何行”这样的问题可能更明显。)很好发现。
【解决方案2】:

两个查询都为您提供相同的数据。

第二个查询是解决问题的直接方法;获取所有在 person_log 中没有条目的人。您可以使用NOT EXISTS 子句而不是NOT IN 子句来执行相同的操作。 (NOT IN 有点精简,但您在子查询中选择的值不能为空,否则您根本看不到任何数据。我通常更喜欢 IN / NOT IN 而不是 EXISTS / NOT EXISTS它们很简单,但这是个人喜好问题。

第一个查询称为反连接。在没有很好地实现这些方法的弱数据库系统上实现与NOT EXISTSNOT IN 查询相同是一个技巧。 (原因是在编写一个新的数据库系统时,程序员通常会把所有的精力都放在连接上,因为连接非常重要,而忽略了EXISTSIN一段时间。)

这取决于执行速度最快的 DBMS,NOT INNOT EXISTS 或反连接。无论您选择哪种语法,理想的 DBMS 都会得到相同的执行计划。

反连接会产生很大的中间结果。对于成熟的 DBMS,您不应该出于这个原因和仅仅为了可读性而使用反连接。

【讨论】:

    【解决方案3】:

    如果您在第二个表中查找不匹配的行,特别是如果列不可为空,请使用 NOT IN。

    【讨论】:

    • 这是错误的,如果列可以为空,那么 NOT IN 根本不应该使用
    • 根据这个常见的参考Here,优化器(随着时间的推移只会变得更好)显然将它们固定为相同的。所以我看不出有什么区别。显然查询和模式各不相同。但人们需要对此保持科学性,而不是猜测。
    • 我不认为优化可以确定查询是否仅针对不存在的值。我想事情变得越来越聪明了。
    【解决方案4】:

    第一个获取所有没有日志条目的人,然后过滤掉不活跃的人。

    第二个查询获取所有人员。然后过滤掉不活跃的。然后获取所有日志条目。然后过滤掉没有日志条目的人。

    它们都将返回相同的信息。但是,出于性能原因,如果可以使用 JOIN,则应避免使用第二个查询。 JOIN 的主要好处是索引。 WHERE 中只会使用一个索引,但每个 JOIN 都会使用一个。

    【讨论】:

      猜你喜欢
      • 2014-06-02
      • 2015-08-17
      • 2011-09-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多