以前已經寫過兩篇介紹列存儲索引的文章,可是隻有非彙集列存儲索引,今天再來簡單介紹一下彙集的列存儲索引,也就是可更新列存儲索引。在SQL Server 2012中首次引入了基於列存儲數據格式的存儲方式。叫作「列存儲索引」。前一篇我已經比較了行存儲索引與非彙集的列存儲索引(http://www.cnblogs.com/wenBlog/p/5682024.html)。其中對於在小表的指定值或者小範圍的查詢來說,尤爲針對事務性的負載行存儲是很合適的。可是對於分析性負載像數據倉庫和BI,在查詢中將會對大量數據進行全掃描,例如事實表,這時候列存儲索引就是更好地選擇。html
在列存儲索引中,數據按照獨立列組織到一塊兒造成索引結構。每列都數據都位於被高度壓縮的數據集中,叫作數據段。這個數據段只包含該列的值,對於大型表它分到多個數據段中,每一個數據段中只含有100萬行數據,這就叫作行組、數據段由一個或者多個數據頁組成。數據將在內存和硬盤上以數據段的形式傳輸。sql
這種索引提升了數據倉庫的查詢效率。這種經過壓縮得到數據格式要比B-Tree結構的壓縮率高7倍多。同時因爲列存儲索引使用了批處理模式執行,數據處理也是批處理的,較少了CPU的使用。列存儲索引強化了檢索數據的速度,與行存儲不一樣的是不用查詢全部列。由於這個緣由,更少數據被讀取到內存中,再處處理器緩存處理。相關的這些因素都會減小硬盤IO,提升總體查詢的性能。數據庫
在2014中列存儲索引有如下限制:緩存
最多支持1024列在你的索引中;性能優化
列存儲索引不能被定義爲惟一性索引;ide
不能建立視圖;性能
不能包含稀疏列;測試
不能使用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中的將與數據段中的數據合併,而後進行壓縮。
咱們首先建立一個事實表在數據庫中腳本以下:
1 USE SQLShackDemo 2 3 GO 4 --建立表 5 CREATE TABLE [dbo].[FactFinance]( 6 7 [FinanceKey] [int] NOT NULL, 8 9 [DateKey] [int] NOT NULL, 10 11 [OrganizationKey] [int] NOT NULL, 12 13 [DepartmentGroupKey] [int] NOT NULL, 14 15 [ScenarioKey] [int] NOT NULL, 16 17 [AccountKey] [int] NOT NULL, 18 19 [Amount] [float] NOT NULL, 20 21 [Date] [datetime] NULL 22 23 ) ON [PRIMARY] 24 25 GO 26 27 --建立彙集索引: 28 29 CREATE CLUSTERED INDEX [IX_FactFinance_FinanceKey_DateKey] ON [dbo].[FactFinance] ( [FinanceKey],[DateKey]) 30 GO 31 32 33 --查詢表: 34 35 SELECT [FinanceKey] 36 37 ,[DateKey] 38 39 ,[OrganizationKey] 40 41 ,[DepartmentGroupKey] 42 43 FROM [FactFinance]
讓咱們檢查下彙集索引掃描操做符,Estimated I/O Cost(估計IO花銷) 的值爲0.183866,Estimated CPU Cost(估計CPU花銷)爲0.0435069,爲了比較列索引的值,咱們先記住:
如今咱們建立列存儲索引在非彙集索引:
CREATE NONCLUSTERED COLUMNSTORE INDEX [IX_FactFinance_FinanceKey_DateKey_OrganizationKey_DepartmentGroupKey] ON [FactFinance] ([FinanceKey],[DateKey],[OrganizationKey],[DepartmentGroupKey]) GO SELECT [FinanceKey] ,[DateKey] ,[OrganizationKey] ,[DepartmentGroupKey] FROM [FactFinance]
這個列存儲索引掃描操做符以下所示:
如上所示,Estimated I/O Cost從0.183866降低到0.0112731,這是由於SQL引擎只檢索須要的列,節省了IO和內存資源。Estimated CPU的時間沒有變化。
IO強化與以前相比是明顯的,咱們也能夠比較兩個查詢,啓用I/O statistics,檢查IO的hits 表現以下:
SET STATISTICS IO ON GO SELECT [FinanceKey] ,[DateKey] ,[OrganizationKey] ,[DepartmentGroupKey] FROM [FactFinance] with (index (IX_FactFinance_FinanceKey_DateKey)) GO SELECT [FinanceKey] ,[DateKey] ,[OrganizationKey] ,[DepartmentGroupKey] FROM [FactFinance] with (index(IX_FactFinance_FinanceKey_DateKey_OrganizationKey_DepartmentGroupKey))
正如所示,比較執行計劃,使用列存儲索引的要比行索引的好四倍,那麼指望一下處理大數據時的10倍性能:
當比較邏輯讀時你也能發現類似的結果。明顯這個邏輯讀也是四倍+關係。
那麼咱們能夠根據下圖歸納一下傳統的行索引與列存儲因此的通常性區別:
也可以使用SSMS建立索引: Indexes -> New Index ->Non-Clustered Columnstore Index 以下:
與非彙集索引建立相似,選擇列,而後這些列沒有排序也不能使用Include選項:
下圖中我在SQL Server2014 企業版中,建立彙集索引:
須要注意的是若是在表上已經有其餘索引,嘗試建立彙集列存儲索引就會出現錯誤,正如咱們以前說的,同一個表中不能或者其餘索引:
不用選擇列,全部數據都包含在內了:
若是你有大型的事實表而且存在查詢問題的,或者SSAS存在其餘性能問題的,列存儲是一個不錯的方案。一下兩種狀況是通過測試的比較好的應用場景:
列存儲索引是一個使用SQL Server性能優化的方案,經過減小IO消耗,尤爲對數據倉庫和BI查詢都是由明顯性能提高。它經過排序數據做爲列存儲,而後壓縮,並使用批處理來處理數據。固然,必需要確保使用列存儲索引的使用帶來了好處,而不會引發其餘性能問題才能使用。好比須要注意使用的硬件環境和數據,若是沒有join、過濾、或者聚合導出巨大的數據量沒有足夠的內存則將被暫時放入硬盤進行switch off,從而引發查詢性能降低。儘可能在使用以前在測試環境中測試是否適合使用,同時還要關注其餘環節是否受影響。
補充,在2016中增長的幾個我認爲不錯新的feature:
基於彙集列存儲索引的 B 樹索引;
基於內存優化表的列存儲索引;
CREATE TABLE 和 ALTER TABLE 中的列存儲索引的壓縮延遲選項;
單線程查詢的批處理執行。