JOIN 或 APPLY。| 模式 | 問題 | 建議 |
|---|---|---|
IN (子查詢) | 轉換開銷、統計不準 | 改用 EXISTS |
NOT IN | 無法用索引、NULL 陷阱 | 改用 NOT EXISTS 或 LEFT JOIN ... WHERE IS NULL |
IS NULL / IS NOT NULL | 索引不生效(NULL 不入索引) | 業務允許時用預設值 >0、>'' 替代 |
> / < | 邊界值掃描 | >= 直接定位首符合值 |
LIKE '%abc%' | 前導萬用字元掃全表 | 改 LIKE 'abc%' 或全文檢索 |
UNION | 排序去重耗資源 | 無重複時用 UNION ALL |
列聯接 col1+col2 | 函數導致索引失效 | 拆分為 col1=... AND col2=... |
ORDER BY 運算式 | 需排序無索引 | 建立計算欄位索引或應用層排序 |
NOT / <> | 負向邏輯掃全表 | 改寫為正向 OR 範圍 |
WHERE 條件:選擇性最高(過濾率最低)的寫最前(舊版優化器自下而上解析),新版自動重排但好習慣仍有益。FROM 表順序:小表/篩選後小結果集寫前面(舊版依序連接),新版自動重排。SUBSTR(col,1,4)='5400' → col LIKE '5400%';col+5=10 → col=5。WHERE varchar_col = 123 → WHERE varchar_col = '123'。ALTER INDEX ... REBUILD 消除碎片,更新統計資訊。DISTINCT → EXISTS(一對多去重)。HAVING → WHERE 前置過濾(分組前先過濾)。DELETE 全表 → TRUNCATE(最小日誌、重置種子,DDL 不可回滾)。COMMIT 釋放鎖、日誌空間。GROUP BY 前置 WHERE 過濾。WHERE id > @lastId) 替代 OFFSET。DISTINCT, UNION, MINUS, INTERSECT, ORDER BY 觸發 SORT,評估 SORT_AREA_SIZE 記憶體設定。
SELECT TOP 20
EXECUTIONS, DISK_READS, BUFFER_GETS,
ROUND((BUFFER_GETS-DISK_READS)/BUFFER_GETS,2) AS Hit_Ratio,
ROUND(DISK_READS/EXECUTIONS,2) AS Reads_Per_Run,
SQL_TEXT
FROM V$SQLAREA -- Oracle 視圖,SQL Server 對應 sys.dm_exec_query_stats
WHERE EXECUTIONS > 0 AND BUFFER_GETS > 0
AND (BUFFER_GETS-DISK_READS)/BUFFER_GETS < 0.8
ORDER BY Hit_Ratio;
優化核心:減少掃描、利用索引、避免排序、重用計畫。每條規則皆有適用場景,實測為準,切勿教條套用。