SQL Server 2012 ColumnStore索引簡介


微軟官方簡介

SQL 服務器 2012年引入了一種新的名為 ColumnStore 的索引。ColumnStores 是所有有關性能和提高的性價比。中非 ColumnStore 查詢處理的每個數據行。與 ColumnStore,可以將 SQL Server 進程行在批處理。不只是數據在多個行的列存儲在單個數據頁中,但您也可以在批處理中處理它。最重要的是大量壓縮數據。這工作是比率大約為 7-1。

ColumnStore 提供了很多更好的吞吐量,因為 CPU 開銷減少執行查詢時。處理需要較少的 I/O 和 RAM,非常適合於快速跟蹤數據倉庫體系結構。ColumnStore 索引提供大規模的 10 到 100 倍性能改進對經常基於行的索引。

限制:

 SQL Server 的索引有很多種,詳見:http://msdn.microsoft.com/zh-cn/library/ms175049.aspx

  是不是有了列存儲索引,其他類型的索引就都可以光榮下崗了?以后什么情況下我們都可以使用列存儲索引嗎?

 

顯然不是這樣的,列存儲索引有着很大的局限性,我們看一下它有哪些限制?

  1.列存儲索引包含的列數不能超過 1024。

  在SQL Server 2012的最大容量規范中提到每個select ,每個insert ,每個update的列數最多是4096。SQL Server 2008用稀疏列突破了單表1024列的限制,列存儲索引限制為不能超過1024列(個人認為這個限制並無大礙,畢竟那么多字段的表還是很少見的)。

  2.無法聚集。只有非聚集列存儲索引才可用。

  例如我們把剛才的索引刪掉,重新創建聚集索引。

create clustered columnstore index PK__TestTabl__ColumnStore
on TestTable(c1,c2,c3,c4,c5)

  錯誤信息是這樣的:不支持聚集列存儲索引

  3.非聚集索引也只能創建一個。

create nonclustered columnstore index PK__TestTabl__ColumnStore2
on TestTable(c1,c2)

  錯誤信息是這樣的:不支持多個非聚集列存儲索引

  4.不能是唯一索引。

  我們再把剛才的索引刪掉,重新創建聚集索引。

create unique columnstore index PK__TestTabl__ColumnStore
on TestTable(c1,c2,c3,c4,c5)

  錯誤信息是這樣的:由於列存儲索引不是唯一的,CREATE INDEX 語句失敗。請在不使用 UNIQUE 關鍵字的情況下創建該列存儲索引,或在不使用 COLUMNSTORE 關鍵字的情況下創建一個唯一索引

  5.不能基於視圖或索引視圖創建。

create view v_ColumnStore
as
select top 100 * from TestTable
go
create nonclustered columnstore index PK__TestTabl__ColumnStore
on v_ColumnStore(c1,c2,c3,c4,c5)

  錯誤信息是這樣的:由於無法對視圖創建列存儲索引,CREATE INDEX 語句失敗。請考慮對基表創建列存儲索引,或不帶 COLUMNSTORE 關鍵字對視圖創建一個索引

  6.不能包含稀疏列。

  創建一個2050個字段的表:

declare @sql varchar(max)
set @sql = ' create table TestColumn (maco xml column_set for all_sparse_columns'
select
    @sql
= @sql + ' ,'+'C'+ltrim(number)+' int sparse '
from master..spt_values where type = ' p'
exec(@sql + ' )')
go
alter table TestColumn add newcol
int

  新建的表中除了newcol,maco列外,其他2048個列都是稀疏列。

create nonclustered columnstore index PK__TestTabl__ColumnStore
on TestColumn(newcol)

  錯誤信息是這樣的:由於不能對稀疏列創建列存儲索引,CREATE INDEX 語句失敗。請考慮對不包含任意稀疏列的列子集創建非聚集列存儲索引

列存儲索引:限制分析
▲圖F

  7.不能作為主鍵或外鍵

  原文是Cannot act as a primary key or a foreign key.

  我上面的測試數據表中是有主鍵的,我們在主鍵上創建一個列存儲索引試一試。

create nonclustered columnstore index PK__TestTabl__ColumnStore
on TestTable(id)

列存儲索引:限制分析
▲圖G

  結果是成功的。我們再測試一下性能:

列存儲索引:限制分析
▲圖H

  測試結果表明對主鍵再添加列存儲索引是可以加上的,但是不起作用,應該說是起副作用。

  8.不能使用 ALTER INDEX 語句更改。而應在刪除后重新創建列存儲索引。

alter index PK__TestTabl__ColumnStore on TestTable reorganize

  錯誤信息是這樣的:由於不能重新組織列存儲索引,ALTER INDEX 語句失敗。重新組織列存儲索引不是必需的

  我們可以使用 ALTER INDEX 禁用和重新生成列存儲索引。

-- 停用
alter index PK__TestTabl__ColumnStore
on TestTable disable
-- 重啟
alter index PK__TestTabl__ColumnStore
on TestTable rebuild

 

 

 9.不能使用 INCLUDE 關鍵字創建。

 

create nonclustered columnstore index PK__TestTabl__ColumnStore
on TestTable(c1) include(c2,c3)

 

  錯誤信息是這樣的:由於列存儲索引不能有包含的列,CREATE INDEX 語句失敗

 

  10.不能包括用來對索引排序的 ASC 或 DESC 關鍵字。

 

  根據壓縮算法對列存儲索引排序。不允許在索引中進行排序。可能按照搜索算法對從列存儲索引中選擇的值進行排序,但是您必須使用 ORDER BY 子句來確保對結果集進行排序。

 

  11.不以傳統索引的方式使用或保留統計信息。

 

  查詢優化的統計信息是一些對象,這些對象包含與值在表或索引視圖的一列或多列中的分布有關的統計信息。查詢優化器使用這些統計信息來估計查詢結果中的基數或行數。通過這些基數估計,查詢優化器可以創建高質量的查詢計划。例如,查詢優化器可以使用基數估計選擇索引查找運算符而不是耗費更多資源的索引掃描運算符,從而提高查詢性能。列存儲索引是基於列的,不關心行數和行中數據的分布情況,所以不以傳統索引的方式使用或保留統計信息。

 

  12.不能對計算列加列存儲索引。

 

-- 添加一個計算列
alter table TestTable add c6
as c1 + c5
-- 給計算列添加列存儲索引
create nonclustered columnstore index PK__TestTabl__ColumnStore

 

  錯誤信息是這樣的:由於表“TestTable”的列“c6”為計算列,不能對計算列創建列存儲索引,CREATE INDEX 語句失敗。請考慮對不包含該列的列子集創建非聚集列存儲索引

 

  13.不能包含具有 FILESTREAM 屬性的列。表中未在索引中使用的其他列可以包含 FILESTREAM 屬性。

 

  從SQL Server 2008開始,增加了對FileStream的支持。FileStream定義在字段后面,標識該字段用於文件流,該列依然是用二進制保存的。

 

  一般都是在數據庫中要特別添加一個文件組和一個或多個文件用來存儲FileStream的數據的。

 

  如果表中的字段有filesteam屬性則不能在該列上創建列存儲索引。

 

  14.有列存儲索引后,表變成只讀表,不能進行添加,刪除,編輯的操作。

 

insert into TestTable(c1,c2) select rand(),rand()

 

  錯誤信息是這樣的:由於不能在包含列存儲索引的表中更新數據,INSERT 語句失敗

 

  微軟提供了三種方式來解決這個問題,這里簡單介紹兩種:

 

  1) 若要更新具有列存儲索引的表,先刪除列存儲索引,執行任何所需的 INSERT、DELETE、UPDATE 或 MERGE 操作,然后重新生成列存儲索引。

 

  2) 對表進行分區並切換分區。對於大容量插入,先將數據插入到一個臨時表中,在臨時表上生成列存儲索引,然后將此臨時表切換到空分區。對於其他更新,將主表外的一個分區切換到一個臨時表中,禁用或刪除臨時表上的列存儲索引,執行更新操作,在臨時表上重新生成或重新創建列存儲索引,然后將臨時表切換回主表。

 

-- 停用
alter index PK__TestTabl__ColumnStore
on TestTable disable
-- 插入數據
insert into TestTable(id,c1,c2)
select 10000002 ,rand(),rand()
-- 重啟
alter index PK__TestTabl__ColumnStore
on TestTable rebuild

 

  這樣就可以成功插入一條數據了。

 

  15.類型限制

 

  下數據類型不能包括在列存儲索引中:

 

  ·binary和varbinary

 

  ·ntext、text和 image

 

  ·varchar(max)和nvarchar(max)

 

  ·uniqueidentifier

 

  ·rowversion(和 timestamp)

 

  ·sql_variant

 

  ·精度大於 18 位的 decimal(和 numeric)

 

  ·標量大於 2 的 datetimeoffset

 

  ·CLR 類型(hierarchyid和空間類型)

 

  ·xml

 

-- 添加一個varchar(max)列
alter table TestTable add c7 varchar(max)
-- 給計算列添加列存儲索引
create nonclustered columnstore index PK__TestTabl__ColumnStore
on TestTable(c7)

 

  錯誤信息是這樣的:表 'TestTable' 中的列 'c7' 的類型不能用作索引中的鍵列

 

  16.列存儲索引不支持 SEEK

 

  如果查詢應返回行的一小部分,則優化器不大可能選擇列存儲索引(例如:needle-in-the-haystack 類型查詢)。

 

  如果使用表提示 FORCESEEK,則優化器將不考慮列存儲索引。

 

  17.列存儲索引不能與以下功能結合使用

 

  ·頁和行壓縮以及 vardecimal 存儲格式(列存儲索引已采用不同格式壓縮)。

 

  ·復制

 

  ·更改跟蹤

 

  ·變更數據捕獲

 

  ·文件流

優勢分析

列存儲索引雖然有一定的限制,但是它的優點還是很突出的。

  1.列存儲和列分組

  與傳統的基於行的數據組織方式(稱為“行存儲”格式)不同,在具有列存儲索引的分列數據庫系統中,每次對一個列的數據進行分組和存儲。SQL Server 查詢處理可以利用新的數據布局,並顯著改進查詢執行時間。

  2.對於靜態數據的讀取速度上有顯著的提高。

  只讀取需要的列。經過高度壓縮,減少了讀取和移動的字節數。

  3.沒有鍵列的概念

  列存儲索引中沒有鍵列的概念,因此,索引中的鍵列數限制 (16) 不適應於列存儲索引。

  4.記錄大小不受900字節的限制。

  索引鍵記錄大小限制(900 字節)也不適應於列存儲索引。

  5.性能的大幅度提升

  列存儲索引可用於顯著加快常見數據倉庫查詢的處理時間。典型的數據倉庫工作負荷涉及匯總大量數據。在數據倉庫和決策支持系統中通常用於提高性能的技術包括預先計算的匯總表、索引視圖、OLAP 多維數據集等。

  通過實例簡單的描述了一下列存儲索引的使用,詳細說明了使用中需要注意的一些限制,也了解了列存儲索引的優點。在下一個SQL Server版本中,很可能加強列存儲索引的優勢,減少其使用限制。

  例如現在建了該索引的表就是只讀表了,但是官方有提到:請勿將列存儲索引創建為一種使表成為只讀表的機制。在將來的版本中,不能保證限制對具有列存儲索引的表進行更新。當需要只讀行為時,應通過創建只讀文件組並將表移到此文件組中來強制執行。

讓我們共同期待功能越來越強悍的SQL Server!本文主要是參考官方文檔,結合個人實踐而來,如有錯誤,望指正。

 

測試實例

一.創建和使用

  實踐出真知,首先我們先模擬1000w測試數據。

  我本地的數據庫環境:

     select @@version
    
/*
     Microsoft SQL Server
2012 - 11.0 . 2100.60 (Intel X86)
     Feb
10 2012 19 : 13 : 17
     Copyright (c) Microsoft Corporation
     Developer Edition
on Windows NT 6.1 < X86 > (Build 7601 : Service Pack 1 )
    
*/

  1.數據模擬

  我們可以創建一個表:

create table TestTable
(
    id
int primary key,
    c1 float,c2 float,c3 float,c4 float,c5 float
)

  插入10000001條的數據:

; with maco (id,c1,c2, c3, c4,c5) as   
(
    
select 1 id,rand(),rand(),rand(),rand(),rand()
    union all  
    
select id + 1 ,rand(checksum(newid())),rand(checksum(newid())),
           rand(checksum(newid())),rand(checksum(newid())),rand(checksum(newid()))
    from maco where id
<= 10000000   
)
insert into TestTable
select * from maco option (maxrecursion 0 )

列存儲索引:新技術令查詢性能大幅提升
▲圖A

  確認一下插入數據成功:

select count( 1 ) as cnt from TestTable

  我們可以看到表中都是一些隨機數:

列存儲索引:創建和使用
▲圖B

  2.創建索引

  這個表我創建的時候設置了主鍵,默認是聚集索引,我們可以找到它的名字。

列存儲索引:創建和使用
▲圖C

  我再新建一個列存儲索引:

create nonclustered columnstore index PK__TestTabl__ColumnStore
on TestTable(c1,c2,c3,c4,c5)

  3.性能比較

  測試一下兩個索引的性能:邏輯讀取次數 ( 66558 vs 114 )

列存儲索引:創建和使用
▲圖D

  我們可以看到I/O大量減少,那么我們多測試幾次。

列存儲索引:創建和使用
▲圖E

  原來的索引不管是要查多少列都讀取6w多次,而列存儲索引的邏輯讀取次數和列數是有關系,如上圖可以明顯的看到要查詢的列數和邏輯讀取次數是成正比的。

  列存儲索引可以提高速度的主要原因,數據壓縮是一個方便,主要還是他只讀取查詢中用到的列的索引頁,而常規索引需要讀取全部索引頁,包括查詢結果中不使用的列。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM