首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> SQL Server 資料庫 >> 關於SqlServer

SQL 查詢效能調優:20 個關鍵最佳實踐與常見反模式

     編輯:關於SqlServer

一、索引與存取路徑

  1. 避免在索引欄位上運算:`WHERE Salary * 12 > 50000` → 導致 Index Scan。改寫 `WHERE Salary > 50000/12` 或建立計算欄位+索引。
  2. 複合索引首欄必須出現在 WHERE/JOIN/ORDER BY:索引 `(A,B,C)`,查詢 `WHERE B=1` 無法用到索引。
  3. 高選擇性欄位優先:複合索引順序應為「最常用且最具過濾力」的欄位在前。
  4. 覆蓋索引:`INCLUDE` 非鍵欄位,讓查詢不回表(Key Lookup)。
  5. 避免 `IS NULL` / `IS NOT NULL` 破壞 SARGability:改用預設值+索引或篩選索引。
  6. `!=` / `<>` 通常導致掃描:若需排除少數值,考慮 `UNION ALL` 正向篩選。
  7. 隱式轉換殺手:`WHERE VarcharCol = 123` → 隱式 `CAST(VarcharCol AS INT)`。統一參數型別、欄位型別。
  8. LIKE 尾碼萬用字元可用索引:`LIKE 'ABC%'` → Seek;`LIKE '%ABC'` → Scan。前綴搜尋考慮全文索引或反向欄位。

二、查詢結構與運算子

  1. 用 `EXISTS` 替代 `IN`(子查詢):`EXISTS` 遇真即停,`IN` 需物化子查詢結果集。`NOT EXISTS` 遠優於 `NOT IN`(後者對 NULL 語意複雜且難優化)。
  2. 避免 `OR` 破壞索引使用:`WHERE A=1 OR B=2` → 多半 Scan。拆分為 `UNION ALL` 兩條求集合。
  3. 慎用 `DISTINCT` / `ORDER BY` / `GROUP BY`:需排序/雜湊,耗 TempDB。確認業務真需要,或在索引順序滿足時省略。
  4. 子查詢改寫為 JOIN 或 APPLY:相關子查詢每列執行一次,`OUTER APPLY`/`CROSS APPLY` 可集合化。
  5. 合併 `UNION` → `UNION ALL`:除非業務需去重,`UNION ALL` 免排序/雜湊,快數倍。
  6. 避免 `SELECT *`:增加網路傳輸、阻礙覆蓋索引、Schema 變更風險。明確列出欄位。

三、聯結策略

  1. 驅動表選小不選大:Nested Loop 外層宜小(少列)、內層有索引。Hash Join 適合大表聯大表且無索引。
  2. 提供充足的 JOIN 條件:缺少條件導致 Cartesian Product 或錯誤的 Join Order。每張表至少一個等值條件連接。
  3. 資料型別一致:`INT` JOIN `VARCHAR` → 隱式轉換 + Scan。統一型別或顯式 CAST。

四、進階技巧

  1. 綁定變數 / 參數化查詢:重用執行計畫、防 SQL Injection、減少編譯 CPU。
  2. 優化 `GROUP BY` / 彙總:預先聚合、使用索引順序避免 Sort、考慮 Columnstore 索引(OLAP)。
  3. 定期維護統計資料與索引:`UPDATE STATISTICS`、`ALTER INDEX REBUILD/REORGANIZE`,避免計畫偏離實際資料分布。

快速自檢清單

症狀可能原因對策
執行計畫出現 Table Scan / Index Scan無索引、SARGability 破壞、統計過期建立索引、改寫 WHERE、UPDATE STATISTICS
Key Lookup 佔成本 90%+非覆蓋索引加 INCLUDE 欄位或調整查詢欄位
TempDB 壓力大、排序溢寫大量 DISTINCT/ORDER BY/GROUP BY/HASH JOIN索引排序、分頁查詢、增加記憶體
參數化查詢偶爾極慢Parameter SniffingOPTION (RECOMPILE)、OPTIMIZE FOR、Plan Guide

效能調優無銀彈,唯有「測量 → 找瓶頸 → 改寫/加索引 → 再測量」的循環。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved