SQL Server 建立主鍵或索引時,預設所有欄位採用 升序 (ASC),這是為了相容早期版本。但實際查詢若以 降序 (DESC) 為主,順序不匹配會導致掃描方向相反,嚴重拖垮效能。本文以百萬筆實測數據,量化順序不匹配的代價,並給出排序策略指導。
test_indexorder,主鍵叢集索引 PK_testorder (Id DESC)Id 為 Identity(1,1)-- 降序查詢 (與索引順序一致)
WITH t_rn AS (
SELECT *, rn = ROW_NUMBER() OVER (ORDER BY Id DESC) FROM test_indexorder
)
SELECT Id, Name, Content, Co1, Co2, Co3, Co4, Co5
FROM t_rn WHERE rn BETWEEN 19007 AND 19057; -- 393 ms
-- 升序查詢 (與索引順序相反)
WITH t_rn AS (
SELECT *, rn = ROW_NUMBER() OVER (ORDER BY Id ASC) FROM test_indexorder
)
SELECT Id, Name, Content, Co1, Co2, Co3, Co4, Co5
FROM t_rn WHERE rn BETWEEN 17007 AND 17057; -- 606 ms
| 查詢排序 | 耗時 (ms) | 相對效能 | 原因 |
|---|---|---|---|
| DESC (匹配索引) | 393 | 1.00x (基準) | 順向掃描葉層頁面,CPU 只需遞增 RowNumber,無額外排序運算子 |
| ASC (相反索引) | 606 | 0.65x (慢 54%) | 逆向掃描 + Top-N Sort,或需回表補齊排序欄位,引入 Sort 運算子、額外 I/O |
結論: 僅排序方向不匹配,效能即下降 50%+。若涉及 Join、Group By、Window Function,放大效應更劇烈。
ORDER BY PK DESC (如最新記錄優先),必須顯式指定 PRIMARY KEY CLUSTERED (Id DESC)。ORDER BY CategoryId ASC, CreatedDate DESC → 索引 (CategoryId ASC, CreatedDate DESC)。Sort、Top N Sort、Index Scan (Ordered: False),若有即代表順序不匹配。DESC 索引僅改變邏輯順序,頁面分裂、合併、填充因子運作機制不變。DBCC SHOW_STATISTICS 顯示仍為升序,屬正常。sys.index_columns 中 is_descending_key = 1 標識降序欄位。INCLUDE 欄位,is_descending_key 無效 (INCLUDE 欄位不參與排序)。索引欄位順序不是預設值能決定的,而是由查詢工作負載決定的。每次建立索引前,先問三個問題:誰在查?怎麼排?多頻繁? 答案裡藏著最佳順序。