查詢含 WHERE ColA = 'X' OR ColB = 'Y' 時,優化器往往選擇 Clustered Index Scan / Table Scan,因為單一索引無法同時支援兩個獨立條件的 Seek,導致大表效能災難。
-- 原始:全表掃描風險
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 | 是 (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 Scan | Concatenation → 兩個 Index Seek |
ColA = ? OR ColB = ? → 最適合。ColA = 'A' OR ColA = 'B' → 較適合 IN ('A','B'),優化器通常自動轉為 Seek。UNION 或外層包 SELECT DISTINCT ... FROM (UNION ALL ...) t。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 分解法,配合適當索引,能將百萬級查詢從秒級降至毫秒級。但務必評估去重需求與維護成本,避免過度優化。