查询性能

tec*_*rer 7 performance sql-server query

为什么

SELECT Barraportfolioname
FROM   portfolio
WHERE  id IN (SELECT DISTINCT i1.portfolioid
              FROM   Import i1
                     LEFT OUTER JOIN Import i2
                       ON i1.PortfolioID = i2.PortfolioID
                          AND i2.ImportSetID = 82
              WHERE  i1.ImportSetID = 83
                     AND i2.ID IS NULL)  
Run Code Online (Sandbox Code Playgroud)

需要 0 秒,而以下查询需要 5 秒。

SELECT DISTINCT p.BarraPortfolioName AS name
FROM   Import i1
       INNER JOIN Portfolio p
         ON p.ID = i1.PortfolioID
       LEFT OUTER JOIN Import i2
         ON i1.PortfolioID = i2.PortfolioID
            AND i2.ImportSetID = 82
WHERE  i1.ImportSetID = 83
       AND i2.ID IS NULL;  
Run Code Online (Sandbox Code Playgroud)

我正在使用 SQL Server。这两个表在查询中使用的所有列上都有索引,即portfolioid、id、importsetid。

由 gbn 编辑,基于 OP 评论

他们说:

这比前两个查询要好得多。

select
   BarraPortfolioName
from 
   (
   select distinct p.BarraPortfolioName,portfolioid
   from
        import i1
        inner join 
        portfolio p on p.id=i1.portfolioid
   where 
        importsetid = ?
   ) as p1
   left outer join
   (
   select distinct portfolioid 
   from import 
   where importsetid = ?
   ) as p2 on p1.portfolioid = p2.portfolioid
where 
   p2.portfolioid is null
Run Code Online (Sandbox Code Playgroud)

gbn*_*gbn 9

这假设两者都给出相同的结果

  • 第一个是“半连接”,因为 IN(子查询)(不需要 DISTINCT)
    这意味着子查询可以“短路”

  • 第二个是外部连接,然后是限制,然后是 DISTINCT 聚合。
    这是 3 个主要的离散操作

即使在子查询中使用外连接,这种“短路”也是造成差异的主要原因。

对于更简单的查询,第二个查询将优化为与第一个查询相同的计划,因为它在语义上是相同的。版本越晚等的可能性越大

有关更多信息,请参阅此内容(相同的逻辑,只是颠倒了):与索引相关的 NOT 逻辑的使用

这是关于SO 用户 Quassnoi 在他的网站上的“IN vs. JOIN vs. EXISTS”

还有一个类似的 SO 示例:https : //stackoverflow.com/a/7221395/27535


Rob*_*ley 3

如果您在 BarraPortfolioName 上没有唯一索引,则需要检查所有索引是否有重复项,这在第一个查询中是不必要的,因为您的 IN 子句会为您处理该索引。

尝试创建一个唯一索引(或约束)并看看这是否有效。或者通过删除不同的并将其放在GROUP BY p.id, p.BarraPortfolioName末尾来更改第二个脚本。这应该会让区分过程短路。