簡體   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