相同結果的 SQL,不同寫法效能可差距數十倍。優化三大支柱:**索引設計**、**聯接條件完整性**、**WHERE 子句可優化性**。
record,620,000 列
-- 查詢 1:日期範圍 + 金額條件
SELECT COUNT(*) FROM record
WHERE date > '19991201' AND date < '19991214' AND amount > 2000; -- 25 秒
-- 查詢 2:分組彙總
SELECT date, SUM(amount) FROM record GROUP BY date; -- 55 秒
-- 查詢 3:日期範圍 + 地點 IN 條件
SELECT COUNT(*) FROM record
WHERE date > '19990901' AND place IN ('BJ','SH'); -- 27 秒
分析:date 重複值極多,非叢集索引下資料物理順序隨機,範圍查詢需掃描大量資料頁(Bookmark Lookup 開銷大)。
-- 同三個查詢分別:14 秒、28 秒、14 秒
分析:叢集索引使資料按 date 物理有序,相同值相鄰。範圍查詢只需定位起訖點掃描連續頁面,避免全表掃描與書籤查找,速度大幅提升。
-- 查詢 1:26 秒(未用 place,索引失效)
-- 查詢 2:27 秒
-- 查詢 3:< 1 秒(用了 place,索引命中)
分析:複合索引遵循「最左前綴原則」。查詢 1、2 未引用前導欄 place,索引無法有效利用;查詢 3 完美命中。
sys.dm_db_index_usage_stats 清理未用索引。INCLUDE 非鍵欄位建立覆蓋索引,避免書籤查找。| 反模式 | 優化寫法 | 原因 |
|---|---|---|
WHERE col + 1 > 100 | WHERE col > 99 | 運算在欄位上 → 掃描 |
WHERE SUBSTRING(col,1,3) = 'ABC' | WHERE col LIKE 'ABC%' | 函數在欄位上 → 掃描 |
WHERE YEAR(date_col) = 2024 | WHERE date_col >= '2024-01-01' AND date_col < '2025-01-01' | 函數在欄位上 → 掃描 |
WHERE ISNULL(col, '') = 'val' | WHERE col = 'val' OR col IS NULL | 函數在欄位上 → 掃描 |
WHERE col IN (SELECT ...) | WHERE EXISTS (SELECT 1 FROM ... WHERE ...) | IN 子查詢常劣於 EXISTS |