2012-07-10 75 views
2

我應該爲每個別名表達式使用單獨的CROSS APPLY還是在可能的情況下在同一個CROSS APPLY中定義多個表達式?交叉應用樣式與性能

我正在重構代碼中生成的許多非常複雜的SQL查詢(通常是四個或五個頁面,一連十個JOIN)。通常它們嵌套五六個深度的查詢,因爲某些部分在不同情況下被重用。嵌套查詢的一個典型原因是一個查詢提取一些值,執行計算併爲該值分配一個別名。然後,封閉查詢使用別名值進行進一步計算等。這是必要的,因爲別名表達式只能在外部查詢中引用,而不在查詢中定義它的其他地方引用。 (代碼中也存在的替代方法是在整個查詢中重複相同的冗長子表達式十次)。爲了簡化此意大利麪SQL,我開始使用CROSS APPLY摺疊這些伸縮式查詢。通過使用CROSS APPLY,我可以分配一個別名並在同一查詢的其他地方使用該別名。請注意,我的CROSS APPLY子句中沒有一個通過子查詢引入新表,或者調用UDF。

起初,我把很多表達式放在同一個CROSS APPLY中。但是,我的代碼需要模塊化。在不同情況下需要不同的字段,因爲用戶可以爲過濾器選擇字段,並且我們爲不同的列生成類似的統計信息,因此會創建許多類似的查詢,這些查詢之間的差異很小。由於某些字段建立在其他字段之上,並且某些字段依賴於在查詢中早些時候定義的某些JOIN,所以我不能將所有字段放在相同的CROSS APPLY中。因此,CROSS APPLY的數量可能會有所不同。因此,當CROSS APPLY定義的字段在其他地方被引用時,CROSS APPLY的表別名將需要被提取的一些字段被新的別名覆蓋並重新定義(通常用於刪除NULL,提供默認值等)。以指定消除歧義。

這樣做的結果是,我需要一個合乎邏輯的方式來命名我的CROSS APPLY,並且我關心性能。如果CROSS APPLY的數量發生變化,那麼如果CROSS APPLY使用簡單的計數器編號(例如,computed1,computed2等),那麼給定的字段可能會將其名稱參考從computed3。[FIELD NAME]更改爲computed4。[FIELD NAME]在整個查詢的其餘部分都會產生漣漪效應,這可能是通過調用不同的C#過程來組合的。這是一個維護問題。

我正在考慮的替代方法是將每個計算表達式放在單獨的CROSS APPLY中,並且CROSS APPLY的名稱將從表達式的別名派生而來。例如:使用

一個CROSS APPLY:

CROSS APPLY (
    SELECT 
      [TIV_BLDG] = (CASE [COVERAGE] WHEN 'TIV_BLDG' THEN VALUEAMT ELSE 0 END) 

     , [TIV_OSTR] = (CASE [COVERAGE] WHEN 'TIV_OSTR' THEN VALUEAMT ELSE 0 END) 

     , [TIV_CONT] = (CASE [COVERAGE] WHEN 'TIV_CONT' THEN VALUEAMT ELSE 0 END) 

     , [TIV_TIME] = (CASE [COVERAGE] WHEN 'TIV_TIME' THEN VALUEAMT ELSE 0 END) 

) computed2 

使用四個交叉APPLYs:

CROSS APPLY (SELECT [TIV_BLDG] = (CASE [COVERAGE] WHEN 'TIV_BLDG' THEN VALUEAMT ELSE 0 END)) AS [TIV_BLDG_COMP] 

CROSS APPLY (SELECT [TIV_OSTR] = (CASE [COVERAGE] WHEN 'TIV_OSTR' THEN VALUEAMT ELSE 0 END)) AS [TIV_OSTR_COMP] 

CROSS APPLY (SELECT [TIV_CONT] = (CASE [COVERAGE] WHEN 'TIV_CONT' THEN VALUEAMT ELSE 0 END)) AS [TIV_CONT_COMP] 

CROSS APPLY (SELECT [TIV_TIME] = (CASE [COVERAGE] WHEN 'TIV_TIME' THEN VALUEAMT ELSE 0 END)) AS [TIV_TIME_COMP] 

如果我用這個多CROSS應用的方法,我可以很容易地生成的名稱不會改變如果我添加新的應用或刪除它們,並且我可以在代碼中預測引用字段什麼是表別名。但是,這意味着更多的CROSS APPLY語句。性能影響是什麼?有沒有更好的方法來做到這一點,使用CROSS APPLY或其他SQL Server功能? (我不需要這是跨數據庫,所以只有微軟的功能很好。)

+1

Nit:查詢計劃員應該能夠在RA規則中摺疊「額外的別名」就好(例如完全將他們從計劃中刪除)。它甚至應該刪除未引用的選定值,並推遲這一事實,等等。在任何情況下,*查詢計劃應該是第一個注意識別性能瓶頸的地方。 – 2012-07-10 18:28:57

+1

無論如何,我使用了一些自動SQL生成(沒有交叉應用,但是有許多嵌套聯接和一些聯合等)。要處理列名稱更改,我還通過每個選擇來跟蹤列名稱(我返回一個表示列名*和*目標表/別名的結構)。然後在每個級別上,我基於新選擇的「視圖」重新生成結構,並更新/放棄列和目標表/別名。使用這種方法,我避免了級別之間別名的大量硬編碼,並允許最終/外部查詢僅適當地選擇內部列。 SQL Server喜歡它。 – 2012-07-10 18:31:35

回答

0

如果存在性能劣勢,它必須處於查詢執行的編譯階段。隨着執行計劃被緩存,第二次執行查詢的時間將不會有任何性能損失。

SQL Server可以查看CROSS APPLY並將它們轉換爲簡單的堆疊「計算標量」。

另一個潛在的問題可能是查詢的大小。不知道AST節點或連接數是否有任何相關限制(我認爲CROSS APPLY在內部限制方面算作連接)。

除了這些問題,我認爲CROSS APPLYs是一個非常好的和快速的解決方案。