[英]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.