包含列解析 所謂的包含列就是包含在非聚集索引中,並且不是索引列中的列。或者說的更通俗一點就是:把一些底層數據表的數據列包含在非聚集索引的索引頁中,而這些數據列又不是索引列,那麼這些列就是包含列。同時,這些包含列並不會對索引中的條目有影響。 好吧,爲了使得問題稍微清楚一點,我用個簡單的圖示說明一下:
我們可以用下面的語句在創建索引的時候加入包含列,代碼如下:
在上述的代碼中,ProductID和ModifiedDate包含在索引鍵中,而OrderQty, UnitPrice, LineTotal作爲包含列。 下面,我們就稍微深入到頁級別來看看建立索引前後的狀態。首先,我們看看,當建立非聚集索引,但是,索引中沒有包含列的時候,索引中的索引頁的詳細如下:
在上圖中可以看到,上面兩個索引頁是整個索引結構中的一部分,此時就包含了2個字段,而且這兩個字段都是索引鍵,另外一個Bookmark是指向底層數據表中數據行的一個指針。 下面,我們再來看看,我們建立了有包含列的非聚集索引之後,索引頁的情況,如下圖:
很明顯,原本的2個索引頁被拆分成爲了3個,因爲一部分底層數據行的數據的數據包含在了索引頁中。從這裏就可以知道一點:加入包含列到非聚集索引中,增大了索引結構中頁的個數,進而在使用的時候會佔用更多的磁盤空間和內存空間。
其實把一些列作爲包含列放在索引結構中就是一種用“空間換時間”的策略。 這個時候,大家可能就會問了:“何必把列放在包含列中這麼麻煩,爲什麼不直接放在索引中?”。
其實把那三個列放在包含列而不是索引列中有以下幾個好處: 1.可以使得索引鍵變化引起的波動更小。舉個例子,如果索引列中的ProductID或者ModifiedDate發生變化,那麼索引結構就會要調整,重新定位到底層的數據行。但是,如果UnitPrice的值發生了變化,整個索引的結構不會發生變化,只是在包含列中的UnitPrice的值進行更新而已。 2.索引中的數據列越少,數據分佈的統計維護的成本就越小。 是否把一些作爲索引列還是包含了其實也和數據庫的類型和用途有很大的關係。例如在OLTP的數據庫中,有很多的數據的增刪改寫的操作,那麼建議索引中的列不要太多。如果是Warehouse類型的數據,那麼就以大量數據的讀取爲主,那麼可以考慮把很一些列包含在索引列中。 包含列實例演示一 下面通過是三個不同的小例子作爲比較演示,並且以AdventureWorks中的SalesOrderDetail示例數據表: 1.演示沒有非聚集索引的例子。 2.演示使用非聚集索引,但是沒有包含列的例子 3.演示有非聚集索引和包含列的例子 在講述的過程中,我們會結合實際的執行詳情說明問題。 示例一:沒有非聚集索引 執行語句如下:
示例二:使用非聚集索引,但是沒有包含列 首先運行下面的語句,建立索引:
示例三:有非聚集索引和包含列
首先執行下面的代碼:
然後再次運行之前的查詢。 好了,三個例子完成之後,我們就來比較一下結果,如下:
總結如下: 1.示例1中對整個表進行掃描,每一個行都要進行掃描,所以進行大量的IO活動。 2.例2首先使用非聚集索引找到ProductID的數據,然後通過書籤查找找到查詢中請求的其他的數據列。 3.示例3,只要在非聚集索引中查找需要的數據就行了,因爲查詢中所有列的數據都在裏面了,不用查找底層的數據表,所以查詢只是查找了索引結構,消耗的IO最少。 |
||||||
yanyangtian 最後編輯於 2012-08-31 16:44:14
不是因爲有希望才堅持,而是因爲堅持纔有希望
如果您認可我們,請轉發一條微博:www.agilesharp.com提供靠譜的SQL Server性能優化,架構設計,解決方案 |
||||||
yanyangtian
|
下面,我們就來看看第二個示例。
包含列示例演示二
第二個查詢和第一個查詢類似,只是將Where條件語句改爲了按照ModifiedDate裏過濾。語句如下:
在查詢執行的過程中,通過Where條件,選擇出了1496條數據,最後通過Group語句,使得最後顯示的結果只有164行數據。 在三種不同的情況下,運行上面的查詢,結果比較如下:
|