當我談論索引時,你們常常會問我在複合非彙集索引裏,列的順序是否重要?簡單來講:「看狀況」。咱們來具體看下爲啥「看狀況」……sql
當在你的表上有進行單例查找的查詢時,在複合非彙集索引裏列的順序真的不重要。假設下列查詢:spa
-- 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
如今你能夠在StateProvinceID和City,或City和StateProvinceID建立非彙集索引:code
-- 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在執行計劃裏直接進行非彙集索引查找操做(在與查找謂語集合裏):orm
當咱們討論在表上的範圍掃描時,這裏你檢索一組數據,就是另外一回事了。假設你執行下列查詢:blog
SELECT AddressID FROM Person.Address WHERE StateProvinceID BETWEEN 10 AND 12 AND City = 'Bothell' GO
此次,支持的非彙集索引,你有2個方法:排序
咱們先用第一個方法:索引
-- Create a supporting Non-Clustered Index CREATE NONCLUSTERED INDEX idx_Test ON Person.Address(StateProvinceID, City) GO
這個狀況下,如你在執行計劃裏所見,SQL在StateProvinceID列上對查詢進行非彙集索引查找操做,對於City列要計算剩餘謂語的值:get
這真的不是個完美的執行計劃,由於你讀取了比你請求更多的數據。但有基於StateProvinceID列上的排序做爲引導列, City做爲隨後列,這是惟一可能的行爲,如你從下圖所見:it
如今咱們嘗試交換下列來建立非彙集索引:City做爲引導列,StateProvinceID做爲第二列:io
-- 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是否能夠直接查找邏輯請求的數據,你也須要在你的心中想象下如何使如何預排序的,你如何經過有效預排序數據來訪問它。
但願這篇文章可讓你更好的理解在非彙集索引裏,列排序如何影響查找操做。
感謝關注!