繁体   English   中英

为什么优化器决定自连接一个表?

[英]Why does the optimizer decide to self-join a table?

我正在分析我的查询,如下所示:

WITH Project_UnfinishedCount AS (
    SELECT P.Title AS title, COUNT(T.ID) AS cnt
    FROM PROJECT P LEFT JOIN TASK T on P.ID = T.ID_PROJECT AND T.ACTUAL_FINISH_DATE IS NULL 
    GROUP BY P.ID, P.TITLE                                                                  
)
SELECT Title
FROM Project_UnfinishedCount
WHERE cnt = (
    SELECT MAX(cnt)
    FROM Project_UnfinishedCount
    );

它返回具有最多未完成任务的项目的标题。

这是它的执行计划: 在此处输入图像描述

我想知道为什么它的步骤 6-8 看起来像项目表的自连接? 并且它将连接的结果存储为视图,但视图,根据行和字节列与项目表相同。 他为什么这样做?

我也想知道 2 和 1 步骤代表什么。 我猜,2 存储我的 CTE 的结果以在步骤 10-14 中使用它,而 1 从视图中删除没有子查询返回的“cnt”值的行,这是正确的猜测吗?

除了上面的注释之外,当您多次引用 CTE 时,还有一个启发式方法告诉优化器具体化 CTE,这就是您看到临时表转换的原因。

关于此查询的其他一些评论/问题。 我假设这种关系是一个 PROJECT 可以有 0 个或多个任务,并且每个 TASK 只针对一个 PROJECT。 在那种情况下,我想知道为什么你有一个外部连接? 此外,您将加入 ACTUAL_FINISH_DATE 列。 这意味着如果您有一个项目,其中所有任务都已完成,那么外部联接将实现不匹配的行,这将使您的查询结果看起来表明有 1 个未完成的任务。 所以我认为你的 CTE 应该看起来更像:

SELECT P.Title AS title, COUNT(T.ID) AS cnt
FROM PROJECT P 
JOIN TASK T on P.ID = T.ID_PROJECT
WHERE T.ACTUAL_FINISH_DATE IS NULL 
GROUP BY P.ID, P.TITLE  

话虽如此,这些“在组中查找匹配项(计数、最大值等)”类型的查询在编写为 window function 时通常更有效。 这样你就可以消除自我加入。 当您拥有数百万或数十亿行时,这可能会产生很大的性能差异。 因此,例如,您的查询可以重写为:

 SELECT TITLE, CNT
 FROM (
    SELECT P.Title AS title, COUNT(T.ID) AS cnt
           , RANK() OVER( ORDER BY COUNT(*) DESC ) RNK
    FROM PROJECT P
    JOIN TASK T on P.ID = T.ID_PROJECT
    WHERE T.ACTUAL_FINISH_DATE IS NULL 
    GROUP BY P.ID, P.TITLE  
      )
  WHERE RNK=1 

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM