SQL 優化自資料庫誕生以來即為永恆議題。優化器雖智能,但受限於統計資訊、語法結構、索引設計,仍需開發者遵循核心原則撰寫高效 SQL。本文提煉九大鐵律,配合原理解析與改寫對照,助你避開效能陷阱。
| # | 鐵律 | 錯誤範例 | 優化寫法 | 核心原理 |
|---|---|---|---|---|
| 1 | 按需選欄,拒絕 SELECT * | SELECT * FROM t | SELECT id, name, amt FROM t | 減少 I/O、網路、記憶體;利用覆蓋索引 |
| 2 | 判斷存在用 EXISTS,不用 COUNT(*) | IF (SELECT COUNT(*) FROM t WHERE ...) > 0 | IF EXISTS (SELECT 1 FROM t WHERE ...) | EXISTS 短路,找到一筆即停;COUNT 需全掃 |
| 3 | 優先 EXISTS 替代 IN/NOT IN | WHERE deptno NOT IN (SELECT deptno FROM emp) | WHERE NOT EXISTS (SELECT 1 FROM emp WHERE dept.deptno = emp.deptno) | IN 易退化為全掃;NOT IN 遇 NULL 邏輯陷阱 |
| 4 | NOT IN 改 LEFT JOIN ... IS NULL | WHERE id NOT IN (SELECT id FROM t2) | FROM t1 LEFT JOIN t2 ON t1.id=t2.id WHERE t2.id IS NULL | JOIN 可利用索引、並行,計畫穩定 |
| 5 | 拒絕 OR,改用 UNION ALL | WHERE a=1 OR b=2 | WHERE a=1 UNION ALL WHERE b=2 | OR 導致索引合併失敗,全掃;UNION ALL 分別走索引 |
| 6 | WHERE 條件順序匹配索引順序,範圍從大到小 | 索引 (a,b,c) → WHERE c=1 AND a=2 | WHERE a=2 AND c=1 | 復合索引最左前綴;高選擇性優先 |
| 7 | 優先 >= 避免 > | WHERE id > 100 | WHERE id >= 101 | 邊界值下推,利用索引 Seek 而非 Scan(視統計資訊) |
| 8 | WHERE 禁用函數/運算/隱式轉換 | WHERE SUBSTRING(name,1,3)='abc'WHERE DATEDIFF(day, dt, '2024-01-01')=0 | WHERE name LIKE 'abc%'WHERE dt >= '2024-01-01' AND dt < '2024-01-02' | 欄位運算導致 SARGable 失效,索引不可用 |
| 9 | 深知索引結構,避開失效模式 | WHERE col IS NULL / <> / != / NOT / NOT LIKE | 改寫為正向條件、覆蓋索引、計算欄位+索引 | 負向條件、NULL 判斷、隱式轉換均導致全掃 |
「可用索引尋找的引數」:WHERE 條件必須讓優化器能直接對索引鍵值進行範圍定位。任何欄位側運算、函數、隱式轉換都會破壞 SARGable,迫使 Scan。
即使寫法正確,過期統計資訊或參數嗅探也可能導致錯誤計畫。定期 UPDATE STATISTICS、使用 OPTION (RECOMPILE) 或 OPTIMIZE FOR UNKNOWN 緩解。
每個索引約增加 10~20% 寫入開銷。定期評估 sys.dm_db_index_usage_stats,移除長期未被讀取的索引。
九大鐵律非絕對真理,但覆蓋 90% 以上常見效能問題。養成「先看執行計畫、再寫 SQL、後驗證 IO/時間」的習慣,配合定期索引健檢,才是持續交付高效能 SQL 的正道。