[效能調教] 避免使用 CTE 串接大量資料

使用 CTE 的出發點應是增加 TSQL 可讀性,但是在濫用的情況下對於效能的衝擊是相當大,因此請在發生 DB 效能問題的時候,不仿也考慮一下 CTE 是否為效能瓶頸的重要關鍵。

前言


針對 CTE 使用上的限制及特性在網路上眾說紛紜,因此很難定義出何謂濫用,但有一些大家共同的經驗可以稍微整理一下,並且透過筆者近期協助調整系統效能的深刻體驗,分享一下「這樣使用」CTE 對於系統效能的衝擊有多大。

實際案例


目前系統都是以 Stored Procedure 對資料庫進行操作,其中有三隻 SP 中大量的使用 CTE 串接 (使用 8 組 CTE 查詢依序串接),且其中有一張資料表資料量約 120000 筆左右,造成該 API 回應時間為 1521 ms 過高,並且在負載測試下的效能更是慘不忍睹;筆者之前完全沒有想到 CTE 有什麼問題,所以調整效能的方向都在調整 CTE內所使用的 TSQL 語法,看看是否有可以改善的空間,但是效果不彰。

就在筆者陷入苦思效能瓶頸的瓶頸時,意外看到 Bruce 大的 COMMON TABLE EXPRESSION (CTE) 教學重點筆記 這篇文章,內容提到「在Store Procedure使用CTE,會造成每次執行都會re-compiler,效能低落」且下方留言又有見證者回報,著實讓我有所頓悟,是條可以值得一事的方向。

因此索性就將三隻 SP 中的所有 CTE 調整為 Temp Table 使用,而原本存在各 CTE 的 TSQL 語法邏輯原封不動地轉換為 Temp Table,在單次測試後得到以下的數據,該 API 回應時間從 1521 ms 降至 441 ms,足足節省一秒左右的時間(灑花+旋轉),接著在負載測試下仍保持相同的回應時間,著實讓我又驚又喜阿。

 

使用 CTE 經驗


當然這只是我的使用情境,因此筆者還是試圖收集廣大網民智慧,想要有個佐證文獻可以依循,但無奈官方文件似乎沒有提及到這塊(如果有再麻煩提供給小弟,感激不盡),因此從熟悉資料庫的友人及網路上的討論串歸納出以下幾點,希望在未來使用 CTE 上更加注意,避免悲劇再度產生:

  • 面對少量資料可使用 CTE 增加可讀性

  • 資料量大於 5000 筆建議使用 Temp Table 取代 CTE

  • CTE 最適合處理遞迴狀況

 

總結


筆者認為 CTE在使用上確實非常方便,可讀性也相當高,但是若串接過多似乎會造成效能衝擊(結果論),本篇僅針對筆者實際遇到的案例作紀錄,如果有熟知 CTE 特性的前輩,在請不吝指導開釋一下了。

 

參考資訊


How to Write Optimized Stored Procedures

Which are more performant, CTE or temporary tables?
 


希望此篇文章可以幫助到需要的人

若內容有誤或有其他建議請不吝留言給筆者喔 !