索引是對資料表中一或多欄位值進行排序的資料結構(通常為 B+ 樹),提供指標指向實際資料行。類似書本目錄:查目錄找頁碼,再翻到該頁。正確使用索引可將查詢效能提升數十至數百倍。
| 特性 | 叢集索引 | 非叢集索引 |
|---|---|---|
| 資料儲存順序 | 資料頁按索引鍵值物理排序儲存 | 資料頁順序不變,索引另建結構 |
| 每表數量 | 僅能有一個 | 可建多個(SQL Server 上限 999) |
| 葉層內容 | 資料頁本身 | 索引鍵值 + 行定位器(RID 或叢集鍵) |
| 適用場景 | 範圍查詢、排序、頻繁存取的主鍵 | 精確查詢、覆蓋索引、高基數欄位 |
| 插入效能影響 | 較大(需維持物理順序,易產生頁分裂) | 較小 |
CREATE INDEX ... WHERE status = 1,針對熱門資料子集,體積小、維護快。
-- CREATE INDEX
CREATE [UNIQUE] [CLUSTERED | NONCLUSTERED] INDEX idx_name
ON table_name (col1 [ASC|DESC], col2 [ASC|DESC], ...)
[INCLUDE (col3, col4, ...)] -- 覆蓋索引包含欄位
[WHERE filter_predicate]; -- 篩選索引
-- CREATE TABLE 時指定
CREATE TABLE t (
id INT PRIMARY KEY CLUSTERED, -- 主鍵預設叢集
code VARCHAR(20) UNIQUE NONCLUSTERED,
status TINYINT,
INDEX idx_status (status) -- SQL Server 2016+ 簡潔語法
);
FILLFACTOR = 80 保留 20% 頁面空間,減少頁分裂。適用於頻繁 INSERT/UPDATE 的叢集索引。預設 0(=100,填滿)。
| 命令 | 用途 | 特性 |
|---|---|---|
DBCC DBREINDEX | 重建所有/指定索引 | 離線、鎖表、速度快、記錄大、需額外磁碟空間 |
DBCC INDEXDEFRAG / ALTER INDEX ... REORGANIZE | 整理碎片(葉層重排序) | 線上、可隨時中斷、記錄小、速度慢、不更新統計資料 |
ALTER INDEX ... REBUILD | 重建(可 ONLINE=ON,企業版) | 企業版支援線上重建,標準版離線 |
UPDATE STATISTICS | 更新統計資料 | 查詢優化器依賴統計資料制定計畫 |
SELECT
OBJECT_NAME(object_id) AS TableName,
index_id,
avg_fragmentation_in_percent
FROM sys.dm_db_index_physical_stats(DB_ID(), NULL, NULL, NULL, 'LIMITED')
WHERE avg_fragmentation_in_percent > 10;
REORGANIZEREBUILDsp_helpindex 'table_name' / sp_help 'table_name'SELECT * FROM sys.indexes WHERE object_id = OBJECT_ID('table_name')Index Seek(佳)、Index Scan(全索引掃描)、Key Lookup(回表)、RID Lookup(堆疊表回表)、Table Scan(全表掃描,避免)。SELECT * FROM t WITH (INDEX(idx_name)) WHERE ...(謹慎使用)。INDEX (a,b,c) 可支援 WHERE a=1、WHERE a=1 AND b=2、WHERE a=1 AND b=2 AND c=3,但不支援 WHERE b=2 或 WHERE c=3。COUNT(DISTINCT col)/COUNT(*) > 0.1 適合建索引;性別/狀態等低基數欄位不適合單獨建索引(可做複合索引次序或篩選索引)。INCLUDE (col3, col4) 將非鍵欄位放入葉層,查詢 SELECT col1, col3 FROM t WHERE col1=1 直接在索引完成。INDEX(a) + INDEX(a,b) 前者多餘;外鍵欄位通常需索引支援 JOIN/刪除檢查。AUTO_UPDATE_STATISTICS ON、排程 REBUILD/REORGANIZE。| 反模式 | 後果 | 改善 |
|---|---|---|
| 所有欄位都建索引 | 寫入極慢、空間浪費、優化器混淆 | 僅針對高頻查詢欄位建立 |
| 叢集索引用 GUID | 嚴重頁分裂、碎片率高 | 用 INT IDENTITY 或有序鍵 |
| WHERE 對索引欄位用函數 | 索引失效(SARGable 違反) | 改寫為範圍查詢 |
| 複合索引欄位順序錯誤 | 無法命中索引 | 遵循最左前綴、高選擇性在前 |
| 從不維護統計資料 | 優化器誤判、選錯計畫 | 開啟自動更新、定期手動更新 |
索引是資料庫效能的核心槓桿。掌握叢集 vs 非叢集、覆蓋/篩選/Columnstore 進階類型、最左前綴、SARGable 原則、碎片維護、統計資料,並養成「看執行計畫 → 調索引 → 驗證」閉環習慣,是高階 DBA/後端工程師的必修課。