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

讓 SQL 查詢跑得更快:索引設計、聯接條件與 WHERE 子句優化三大實戰原則

     編輯:關於SqlServer

核心觀念

相同結果的 SQL,不同寫法效能可差距數十倍。優化三大支柱:**索引設計**、**聯接條件完整性**、**WHERE 子句可優化性**。

實測環境

  • 主機:HP LH II
  • CPU:330 MHz
  • 記憶體:128 MB
  • OS:OpenServer 5.0.4
  • DB:Sybase 11.0.3(原理通用於 SQL Server/Oracle)
  • 測試表:record,620,000 列

案例一:索引設計的決定性影響

場景 A:date 欄位建立非叢集索引


-- 查詢 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 開銷大)。

場景 B:date 欄位建立叢集索引


-- 同三個查詢分別:14 秒、28 秒、14 秒

分析:叢集索引使資料按 date 物理有序,相同值相鄰。範圍查詢只需定位起訖點掃描連續頁面,避免全表掃描與書籤查找,速度大幅提升。

場景 C:(place, date, amount) 複合索引(place 為前導欄)


-- 查詢 1:26 秒(未用 place,索引失效)
-- 查詢 2:27 秒
-- 查詢 3:< 1 秒(用了 place,索引命中)

分析:複合索引遵循「最左前綴原則」。查詢 1、2 未引用前導欄 place,索引無法有效利用;查詢 3 完美命中。

原則總結

1. 索引設計鐵律

  • 叢集索引選擇範圍查詢高頻、重複值多、需排序的欄位(如日期、流水號)。
  • 非叢集索引覆蓋高選擇性查詢欄位(唯一值多、WHERE/JOIN 常用)。
  • 複合索引遵循最左前綴:WHERE/JOIN/ORDER BY 欄位順序決定索引欄位順序。
  • 避免過度索引:每個索引增加 INSERT/UPDATE/DELETE 開銷,定期評估 sys.dm_db_index_usage_stats 清理未用索引。
  • 包含欄位:INCLUDE 非鍵欄位建立覆蓋索引,避免書籤查找。

2. 聯接條件完整性

  • **務必提供完整 JOIN 條件**,缺少條件導致笛卡兒積或錯誤計畫。
  • **驅動表選擇**:小表驅動大表,或有高選擇性索引的表優先。
  • **避免隱性轉換**:JOIN 欄位資料型別、Collation 必須一致,否則索引失效。
  • **使用 ANSI JOIN 語法**;舊式 WHERE JOIN 難維護且易出錯。

3. WHERE 子句可優化性

進階優化清單

  1. 統計資料更新:UPDATE STATISTICS / AUTO_UPDATE_STATISTICS ON,確保優化器決策準確。
  2. 參數化查詢:預存程序/sp_executesql 重用計畫,防止注入。
  3. 避免 SELECT *:明確列出欄位,減少 I/O、網路、記憶體壓力。
  4. 分頁用 OFFSET/FETCH 或 ROW_NUMBER,勿用雙重 TOP。
  5. 適度反正規化:關鍵查詢路徑冗餘欄位,消除 JOIN。
  6. 監控執行計畫:關注 Scan vs Seek、估計 vs 實際行數、平行度、記憶體授予。

結語

索引是銀彈,但需精準瞄準;聯接條件要完整;WHERE 子句要「欄位不運算」。三大原則貫徹落實,查詢效能將質變。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
反模式優化寫法原因
WHERE col + 1 > 100WHERE col > 99運算在欄位上 → 掃描
WHERE SUBSTRING(col,1,3) = 'ABC'WHERE col LIKE 'ABC%'函數在欄位上 → 掃描
WHERE YEAR(date_col) = 2024WHERE 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