之前已經寫過兩篇介紹列存儲索引的文章,但是隻有非聚集列存儲索引,今天再來簡單介紹一下聚集的列存儲索引,也就是可更新列存儲索引。在SQL Server 2012中首次引入了基于列存儲資料格式的存儲方式。叫做“列存儲索引”。前一篇我已經比較了行存儲索引與非聚集的列存儲索引(http://www.cnblogs.com/wenBlog/p/5682024.html)。其中對于在小表的指定值或者小範圍的查詢來講,尤其針對事務性的負載行存儲是很合适的。但是對于分析性負載像資料倉庫和BI,在查詢中将會對大量資料進行全掃描,例如事實表,這時候列存儲索引就是更好地選擇。
在列存儲索引中,資料按照獨立列組織到一起形成索引結構。每列都資料都位于被高度壓縮的資料集中,叫做資料段。這個資料段隻包含該列的值,對于大型表它分到多個資料段中,每個資料段中隻含有100萬行資料,這就叫做行組、資料段由一個或者多個資料頁組成。資料将在記憶體和硬碟上以資料段的形式傳輸。
這種索引提高了資料倉庫的查詢效率。這種通過壓縮獲得資料格式要比B-Tree結構的壓縮率高7倍多。同時由于列存儲索引使用了批處理模式執行,資料處理也是批處理的,較少了CPU的使用。列存儲索引強化了檢索資料的速度,與行存儲不同的是不用查詢所有列。因為這個原因,更少資料被讀取到記憶體中,再到處理器緩存處理。相關的這些因素都會減少硬碟IO,提高整體查詢的性能。
在2014中列存儲索引有以下限制:
最多支援1024列在你的索引中;
列存儲索引不能被定義為唯一性索引;
不能建立視圖;
不能包含稀疏列;
不能使用ALTER INDEX來修改索引,隻能drop然後重新建立;
不能使用INCLUDE關鍵字。
不能排序列;
不能使用FILESTREAM屬性。
當然還有一些資料類型不能包含在列存儲索引中(binary , varbinary , ntext , text, , image, varchar(max) , nvarchar(max), uniqueidentifier, rowversion , sql_variant,精度大于18 的decimal,CLR 和xml等)
另一方面,對于索引列900位元組的限制也不适用與列存儲索引。
在SQL Server2012 中,隻能建立非聚集列存儲索引,并且不能更新。為了更新你必須删除索引,然後進行插入、更新或者删除的操作後在重建索引。
在2014中列存儲索引得到了不小的提升,比如消除了隻讀限制。增加了聚集列存儲索引,列存儲索引作為了表的存儲方式,存儲表的資料。
索引列
需要指定列上建立
所有列都包含在内
存儲
額外增加百分之10的空間作為索引
壓縮十倍的資料量,如果表之前是頁壓縮,則可以壓縮5倍左右
更新
是
否
排序
在建立之前進行排序

如圖增量存儲部分我們叫做deltastore,用于存儲不夠最小行組大小的資料。流程就是将行資料提取成列資料,然後進行壓縮存儲,多餘的部分放到deltastore中。
插入新行的時候,值被存儲在deltastore中,直到達到最小rowgroup(行組)大小時,然後壓縮并移動到列存儲資料段中。
删除資料時,行将被删除從deltastore存儲中,但是在列存儲索引資料段中隻是被标記為删除,除非重建後才會被真的删除。
更新的時候,在deltastore存儲中行資料被删除,然後在列存儲資料段中被标記為删除,新的列别插入到deltastore中。
最後當重建索引的時。SQLServer将會删除所有标記為删除的資料段,資料存儲在deltastore中的将與資料段中的資料合并,然後進行壓縮。
我們首先建立一個事實表在資料庫中腳本如下:
讓我們檢查下聚集索引掃描操作符,Estimated I/O Cost(估計IO花銷) 的值為0.183866,Estimated CPU Cost(估計CPU花銷)為0.0435069,為了比較列索引的值,我們先記住:
現在我們建立列存儲索引在非聚集索引:
這個列存儲索引掃描操作符如下所示:
如上所示,Estimated I/O Cost從0.183866下降到0.0112731,這是因為SQL引擎隻檢索需要的列,節省了IO和記憶體資源。Estimated CPU的時間沒有變化。
IO強化與之前相比是明顯的,我們也可以比較兩個查詢,啟用I/O statistics,檢查IO的hits 表現如下:
正如所示,比較執行計劃,使用列存儲索引的要比行索引的好四倍,那麼期望一下處理大資料時的10倍性能:
當比較邏輯讀時你也能發現相似的結果。明顯這個邏輯讀也是四倍+關系。
那麼我們可以根據下圖概括一下傳統的行索引與列存儲是以的一般性差別:
也能夠使用SSMS建立索引: Indexes -> New Index ->Non-Clustered Columnstore Index 如下:
與非聚集索引建立類似,選擇列,然後這些列沒有排序也不能使用Include選項:
下圖中我在SQL Server2014 企業版中,建立聚集索引:
需要注意的是如果在表上已經有其他索引,嘗試建立聚集列存儲索引就會出現錯誤,正如我們之前說的,同一個表中不能或者其他索引:
不用選擇列,所有資料都包含在内了:
如果你有大型的事實表并且存在查詢問題的,或者SSAS存在其他性能問題的,列存儲是一個不錯的方案。一下兩種情況是經過測試的比較好的應用場景:
對于高頻率響應的報表/儀表闆,尤其分析當性能表現不佳的時候,會有很不錯的性能。
對于ETL的過程來講,源資料的列存儲索引将會極大提高性能,如果資料足夠大甚至可以考慮臨時建立列存儲索引。然後執行ETL。
列存儲索引是一個使用SQL Server性能優化的方案,通過減少IO消耗,尤其對資料倉庫和BI查詢都是由明顯性能提升。它通過排序資料作為列存儲,然後壓縮,并使用批處理來處理資料。當然,必須要確定使用列存儲索引的使用帶來了好處,而不會引起其他性能問題才能使用。比如需要注意使用的硬體環境和資料,如果沒有join、過濾、或者聚合導出巨大的資料量沒有足夠的記憶體則将被暫時放入硬碟進行switch off,進而引起查詢性能下降。盡量在使用之前在測試環境中測試是否适合使用,同時還要關注其他環節是否受影響。
補充,在2016中增加的幾個我認為不錯新的feature:
基于聚集列存儲索引的 B 樹索引;
基于記憶體優化表的列存儲索引;
CREATE TABLE 和 ALTER TABLE 中的列存儲索引的壓縮延遲選項;
單線程查詢的批處理執行。