Query-Performance

稍後加入較小表的 WITH 表的性能

  • September 9, 2021

我正在嘗試開發一個通用框架,用於從大型數據庫中獲取分塊隊列。由於各種因素,這樣寫查詢很方便:

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 中,然後JOINs tocohort理論上可以在加入潛在的**之前消除很多行,從而提高執行效率。cohort

相反,如果行在被聯合的兩個數據集之間都是不同的,但只有一小部分行與w.id = cohort.id謂詞匹配,那麼首先單獨處理每個數據集然後處理結果可能會更有效,就像你的第二個查詢一樣。這只是一個例子,當然優化器應該能夠在這兩種情況下找出一個足夠好的執行計劃,但它並不總是完美的。JOIN``cohort``UNION

還有許多其他因素在這裡發揮作用,以及從表的索引方式到伺服器的硬體配置方式。即使在您使用操作員的具體範例中,UNION ALL也可能會根據每個查詢執行時的數據內容看到截然不同的執行計劃。

此外,絕對沒有辦法具體回答一個查詢在一個數據庫系統與另一個數據庫系統上的行為方式,但總的來說,任何現代關係數據庫系統之間都沒有實質性的性能差異。它們都能夠等效地處理各種類似的場景,每個場景都有自己的特點和現代數據問題的解決方案。

引用自:https://dba.stackexchange.com/questions/299286