SQL Server 擁有強大的**查詢優化器**,它會分析 WHERE 子句、可用索引、統計資料,自動選擇最佳執行計畫。**寫條件順序不影響結果**,優化器會自動重排。但開發者必須撰寫「可優化」的條件(SARG),讓優化器有機會使用索引。
符合以下形式的條件稱為 SARG,優化器可利用索引快速定位:
欄位 運算子 常數/變數
常數/變數 運算子 欄位
欄位 運算子 常數/變數 AND 欄位 運算子 常數/變數 ...
運算子包含:=, >, <, >=, <=, BETWEEN, IN (常數清單), LIKE '前綴%'。
| # | 陷阱 | 失效範例 | 修正寫法 | 原理 |
|---|---|---|---|---|
| 1 | LIKE 開頭萬用字元 | name LIKE '%張' | name LIKE '張%' | 前綴固定才能索引搜尋 |
| 2 | OR 導致全表掃描 | name='張三' OR price>5000 | 拆分為 UNION ALL 或改寫邏輯 | OR 兩側索引難合併 |
| 3 | 否定運算子 | NOT, !=, <>, !<, !>, NOT IN, NOT EXISTS, NOT LIKE | 改用正向條件或覆蓋索引 | 無法透過索引定位「不等於」 |
| 4 | 欄位參與運算/函數 | ABS(price) < 5000YEAR(date_col) = 2023 | price BETWEEN -5000 AND 5000date_col >= '2023-01-01' AND date_col < '2024-01-01' | 運算破壞索引順序 |
| 5 | 隱含轉換 | varchar_col = 123(數字比字串) | varchar_col = '123' | 優化器對欄位做 CONVERT,索引失效 |
| 6 | IN 等同 OR | tid IN (2,3) | 小清單可接受;大清單用 JOIN 臨時表 | 內部展開為 OR |
| 7 | NOT IN 子查詢含 NULL | id NOT IN (SELECT nullable_col FROM t) | NOT EXISTS (SELECT 1 FROM t WHERE t.col = outer.id) | NULL 導致 NOT IN 永遠為 UNKNOWN |
| 8 | EXISTS vs IN 效能迷思 | 傳統認知 EXISTS 優於 IN | 實測**效能相同**,優化器內部轉換相同 | 現代優化器已統一處理 |
| 9 | CHARINDEX vs LIKE '%...%' | CHARINDEX('關鍵字', col) > 0 | 同樣全表掃描,無優勢 | 皆無法使用索引 |
| 10 | UNION 不一定優於 OR | 同欄位 OR 改 UNION 反而變慢 | 同欄位用 IN 或單一範圍條件 | UNION 需合併排序去重 |
| 11 | SELECT * 殺手 | SELECT * FROM t | 只選需要欄位 | 減少 I/O、鎖定、網路傳輸、覆蓋索引機會 |
| 12 | COUNT(*) vs COUNT(col) | 迷思 COUNT(*) 較慢 | 實測 COUNT(*) ≈ COUNT(PK) < COUNT(其他欄位) | 優化器自動選最窄欄位統計 |
| 查詢 | 耗時 | 邏輯讀 |
|---|---|---|
SELECT TOP 10000 gid, fariqi, reader, title FROM tgongwen ORDER BY gid DESC | 4,673 ms | 41,956 |
SELECT TOP 10000 gid, fariqi, title FROM tgongwen ORDER BY gid DESC | 1,376 ms | — |
SELECT TOP 10000 gid, fariqi FROM tgongwen ORDER BY gid DESC | 80 ms | — |
| 排序欄位 | 10,000 筆耗時 | 說明 |
|---|---|---|
| 無 ORDER BY | 196 ms | 依叢集索引自然順序 |
| 叢集索引欄位 (fariqi) | 156-173 ms | **最快**,資料物理順序即邏輯順序 |
| 非叢集索引欄位 (gid-PK) | 4,720-4,736 ms | 需書籤查找/排序運算子 |
結論:排序欄位 = 叢集索引鍵 時效能最高;正序/倒序差異極小。
-- 只需前 10 筆,但子查詢排序 10,000 筆
SELECT TOP 10 * FROM (
SELECT TOP 10000 gid, fariqi, title FROM tgongwen WHERE neibuyonghu='辦公室' ORDER BY gid DESC
) AS a ORDER BY gid ASC;
外層 TOP 10 讓引擎只輸出 10 列,**物理 I/O 大幅降低**,總耗時甚至**小於**子查詢單獨執行時間。善用 TOP 限制中間結果集大小,是大資料分頁、分批處理的核心技巧。
SELECT *?TOP / OFFSET-FETCH 限制?UPDATE STATISTICS / 自動更新)