Left join or Select in select (SQL - 查询速度)

Left join or Select in select (SQL - Speed of query)

我有这样的东西:

SELECT CompanyId 
FROM Company
WHERE CompanyId not in
    (SELECT CompanyId 
     FROM Company 
     WHERE (IsPublic = 0) and CompanyId NOT IN 
         (SELECT ShoppingLike.WhichId 
          FROM Company 
          INNER JOIN 
          ShoppingLike ON Company.CompanyId = ShoppingLike.UserId 
          WHERE (ShoppingLike.IsWaiting = 0) AND
                (ShoppingLike.ShoppingScoreTypeId = 2) AND
                (ShoppingLike.UserId = 75)
          )
     )

它有3个select,我想知道不做3个select怎么能有,100万条记录哪个速度更快? "select in select" 或 "left join"?

我的经验来自 Oracle。优化棘手的查询永远没有正确答案,这是你和优化者之间的协作。您需要检查解释计划,有时甚至是跟踪,通常在编写查询的每个阶段,以找出优化器的想法。话虽如此:

  • 您可以通过将其子查询 WHERE 子句的全部内容放入 NOT(...) 来删除外部 SELECT。从表面上看,它会阻止对 Company(或其 CompanyId 的索引)的外部全面扫描。尝试一下,检查输出是否相同并获取时间,然后在尝试下面的操作之前暂时将其删除。由于创建了隐式 OR,NOT() 很可能会导致优化器停止考虑针对 ShoppingLike 子查询的 ANTI-JOIN。
  • 确保将 CompanyId 和 WhichId 定义为 NOT NULL 列。如果没有这个(或明确的 CompanyId IS NOT NULL 之类的东西),那么 ANTI-JOIN 选项通常会被丢弃。
  • 最内部的子查询不相关(不引用其外部查询中的任何内容)因此可以单独提取和调整。就风格而言,我会交换 INNER JOIN 周围的 table 名称,因为您希望首先扫描 ShoppingLike,因为它具有针对它的所有过滤器。它不会有任何区别,但它更容易阅读,并且可以使用提示按指定的顺序扫描 tables。我什至会质疑在这个子查询中是否需要 Company table。
  • 您曾经使用过 NOT IN,而有时非常相似的 NOT EXISTS 会提供优化器 more/alternative 选项。

除非您开始尝试解释计划,否则以上所有内容都只是反复试验。 Oracle可以,顺风顺水,在LEFT JOININSELECT之间转换。超过 100 万行将创造投资时间。