SQL 語句品質直接決定資料庫負載與回應速度。本文提煉 9 大優化鐵律,涵蓋欄位提取、存在性判斷、IN/EXISTS 抉擇、JOIN 替代、OR 陷阱、WHERE 順序、比較運算子選擇、索引失效模式、運算下推,附反面教材與正確寫法對照。
-- 差
SELECT * FROM Orders;
-- 好
SELECT OrderID, CustomerID, OrderDate FROM Orders;
每減少一欄位即降低網路傳輸、記憶體佔用、緩衝區壓力。
-- 差
IF (SELECT COUNT(*) FROM Table WHERE ...) > 0
-- 好
IF EXISTS (SELECT 1 FROM Table WHERE ...)
EXISTS 支援短路:找到第一筆即停止,COUNT(*) 必須掃描所有符合列。
-- 差 (IN 效能較低,NULL 值語義陷阱)
SELECT * FROM Dept WHERE DeptNo NOT IN (SELECT DeptNo FROM Emp);
-- 好 (EXISTS 穩定高效)
SELECT * FROM Dept WHERE NOT EXISTS (SELECT 1 FROM Emp WHERE Dept.DeptNo = Emp.DeptNo);
SELECT D.*
FROM Dept D
LEFT JOIN Emp E ON D.DeptNo = E.DeptNo
WHERE E.DeptNo IS NULL;
JOIN 可利用索引與統計資訊,優化器選擇空間更大。
-- 差:OR 通常使索引失效
SELECT * FROM Table WHERE Col1 = 'A' OR Col2 = 'B';
-- 好:UNION ALL 分開走索引再合併
SELECT * FROM Table WHERE Col1 = 'A'
UNION ALL
SELECT * FROM Table WHERE Col2 = 'B' AND Col1 <> 'A';
(A, B, C) → WHERE 條件順序盡量符合 A, B, C。-- 等價但 >= 可能利用索引邊界更精確
WHERE Id >= 100 -- 優於 WHERE Id > 99
| 失效模式 | 範例 | 修正 |
|---|---|---|
| 函數包裹欄位 | WHERE SUBSTRING(Id,1,1)='A' | WHERE Id LIKE 'A%' |
| 欄位參與運算 | WHERE Result*10 > 30 | WHERE Result > 3 |
| 隱含轉換 | WHERE VarcharCol = 123 | WHERE VarcharCol = '123' |
| 負向運算子 | WHERE Col <> 'X', NOT IN, NOT EXISTS | 改用正向邏輯或 JOIN |
| IS NULL | WHERE Col IS NULL | 考慮過濾索引或計算欄位 |
核心原則:WHERE 子句中任何對欄位的操作 (函數、計算) 都會導致索引失效,應盡可能將運算移至常數側。
將這 9 原則內化為寫碼肌肉記憶,能從源頭消除 80% 以上的效能隱憂。