包含 INCLUDE 的多個非索引視圖與高寫入情況下的多個索引視圖
當您想封裝 T-SQL 以從相同的基表中選擇不同的數據子集時,將普通視圖與非聚集索引和基表上的 INCLUDE 結合使用更有效,還是使用多個索引視圖更好,即使寫入頻繁?
背景:我遇到了一個設計問題,如果我處理不正確,可能會導致很多問題,所以我想要一些關於如何最好地解決它的回饋。本質上,我有一系列主要由浮點列組成的表,我需要在數百個查詢中加入這些表,每個查詢都檢索相同列的無數子集,並以相似但並不總是相同的方式將它們連接在一起。為了便於維護、程式碼易讀性、模組化等,我會盡可能多地封裝 T-SQL 中跨查詢的共性。例如,在下面的範常式式碼中,我在第二個查詢中選擇了與第一個查詢中略有不同的列列表,並連接到第三個表;有幾十個這樣的類似 SQL 語句的排列分散在數百個查詢中。
儲存過程範例 1
; WITH CTE1 AS (SELECT T1.ID, Column1, Column2, Column3, Column4, Column3InTable2, Column5InTable3 FROM Table1 AS T1 INNER JOIN Table2 AS T2 ON T1.ID = T2.ForeignKeyID ) UPDATE T1 SET Column1 = Whatever FROM Table1 AS T1 INNER JOIN CTE1 AS T1 ON T1.ID = T2.ID
儲存過程範例 2
; WITH CTE1 AS ( SELECT T1.ID, Column1, Column2, Column3, Column5, Column3InTable2, Column2InTable3, Column3InTable3 FROM Table1 AS T1 INNER JOIN Table2 AS T2 ON T1.ID = T2.ForeignKeyID INNER JOIN Table3 AS T3 ON T1.ID = T3.ForeignKeyID ) UPDATE T1 SET Column3InTable3 = Whatever FROM Table1 AS T1 INNER JOIN CTE1 AS T1 ON T1.ID = T2.ID
我想使用的是簡化的檢索結構,如下所示:
CREATE VIEW View1 AS SELECT T1.ID, Column1, Column2, Column3, Column4, Column3InTable2, Column5InTable3 FROM Table1 AS T1 INNER JOIN Table2 AS T2 ON T1.ID = T2.ForeignKeyID CREATE VIEW View2 AS SELECT T1.ID, Column1, Column2, Column3, Column5, Column3InTable2, Column2InTable3, Column3InTable3 FROM Table1 AS T1 INNER JOIN Table2 AS T2 ON T1.ID = T2.ForeignKeyID INNER JOIN Table3 AS T3 ON T1.ID = T3.ForeignKeyID
儲存過程範例 1 更新
UPDATE T1 SET Column1 = Whatever FROM View1
儲存過程範例 2 更新
UPDATE View2 SET Column3InTable3 = Whatever
根據經驗,我已經了解到通過表值函式檢索數據會導致性能下降,當我在這些查詢所需的所有列組合上創建單個索引臨時表時,性能得到顯著改善。不幸的是,創建不同的臨時表只檢索每個查詢所需的數據子集,很快就會變成維護和協調的噩夢。因此,我仍然需要在每個過程中將復雜的連接引用到同一個廣泛的臨時表,這根本無助於我對事物的模組化。理想情況下,我想使用視圖來封裝程式碼(看看當它們引用視圖時閱讀上面的範例有多容易),但我想為我的幾十個基本查詢中的每一個創建不同的索引視圖需要會迅速降低性能,因為每次讀取時,所有基表都會以幾乎 1:1 的比例頻繁更新。我是否可以通過使用一系列非索引視圖僅對我需要的列進行操作來解決此問題,同時僅使用為每個列子集量身定制的一系列 INCLUDE 子句索引基表,或者我注定要遇到由於頻繁更新而導致相同的性能下降?
值得慶幸的是,我只需要在任何給定語句中更新一個基表,因此在單個視圖中更新多個表的限制不是問題(通常,我只需要檢索其他表即可計算新值更新的列)。主要是更新的頻率使我的封裝工作複雜化。在閱讀了有關設計索引視圖和索引的這些 Microsoft 文章以及執行緒中的回複使用索引視圖進行聚合之後 - 好得令人難以置信?我還沒有看到任何會阻止我使用這種方法的東西。也許還有一個更好的我還沒有想到的。我還玩弄了將這些視圖分層建構以節省更多程式碼的想法,但不知道這是否會使事情進一步複雜化。提前感謝您的任何建議。
如果您以前的多語句表值函式 (MSTVF) 解決了您的問題,但以性能為代價,那麼您應該將這些函式重寫為內聯表值函式 (ITVF)。
MSTVF 對每一行執行一次。切換到內聯表值函式,然後將該函式交叉應用到您的查詢將意味著該函式僅執行一次。您應該會看到這種方法顯著提高了性能。
有關更多資訊,請參閱Wayne Sheffield的比較內聯和多語句表值函式文章。