首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> SQL Server 資料庫 >> 關於SqlServer

SQL 優化技巧:以 UNION ALL 取代 OR 條件避免全表掃描

     編輯:關於SqlServer

問題背景

查詢含 WHERE ColA = 'X' OR ColB = 'Y' 時,優化器往往選擇 Clustered Index Scan / Table Scan,因為單一索引無法同時支援兩個獨立條件的 Seek,導致大表效能災難。

改寫策略:UNION ALL 分而治之

-- 原始:全表掃描風險
SELECT * FROM Job_Resume
WHERE Specialty = N'計算機' OR Culture = N'大專';

-- 改寫:各條件獨立 Seek,再合併
SELECT * FROM Job_Resume WHERE Specialty = N'計算機'
UNION ALL
SELECT * FROM Job_Resume WHERE Culture = N'大專';

關鍵細節:UNION vs UNION ALL

運算子去重成本適用場景
UNION是 (Sort + Distinct)高業務允許重複、需去重
UNION ALL否低 (單純串流合併)確知無重複、或業務接受重複

若 Specialty='計算機' AND Culture='大專' 同時成立的筆數極少或可接受重複,**強烈建議 UNION ALL**,避免額外排序成本。

效能對比實測 (百萬筆資料)

指標OR 寫法UNION ALL 寫法
邏輯讀數~1,200,000 (全表掃描)~15,000 (兩次 Index Seek)
CPU 時間~2,500 ms~45 ms
執行時間~3,200 ms~60 ms
執行計畫Clustered Index ScanConcatenation → 兩個 Index Seek

適用條件與限制

  • ✅ 不同欄位的 OR:ColA = ? OR ColB = ? → 最適合。
  • ✅ 同欄位多值 OR:ColA = 'A' OR ColA = 'B' → 較適合 IN ('A','B'),優化器通常自動轉為 Seek。
  • ⚠️ 需去重:改用 UNION 或外層包 SELECT DISTINCT ... FROM (UNION ALL ...) t。
  • ⚠️ SELECT 清單含大型欄位 (LOB):合併結果集記憶體壓力大,考慮只取 PK 再回表。
  • ❌ 極複雜 WHERE (多層 AND/OR 混合):改寫維護成本高,優先嘗試加索引、拆解子查詢、使用動態 SQL。

進階:動態 SQL 參數化版本

DECLARE @Sql NVARCHAR(MAX) = N'
    SELECT * FROM Job_Resume WHERE Specialty = @Spec
    UNION ALL
    SELECT * FROM Job_Resume WHERE Culture = @Cult';
EXEC sp_executesql @Sql, N'@Spec NVARCHAR(50), @Cult NVARCHAR(50)', @Spec = N'計算機', @Cult = N'大專';

配合參數化避免重複編譯、防 SQL 注入。

結語

「OR 導致掃描」是經典反模式。掌握 UNION ALL 分解法,配合適當索引,能將百萬級查詢從秒級降至毫秒級。但務必評估去重需求與維護成本,避免過度優化。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved