復合非聚集索引——列順序重要么?


當我談論索引時,大家經常會問我在復合非聚集索引里,列的順序是否重要?簡單來說:“看情況”。我們來具體看下為啥“看情況”……

單例查找(Singleton Lookups)

當在你的表上有進行單例查找的查詢時,在復合非聚集索引里列的順序真的不重要。假設下列查詢:

-- Without a supporting Non-Clustered Index we have to scan the complete Clustered Index
SELECT AddressID FROM Person.Address
WHERE StateProvinceID = 79 AND City = 'Bothell'
GO

現在你可以在StateProvinceIDCity,或CityStateProvinceID創建非聚集索引:

-- Create a supporting Non-Clustered Index
CREATE NONCLUSTERED INDEX idx_Test ON Person.Address(StateProvinceID, City)
GO

-- SQL Server performs a Non-Clustered Index Seek operation in combination with a Seek Predicate
SELECT AddressID FROM Person.Address
WHERE StateProvinceID = 79 AND City = 'Bothell'
GO

-- Change the column ordering
CREATE NONCLUSTERED INDEX idx_Test ON Person.Address(City, StateProvinceID)
WITH (DROP_EXISTING = ON)
GO

-- The column ordering doesn't matter in the Non-Clustered Index
SELECT AddressID FROM Person.Address
WHERE StateProvinceID = 79 AND City = 'Bothell'
GO

這里非聚集索引里的列的順序真的不重要,因為SQL Server在執行計划里直接進行非聚集索引查找操作(在與查找謂語集合里):

范圍掃描(Range Scans)

當我們討論在表上的范圍掃描時,這里你檢索一組數據,就是另一回事了。假設你執行下列查詢:

SELECT AddressID FROM Person.Address
WHERE StateProvinceID BETWEEN 10 AND 12 AND City = 'Bothell'
GO

這次,支持的非聚集索引,你有2個方法:

  • StateProvinceID和City列上的非聚集索引
  • City和StateProvinceID列上的非聚集索引

我們先用第一個方法:

-- Create a supporting Non-Clustered Index
CREATE NONCLUSTERED INDEX idx_Test ON Person.Address(StateProvinceID, City)
GO

這個情況下,如你在執行計划里所見,SQL在StateProvinceID列上對查詢進行非聚集索引查找操作,對於City列要計算剩余謂語的值:

這真的不是個完美的執行計划,因為你讀取了比你請求更多的數據。但有基於StateProvinceID列上的排序作為引導列, City作為隨后列,這是唯一可能的行為,如你從下圖所見:

現在我們嘗試交換下列來創建非聚集索引:City作為引導列,StateProvinceID作為第二列:

-- Change the column ordering in the Non-Clustered Index
CREATE NONCLUSTERED INDEX idx_Test ON Person.Address(City, StateProvinceID)
WITH (DROP_EXISTING = ON)
GO

-- Non-Clustered Index Seek on StateProvinceID *without* a Residual Predicate on column City
SELECT AddressID FROM Person.Address
WHERE StateProvinceID BETWEEN 10 AND 12 AND City = 'Bothell'
GO

當你再次執行你的查詢,你會看到SQL Server再次執行了非聚集索引查找操作。但這次對於你的查詢,“沒有”剩余謂語(Residual Predicate)。

因為你物理上讀取的剛好是你邏輯上請求的數據。但這個現在這么可能呢?那就看看下面的圖:在非聚集索引里數據是如何排序的:

如你所見,現在的數據按City預先排,在每個City組里,你會有在StateProvinceID列的排序。因此你可以直接獲得邏輯請求的數據——不用進一步剩余謂語(Residual Predicate)的值計算就可以返回值。

小結

當你要進行范圍掃描時——在復合非聚集索引里列的順序重要的!在多次交流會上我經常提到:SQL Server里的一切幾戶都與索引有關,索引本身就會預排序數據!沒別的!理解SQL Server是否可以直接查找邏輯請求的數據,你也需要在你的心中想象下如何使如何預排序的,你如何通過有效預排序數據來訪問它。

希望這篇文章可以讓你更好的理解在非聚集索引里,列排序如何影響查找操作。

感謝關注!

原文鏈接

https://www.sqlpassion.at/archive/2016/06/27/composite-non-clustered-indexes-does-the-sorting-order-matter


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM