因歷史設計缺陷,主鍵/外鍵長度不一致 (如主表 `CHAR(20)`,從表 `CHAR(30)`),導致短鍵值在長欄位中以空白填充。開發者為了關聯查詢,在 `WHERE` 條件雙邊套用 `TRIM()`:
-- 低效寫法:雙邊函數導致索引失效
SELECT A.Key, B.Key, C.Key
FROM TableA A, TableB B, TableC C
WHERE TRIM(A.Key) = TRIM(B.FKey) AND TRIM(A.Col) = TRIM(C.PKey);
| 查詢場景 | 耗時 | 備註 |
|---|---|---|
| 雙表 JOIN (A 200行, B 4萬行) + 雙邊 TRIM | ~1 秒 | 尚可接受 |
| 三表 JOIN (加入 C 2行) + 雙邊 TRIM | ~70 秒 | 效能崩塌,慢 70 倍 |
| 三表 JOIN + 單邊 TRIM (僅右側) | ~1 秒 | 恢復正常速度 |
核心原則:將函數運算移至「非索引鍵」或「常數/參數」側,保留驅動表索引欄位「裸露」。
-- 優化寫法:僅對「髒資料側」 (長欄位/從表) 做 TRIM
SELECT A.Key, B.Key, C.Key
FROM TableA A
INNER JOIN TableB B ON A.Key = TRIM(B.FKey) -- A.Key 有索引,B.FKey 無索引或髒資料
INNER JOIN TableC C ON A.Col = TRIM(C.PKey); -- 同理
「WHERE 條件裡,索引欄位要裸奔,髒資料欄位才包函數。」
永遠檢視執行計畫:是否出現Table Scan或Index Scan而非Index Seek?若是,檢查是否有函數、隱含轉換、或運算符導致 SARGable 失效。