SQL 效能優化分析
問題摘要
這段查詢的主要負擔不在單一 JOIN,而是多個高成本操作疊加:
- 每列重複執行相關子查詢,特別是 FOR XML PATH 的 HoldReasonC 與 HoldReasonE。
- 第三段使用 CASE WHEN ... 形成非 SARGable 條件,索引利用率差。
- DISTINCT 可能掩蓋了 join 膨脹,但本身會增加排序或 hash 成本。
- CreditControl 區塊可能存在乘積放大風險,因為 detail 與 product 兩張表只用 FormNo 串接。
- 外層 SELECT * 會增加 I/O、記憶體與網路傳輸成本。
高優先級優化建議
1. 移除 correlated subquery
目前每一列都會對 command table 再掃一次,成本很高。應改成先對 command table 依 (FormNo, HoldSourceId, OrderHoldId) 聚合,再 LEFT JOIN 回主查詢。
如果 SQL Server 版本支援,可優先用 STRING_AGG;若版本較舊,再用 XML 聚合,但也要先彙總後再 join。
2. 改寫非 SARGable 條件
這段條件:
WHERE (CASE WHEN A.OrderNumber IS NOT NULL THEN A.OrderNumber ELSE B.OrderNumber END) = @trxReferenceNo
建議改成:
WHERE (A.OrderNumber = @trxReferenceNo) OR (A.OrderNumber IS NULL AND B.OrderNumber = @trxReferenceNo)
更好的方式是直接拆成兩段 UNION ALL,讓每段都能更容易走索引。
3. 檢查 DISTINCT 是否必要
如果是因為 join 寫法導致重複,應修正關聯鍵,而不是用 DISTINCT 事後去重。
4. 修正 CreditControl 的 join 粒度
CreditControlFormDetail 與 CreditControlFormDetailProduct 目前都只依 FormNo 連接,這很容易把資料量放大成 N x M。
應確認是否還有其他明確關聯鍵,例如 detail id、line number 或 product key,避免無意間拉爆結果集。
5. 不要用 SELECT *
外層應只保留真正需要的欄位,減少資料搬運成本。
索引建議
Header / Line 表
- SoChgFormHeader(OrderNumber, Tenant, FormNo)
- SoChgFormLine(Tenant, FormNo)
- NewSoFormHeader(OrderNumber, Tenant, FormNo)
- NewSoFormLine(Tenant, FormNo)
- PriceControlFormHeader(OrderNumber, Tenant, FormNo)
- PriceControlFormLine(Tenant, FormNo)
Command 表
- SoChgHoldCommand(FormNo, HoldSourceId, OrderHoldId)
- NewSoHoldCommand(FormNo, HoldSourceId, OrderHoldId)
- PriceControlHoldCommand(FormNo, HoldSourceId, OrderHoldId)
並視查詢欄位加入 INCLUDE(HoldReasonC, HoldReasonE)。
CreditControl 表
- CreditControlForm(SoDoNumber, FormNo)
- CreditControlFormDetail(FormNo, ...)
- CreditControlFormDetailProduct(FormNo, ...)
實際索引欄位仍要依真正的關聯鍵補齊。
進一步優化
- ROW_NUMBER() OVER (ORDER BY FormNo) 會觸發排序;如果只是畫面顯示序號,可在應用層處理。
- NOLOCK 不會根治效能問題,只是降低鎖等待的表象,還會帶來髒讀與重複讀風險。
- 如果 @trxReferenceNo 的資料分布很偏斜,可評估 OPTION (RECOMPILE),但要先測試實際計畫。
下一步建議
- 先看實際 execution plan,確認是否卡在 lookup、scan、sort 或 hash join。
- 先重寫 HoldReason 聚合邏輯,這通常是最直接的降 DTU 手段。
- 再檢查 CreditControl 的 join 是否造成結果膨脹。