2012-07-12 48 views
3

忍受着我,我是中級新手。如何決定是否應該使用CTE?

我的問題是 - 當我應該使用CTE?我如何決定是否應該使用CTE?

什麼時候應該使用這樣的:

;with cteTesting as 
(
    select * 
    from testing.first_table 
) 
select * 
from testing.second_table s 
     inner join cteTesting t 
      on s.key = t.key 

在此:

select * 
from testing.second_table s 
     inner join 
     (
      select * 
      from testing.first_table 
     ) t 
     on s.key = t.key 

爲什麼呢?這只是代碼流,代碼可讀性 - 還是有更多的技術?在某些情況下,會有更好的執行計劃嗎?

編輯:剛剛意識到我的示例代碼示例是非常差的。我試圖強調,在很多情況下,我可以在from語句而不是CTE中使用select,如何決定我應該使用哪一個?

回答

5

對於簡單的例子,它並沒有太大的差別。如果您需要使用Recursive功能來構建層次結構,那麼您沒有太多選擇 - 您需要使用CTE。

另一種情況下,它可能並沒有太大的性能差異,但確實爲便於閱讀,是當你需要在同一子查詢中多次加入。如果您使用子查詢,則必須重複整個表達,而與熱膨脹係數,你只需要使用名稱兩次:

;With NamedExpression as (
    select t1.ID,t2.ID as ID2,SUM(t3.Value) as Val 
    from 
     Table1 t1 
     left join 
     Table2 t2 on t1.id = t2.t1id 
     inner join 
     Table3 t3 on t3.col = t1.id or t3.col2 = t2.id 
    group by 
     t1.ID,t2.ID 
) 
select 
    * 
from 
    NamedExpression ne 
     inner join 
    NamedExpression ne2 
     on 
      ne.ID2 = ne2.ID 

還應當指出的是,如果你做了以上的子查詢,和表情特別複雜,有時可能需要時間讀/維護者,以驗證兩個子查詢實際上是相同的,並且有兩個


有一些細微的差別不同時,如果你有一個表示子查詢應該進一步出現的縮進樣式比其封閉的查詢權,那麼建立在其他表達式都可能會導致所有的代碼轉移到右側 - 而用熱膨脹係數,你停下並返回到左建立各子表達式(CTE):

;WITH CTE1 AS (
    SELECT 
    ... 
), CTE2 as (
    SELECT 
    ... 
    FROM CTE1 
), CTE3 as (
    SELECT 
    ... 
    FROM CTE2 
) 
select * from CTE3 

VS:

select * 
from 
    (
     select ... 
     from 
      (
       select ... 
       from 
        (
          select ... 
+0

非常詳細 - 謝謝你。將探索這一點,但這一切看起來像選擇CTE – Codingo 2012-07-12 07:43:31

4

親自找到CTE版本更具可讀性,特別是如果選擇變大。

當您使用派生表超過主一旦選擇它可能是最好使用CTE,因爲它告訴您要一次運行該數據庫。雖然我不會感到驚訝,如果優化是足夠聰明來檢測在FROM子句中兩個相同的子選擇和只運行過一次:

with foo as (
    select .. 
    from bar 
) 
select f1.* 
from foo f1 
    join foo f2 on ... 

select f1.* 
from (select ... from bar) f1 
    join (select ... from bar) f2 on ... 

我覺得最重要的部分是要保持一致(跨越你寫的和你的團隊內部)。

+0

SQL Server不一般跑多次提到有一次甚至同一CTE [沒有一些黑客(http://connect.microsoft.com/SQLServer/feedback/details/218968/)讓共同表達子單獨看在不同的派生表中很不幸。 – 2012-07-12 08:56:58

+0

@MartinSmith:謝謝你提供的信息。我認爲SQL Server優化器至少會像Oracle或PostgreSQL那樣聰明。 – 2012-07-12 09:22:37

2

我注意到聯接(ESP。當與大量WHERE子句結合使用時)在涉及大型數據集時可能會造成災難性的性能。

熱膨脹係數可以通過只選擇相關記錄,並加入了這些子集解決此問題。

考慮一個CTE爲一種的預選擇爲最終SELECT準備數據。我用的CTE

+0

Hmn非常令人信服的理由。值得多思考。這次真是萬分感謝 – Codingo 2012-07-12 07:42:56

2

的另一個原因是不是要取代派生表,但要保證複雜的報告SQL包含正確的記錄。所以假設你正在做某種類型的財務報告,並且你想確保你完全返回你想要的記錄。當你有10個連接時,很難判斷數據是否正確。

因此,我使用CTE構建了一個複雜的查詢片段。例如,我只想要符合特定標準的訂單。第一個CTE是挑選出來的那個。我寫它,然後在CTE上運行一個選擇。這告訴我我的訂單數量,因此當我增加複雜性時,我可以直接看到數字更改的位置,並確定它是否應該更改,或者是否需要更改查詢。如果我需要左連接或內連接,或者如果我可能需要相關表上的條件將其限制爲一條記錄,這可以讓我很快知道。

通常當我這樣做,我會已鏈接CTES之前,我的最終選擇是要簡單得多。更進一步的價值在於,我發現在需要更改這些查詢時,維護這些複雜的報表查詢要容易得多。因此,假設我有熱膨脹係數在這樣一個鏈條:

  • 訂單
  • 成本彙總表
  • 客戶人口統計

然後,當我需要改變我是如何做的成本計算財產以後,它是更容易找到更改的位置,更容易檢查最終結果。

相關問題