星期一, 8月 20, 2018

[SQL] 避免欄位比較

閱讀 Microsoft SQL Server Performance Tuning 效能調校的 SARG 介紹時,提到 [資料欄位 運算子 資料欄位] 是不符合 SARG 原則,以往看到的資料大多是強調 [資料欄位 符合 SARG 運算子 <常數或變數>] 符合 SARG,最近調校有剛好發現很多 [資料欄位 運算子 資料欄位] 語法,不太能從 TSQL 語法變化來提升效能,所以重新閱讀書籍內容時特別有感

SARG 意義

在查詢子句中,SARG 代表用來搜尋的常數或變數可以直接與索引鍵值做比較 

SARG 運算子列表

  • 符合:=、<、>、>=、<=、BETWEEN、LIKE (看 % 位置) 
  • 不符合:NOT、!=、<>、!>、!<、NOT EXISTS、NOT IN、NOT LIKE 

SARG 格式理論

  • 符合:
    • 資料欄位 符合 SARG 運算子 <常數或變數>
    • <常數或變數> 符合 SARG 運算子 資料欄位
  • 不符合:資料欄位 運算子 資料欄位

案例說明

物流申請例子來說明,商業邏輯很簡單派車單 (檔頭、檔身) 搭配物流申請,物流單申請可以存在多張多張派車單內,所以要知道待運送的物流申請資料,必須用下述語法去比對出來
SELECT
  T.*
  , D.物流單編號
  , ISNULL(D.已運輸數量, 0) AS 已運輸數量
FROM 物流申請 AS T
  LEFT JOIN 
    (
      SELECT
        物流單編號
        , SUM(已運輸數量) AS 已運輸數量
      FROM 派車檔身
      GROUP BY 物流單編號
    ) AS D ON T.物流單編號 = D.物流單編號
WHERE (D.物流單編號 IS NULL        -- 物流申請還未派車
  OR T.物流申請數量 > D.已運輸數量) -- 物流申請已經派車,但還未完全派車完

當時這樣設計看執行 Statistics 覺得很 OK、還覺得執行計劃有跑出平行處理很不錯,時過境遷後,現在看到平行處理就覺得事情不尋常,Orz

醜醜的執行計畫,物流申請和派車檔身都跑 Clustered Index Scan 來處理

有該篇 - [SQL] 利用 UNION ALL 取代 OR 條件 經驗,當然是要來嘗試一下
-- 物流申請還未派車
SELECT
  T.* ,
  0 AS 已運輸數量
FROM 物流申請 AS T
WHERE NOT EXISTS
  (
    SELECT 1 FROM 派車檔身 AS D WHERE T.物流單編號 = D.物流單編號
  )
UNION ALL
-- 物流申請已經派車,但還未完全派車完
SELECT
  T.*
  , D.已運輸數量
FROM 物流申請 AS T
  JOIN
    (
      SELECT
        物流單編號
        , SUM(已運輸數量) AS 已運輸數量
      FROM 派車檔身
      GROUP BY 物流單編號
    ) AS D ON T.物流單編號 = D.物流單編號
WHERE T.物流申請數量 > D.已運輸數量

改完之後發現更慘,Statistics 為原本兩倍左右,執行計畫也肥了不少

無法從語法獲得改善,就只能動 Table Schema 來改善囉

沒有留言:

張貼留言