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

SQL Server 索引欄位順序陷阱:WHERE 範圍條件 + ORDER BY 時的關鍵排序

     編輯:關於SqlServer

一條反直覺的索引設計鐵律

查詢:`SELECT TOP 20 * FROM t_article WHERE datetime > DATEADD(day,-7,getdate()) ORDER BY countView DESC`

**建立索引時,必須把 `countView` (ORDER BY 欄位) 放在最前面,`datetime` (WHERE 範圍條件) 放在後面,索引才會被使用。**

驗證環境

  • SQL Server 2005 測試通過。
  • 此行為在 2008/2012/2014/2016/2019 依然成立(優化器規則未變)。

原理剖析

  • 索引鍵順序決定 **B+ 樹排序順序**。
  • `ORDER BY countView DESC` 需要索引已按 `countView` 排序,才能直接從葉節點順序掃描前 20 筆(避免 Sort 運算子)。
  • `WHERE datetime > ...` 是 **範圍掃描**,若 `datetime` 在前,索引按時間排序,`countView` 亂序,**無法滿足 ORDER BY**,優化器只能選 Clustered Index Scan + Sort,或建議建立 `countView` 領先的索引。
  • 把 `countView` 放前面,索引按熱門度排序,**Top 20 直接從索引頭部取**,再套用 `datetime` 篩選(Residual Predicate),極少量行即滿足,總成本極低。

正確索引定義

CREATE NONCLUSTERED INDEX IX_t_article_countView_datetime
ON t_article (countView DESC, datetime)
INCLUDE (其他 SELECT 欄位);  -- 覆蓋查詢避免 Key Lookup

延伸:複合索引欄位順序通則

  1. **等值條件 (`=`) 在前** — 選擇性最高、可 Seek 定位。
  2. **排序欄位 (`ORDER BY`) 緊接在後** — 滿足排序避免 Sort。
  3. **範圍條件 (`>`, `<`, `BETWEEN`, `LIKE '%...'`) 在最後** — 只能做 Residual Predicate 或 Range Scan 終止。
  4. **INCLUDE 非鍵欄位** — 覆蓋查詢,不計入鍵長度限制 (900 bytes),不影響排序。

驗證腳本

-- 查看執行計畫是否出現 Index Seek + Ordered:True + Top
SET STATISTICS IO, TIME ON;
SELECT TOP 20 * 
FROM t_article 
WHERE datetime > DATEADD(day,-7,getdate()) 
ORDER BY countView DESC;

結語

**ORDER BY 欄位優先、範圍條件欄位靠後** — 這是「Top N 排序查詢」索引設計的黃金法則。違背它,就是送給 Sort 運算子 CPU 週期與 tempdb I/O 的禮物。

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