許多開發者聽聞「IN 不符合 SARG(Search ARGument)標準,會導致全表掃描」,因此傾向改寫為 UNION ALL。但這觀點僅適用於早期資料庫版本。SQL Server 2005 之後,優化器對 IN、OR 等邏輯有顯著增強,本文透過實測執行計畫,揭示兩者在不同資料量下的真實表現。
Member(百萬筆),proxyID 上有非叢集索引WHERE proxyID IN ('ID1','ID2',...)WHERE proxyID='ID1' UNION ALL SELECT ... WHERE proxyID='ID2' ...Index Seek + Filter,優化器將 30 個值轉為內部篩選邏輯,一次掃描索引即可。Index Seek 透過 Concatenation 串聯,每個分支各自求值再合併。代理商編號較多時,UNION ALL 效率顯著優於 IN。IN 的 Filter 操作需在記憶體中比對 30 個值,隨值增多 CPU 開銷線性增長;UNION ALL 則利用索引精準定位各分支,並行潛力大。
| 代理商數量 | IN 執行計畫 | UNION ALL 執行計畫 | 耗時差異 |
|---|---|---|---|
| 2 個 | Nested Loops(2 次 Index Seek) | Concatenation(2 次 Index Seek) | 幾乎相同 |
| 6 個 | Nested Loops(6 次 Index Seek) | Concatenation(6 次 Index Seek) | 差距極小 |
| 15 個 | 單一 Index Seek + Filter | Concatenation(15 次 Index Seek) | UNION ALL 略快 |
可見優化器會根據值的數量自動切換策略:值少時轉為 Nested Loops(類似 UNION ALL),值多時改用單一 Seek + Filter。此時兩者效能趨近。
IN,可讀性最佳。UNION ALL 或臨時表/表值參數(TVP)批次傳入。OR 條件,高版本優化器同樣能有效處理。資料庫引擎持續演進,早期經驗法則(如「IN 不走索引」、「OR 不走索引」)在新版本多已失效。正確做法是:
SET STATISTICS IO, TIME ON 實測。Actual Execution Plan 而非估計計畫。Logical Reads、CPU Time、Elapsed Time 三大指標。