稍後加入較小表的 WITH 表的性能
我正在嘗試開發一個通用框架,用於從大型數據庫中獲取分塊隊列。由於各種因素,這樣寫查詢很方便:
with tab as ( select whatever , id from whereever union all select whatever , id from whereever2 ) select t.whatever , t.id from tab as t inner join cohort as c on c.id = t.id
現在,我知道大多數數據庫會“在後台”重寫您的查詢以提高效率。如果他們沒有,那麼此查詢將從 中提取所有內容,
whereever
然後使用下面的聯接對其進行過濾。這將是低效的。或者,我可以這樣做:
進而:
select whatever , id from whereever inner join cohort on w.id = cohort.id union all select whatever , id from whereever2 inner join cohort on w.id = cohort.id
這個更醜陋,重複且更難以程式方式編寫。
原則上,哪個應該更快,為什麼?
如果重要的話,我使用的是 MS SQL 數據庫,但我很想知道答案是否會因 postgres 而異。
有太多變數來推測哪一個會更快。不幸的是,這對於大多數查詢來說都是正確的,它實際上歸結為實際測試一個查詢與另一個查詢,分析它們的查詢計劃,並查看它們的執行統計數據以確定哪個查詢性能更高。
這些變數之一很可能是執行查詢時您在表中擁有的數據。這可能基於數據量和表中數據之間的值分佈而發生。
為了清楚地展示這方面的一個範例,我們假設您問題中的查詢實際上只使用了
UNION
運算符(而不是UNION ALL
運算符)。操作員對UNION
整個結果集進行重複數據刪除(在聯合的兩個數據集之間,甚至在操作員任一側的單個數據集中的任何重複數據中UNION
)。如果兩個數據集之間有很多重複的行,那麼第一個範例查詢UNION
將兩者放在一個 CTE 中,然後JOIN
s tocohort
理論上可以在加入潛在的**之前消除很多行,從而提高執行效率。cohort
相反,如果行在被聯合的兩個數據集之間都是不同的,但只有一小部分行與
w.id = cohort.id
謂詞匹配,那麼首先單獨處理每個數據集然後處理結果可能會更有效,就像你的第二個查詢一樣。這只是一個例子,當然優化器應該能夠在這兩種情況下找出一個足夠好的執行計劃,但它並不總是完美的。JOIN``cohort``UNION
還有許多其他因素在這裡發揮作用,以及從表的索引方式到伺服器的硬體配置方式。即使在您使用操作員的具體範例中,
UNION ALL
也可能會根據每個查詢執行時的數據內容看到截然不同的執行計劃。此外,絕對沒有辦法具體回答一個查詢在一個數據庫系統與另一個數據庫系統上的行為方式,但總的來說,任何現代關係數據庫系統之間都沒有實質性的性能差異。它們都能夠等效地處理各種類似的場景,每個場景都有自己的特點和現代數據問題的解決方案。