1. 程式人生 > >SQL Server 非聚集索引的覆蓋,連接,交叉和過濾 <第二篇>

SQL Server 非聚集索引的覆蓋,連接,交叉和過濾 <第二篇>

相對 col 超過 引用 保持 書簽 基本 nbsp 當我

  在SQL Server中,非聚集索引其實可以看做是一個含有聚集索引的表,但相對實際的表來說,非聚集索引中所存儲的表的列數要少得多,一般就是索引列,聚集鍵(或RID)。非聚集索引僅僅包含源表中的非聚集索引的列和指向實際物理表的指針。

一、非聚集索引之INCLUDE

  非聚集索引其實可以看做一個含有聚集索引的列表,當這個非聚集索引中包含了查詢所需要的所有信息的時候,則就不再需要去查基本表,僅僅做非聚集索引就能夠得到所需要的數據。INCLUDE實際上也能稱為覆蓋索引,但它不影響索引鍵的大小。

  先來看下面一張表:

  技術分享

  此表大約是15萬數據左右。聚集索引列是Id,我們先來在Name列建立一個非聚集索引。

  CREATE NONCLUSTERED 
  INDEX Index_Name ON Person(Name)

  然後執行查詢:

  SELECT Name,Age FROM Person where Name = 歐琳琳

  執行計劃如下:

  技術分享

  上面的執行過程是,先掃描非聚集索引列,找到聚集索引,然後在通過聚集索引定位到數據。

  下面我們刪除掉剛才那個索引,再建過另外一個。

  DROP INDEX Person.Index_Name    --刪除非聚集索引Index_Name

  CREATE NONCLUSTERED             --再重新建過一次,這次我們INCLUDE Age列
  INDEX Index_Name ON Person(Name)   INCLUDE (Age)

  現在我們再來看看剛才的查詢的執行計劃:

  技術分享

  由於Age列也被INCLUDE進了非聚集索引INDEX_Name中,因此這次僅僅通過查找非聚集索引就能夠得到所需的全部數據。不需要再掃描聚集索引了。明顯這次查詢要比剛才快。

  要註意的是INCLUDE進來的列,並不作為索引使用,能當索引掃描的,只是索引列

  INCLUDE最好在以下情況中使用:

  • 你不希望增加索引鍵的大小,但是仍然希望有一個覆蓋索引;
  • 你打算索引一種不能被索引的數據類型(除了文本、ntext和圖像);
  • 你已經超過了一個索引的關鍵字列的最大數量(但是最好避免這個問題);

二、非聚集索引之覆蓋

  索引覆蓋指的是:建立的索引使得-SQL查詢不用到達基本表僅僅通過索引查找就得到了所需數據。  

  如果查詢遇到一個索引並且完全不需要引用數據表就得到了所需數據,那麽這個索引就可以稱為覆蓋索引。覆蓋索引對於減少查詢的邏輯讀是一種有用的技術。

  下面刪除之前創建的索引,在來看看索引的覆蓋。

  CREATE NONCLUSTERED INDEX INDEX_NAME ON Person(Name,Age)

  SELECT Name,Age FROM Person WHERE Name = 歐琳琳

  看看執行計劃:

  技術分享

  可以看到,也是僅僅查找了非聚集索引就得到了結果。效率非常快。

  下面來看看覆蓋和前面的INCLUDE有什麽區別呢?我們將搜索條件改為Age。

  覆蓋索引:

  技術分享

  INCLUDE:

  技術分享

  留意一下,INCLUDE是聚集表掃描了,而覆蓋索引依然使用非聚集索引就找到了結果。

  因此可以得出結論,INCLUDE列並不能當索引鍵使用。

  為了利用覆蓋索引,要註意SELECT語句的清單,應盡可能使用較少的列來保持小的覆蓋索引的尺寸,使用INCLUDE語句來添加的列這時候才有意義。

  在建立許多覆蓋索引之前,考慮SQL Server如何有效和自動地使用索引交叉來為查詢即時創建覆蓋索引。

三、非聚集索引的交叉

  如果一個表有多個索引,那麽SQL Server可以使用多個索引來執行一個查詢。SQL Server可以利用多個索引,根據每個索引選擇小的數據子集,然後執行兩個子集的一個交叉(即只返回滿足所有條件的那些行)。SQL Server可以在一個表上開發多個索引,然後使用一個算法來在兩個子集中得到交叉(可以理解為求交集)。

  我們先刪除掉前面建立的索引,再來新建過:

  技術分享

  非聚集索引的本質是表,通過額外建立表使得幾個非聚集索引之間進行像表一樣的Join,從而使非聚集索引之間可以進行Join來在不訪問基本表的情況下給查詢優化器提供所需要的數據。

  為了增進一個查詢的性能,SQL Server可以在表上使用多個索引。因此,考慮創建多個窄索引來代替寬的索引鍵。SQL Server能夠在需要的時候一起使用它們,當不需要時,查詢可以從窄索引中獲益。在創建一個覆蓋索引時,需要確定索引的寬度是否可以接受,使用包含列是否可以完成任務。如果不行則確定現有的包含大部分覆蓋索引所需要的列的非聚集索引。如果有可能,適當重新安排現有非聚集索引的列順序,使優化器能夠考慮兩個非聚集索引之間的的一個索引交叉。

  有時候,可能必須為一下原因創建一個單獨的非聚集索引:

  •   重新排列現有索引中的列不被允許;
  •   覆蓋索引所需要的一些列不能被包含在現有的非聚集索引中;
  •   兩個現有非聚集索引中的總列數可能多於覆蓋索引所需要的列數;

  在這些情況下,可以在剩下的列上創建非聚集索引。如果新索引符合和現有索引符合覆蓋索引的要求,優化器將能夠使用索引交叉。在為新確定列及其順序時,也要註意其他查詢,以嘗試使其最大化。

四、非聚集索引的連接

  索引連接是索引交叉的特例,它將覆蓋索引技術應用到索引交叉。如果沒有單個覆蓋查詢的索引而存在多個索引一起可以覆蓋該查詢,SQL Server可以使用索引連接來完全滿足查詢而不需要轉到基本表。

  非聚集索引的連接實際上是非聚集索引的交叉的一種特例。使得多個非聚集索引交叉後可以覆蓋所要查詢的數據,從而使得從減少查詢基本表變成了完全不用查詢基本表。

  --建立兩個非聚集索引,一個在Name列,一個在INSiteId列
  CREATE NONCLUSTERED INDEX INDEX_Name ON Person(Name) INCLUDE(Age)  --索引還是剛才的索引,但是包含多一列
  CREATE NONCLUSTERED INDEX INDEX_INSiteId ON Person(INSiteId) INCLUDE(Height)  --同上

  SELECT Name,Age,Height,INSiteId FROM Person WHERE INSiteId > 5155400 AND Name = 簡單   --註意條件,索引連接剛好能覆蓋所需數據,從而避免查找基本表

  查看結果:

  技術分享

  索引交叉和索引連接有什麽區別呢?前面說到果,索引連接是索引交叉的特例。索引連接在交叉了之後,不用再轉到基本表,少了一步書簽查找。而索引交叉之後,還有一步書簽查找轉到基本表獲得數據,因為索引交叉的返回列並不能完全符合SELECT的列。

五、非聚集索引的過濾

  過濾索引是使用過濾器的非聚集索引,這個過濾器基本上是一個WHERE子句,用來在可能沒有很好選擇性的一個或多個列上創建一個高選擇性的關鍵字組。

  例如,一個具有大量NULL值的列可能被存儲為稀疏列來降低這些null值的開銷。在這個列添加一個過濾索引將使你擁有在不是null的數據上的索引。

  在下面的所使用的Person表中,Name列有超過50%是NULL值,執行查詢:

  SELECT Name,Age FROM Person WHERE Name IS NOT NULL

  技術分享

  這是一個聚集表掃描,並沒有有效地使用索引。

  當我們建立非聚集索引,且加上過濾後:INCLUDE()是為了形成覆蓋索引。

  CREATE NONCLUSTERED INDEX INDEX_Name ON Person(Name) INCLUDE(Age) WHERE Name IS NOT NULL  --過濾的索引上過濾掉NULL值的行

  技術分享

  在我的數據庫當中,建立索引,加不加過濾沒太大區別(因為很遺憾,Name列基本上沒有NULL的),但是當過濾條件IS NOT NULL能夠過濾很多條數據的時候,這時過濾的作用才能夠展示出來如果過濾條件,能夠篩選掉很多條數據,那麽性能無疑會大有提升。

  過濾索引再許多方面帶來回報:

  •   減少索引尺寸從而增進查詢效率;
  •   建立更小的索引降低存儲開銷;
  •   因為尺寸減小,降低了索引維護的成本;

SQL Server 非聚集索引的覆蓋,連接,交叉和過濾 <第二篇>