3.8 列存储索引
3.8.1 列存储的概念
在传统的索引技术中,每一行的索引数据都被一起保持在一页中(SQL Server 不允许索引行跨页),每列数据在一个索引中是跨所有页保留的。也就是说,传统索引对每行的数据进行分组和存储,然后联接所有的行以完成整个索引。
列存储索引(columnstore index)不同于传统索引,它对每列的数据进行分组和存储,然后联接所有的列以完成整个索引。列存储有以下优势:
(1)每列的索引数据都进行了压缩,因为许多列都可能包含非常重复的数据值,所以压缩率非常高。
与使用非压缩数据大小相比,可提供多达 7 倍数据压缩率。
(2)查询通常仅从表中选择几列,列存储的架构降低了索引中的页数量,这减少了从物理介质的总 I/O。
(3)较高的压缩率通过使用更小的内存中空间提高查询性能。反过来,因为 SQL Server 可以在内存中执行更多查询和数据操作,因此可以提高查询性能。
(4)SQL Server 使用批处理模式执行(有时候称作基于向量或向量化的执行)与列存储存储格式紧密集成,并且围绕列存储存储格式进行了优化,它可以极大降低 CPU 使用率。
与传统面向行的存储方式相比,使用列存储索引存档可最多提高 10 倍查询性能。列存储索引特别适合于对大型数据集执行分析的大多数只读查询。通常,列存储索引是针对数据仓库工作负荷的查询。列存储索引为使用全表扫描的查询带来很大的性能好处,但不适合于查找数据并且搜索特定值的查询。
3.8.2 行组和列段
为获得高性能和高压缩率,列存储索引将表划分为由行构成的组,称为行组。行组中的行数必须足够大(通常可包含的最大行数是 1,048,576 行),以便提高压缩率,并且还要足够小,以便从内存中操作中受益。
每个行组再以按列形式压缩,称为列段。每个列在每个行组中有一个列段,每个列段一起压缩并且存储于物理介质上。
3.8.3 非聚集列存储索引
SQL Server 2012 开始引入非聚集列存储索引。它是在传统的行存储表中(堆或聚集索引)使用
CREATE COLUMNSTORE INDEX 语句创建非聚集列存储索引。例如:
CREATE NONCLUSTERED COLUMNSTORE INDEX Order_simple ON Orders (OrderNum, OrderDate, CustomerNum) |
具有非聚集列存储索引的表在该索引被删除或禁用前是只读的。若要更新该表和非聚集列存储索引,可以使用以下方案之一:
(1)可以将更新数据存储在其他不含列存储索引表,再联接到该表。
(2)可以禁用该索引,更新该表,然后重新生成该索引。
(3)可以切入和切出分区。
3.8.4 可更新聚集列存储索引
SQL Server 2014 在企业版、开发版和评估版中还提供了可更新聚集列存储索引。它是针对整个表的物理存储空间并且是表的唯一索引。聚集索引可更新,可以对索引执行插入、删除和更新操作,并且可以将数据大容量加载到索引中。
列存储索引可能会将一些数据暂时存储于称作增量存储的行存储表中,同时还存储针对已删除行的 ID 的 B 树。
增量存储操作在后台处理。在增量存储达到最大行数后,它会关闭。元组移动进程(tuple-move process)会检查是否有已关闭的行组。在它找到已关闭行组后,会对其进行压缩并且将其存储到列存储中。
若要创建聚集列存储索引,请首先作为堆或聚集索引创建一个行存储表,然后,使用 CREATE CLUSTERED COLUMNSTORE INDEX 语句将该表转换为聚集列存储索引。如果需要让该聚集列存储索引具有与聚集索引相同的名称,则使用 DROP_EXISTING 选项。
可以使用 DROP INDEX 语句删除聚集列存储索引。此操作将删除该索引并将列存储表转换为行存储堆。
提示:
创建列存储索引默认情况下是一种并行操作,因此它比按顺序创建索引需要更多的内存。在内存充足的情况下,创建列存储索引相当于在同一列上生成 B 树所用时间的 1.5 倍。
创建列存储索引所需的内存取决于列数、字符串列的数目、并行度 (DOP) 和数据特性。例如,如果某个表具有不到 10 亿行,SQL Server 将仅使用一个线程创建列存储索引。
如果某个表具有超过 10 亿行,但 SQL Server 无法获得足够大的内存授予来使用最大并行度(MAXDOP) 创建索引,SQL Server 将根据需要自动减少 MAXDOP,以便适合可用内存授予。因此请计划足够的内存以便并行创建列存储索引。
本文出自 “SQL Server 管理员指南” 博客,谢绝转载!