数据压缩

SQL Server 2014 支持用于行存储表和索引的行压缩和页压缩,以及用于列存储表和索引的列存储压缩和列存储存档压缩。

对于行存储表和索引,请使用数据压缩功能来帮助减小数据库的大小。 除了节省空间外,数据压缩还有助于提高 I/O 密集型工作负荷的性能,因为数据存储在更少的页中,查询需要从磁盘读取更少的页。 但是,在与应用程序交换数据时,在数据库服务器上需要额外的 CPU 资源来压缩和解压缩数据。 可以在以下数据库对象上配置行和页面压缩:

  • 以堆形式存储的整个表。

  • 这是一张作为聚集索引存储的完整表。

  • 整个非聚集索引。

  • 整个索引视图。

  • 对于分区表和索引,可以为每个分区配置压缩选项,并且对象的各个分区不必具有相同的压缩设置。

对于列存储表和索引,所有列存储表和索引始终使用列存储压缩,这是用户不可配置的。 使用列存储档案压缩进一步减小数据大小,以便在可以投入额外的时间和 CPU 资源来存储和检索数据时。 可以对以下数据库对象配置列存储存档压缩:

  • 整个列存储表或整个聚集列存储索引。 由于列存储表存储为聚集列存储索引,因此这两种方法的结果相同。

  • 整个非聚集列存储索引。

  • 对于分区列存储表和列存储索引,可以为每个分区配置存档压缩选项,并且各个分区不必具有相同的存档压缩设置。

使用行和页面压缩时的注意事项

使用行和页面压缩时,请注意以下注意事项:

  • 在 Service Pack 或后续版本中,数据压缩的详细信息可能会更改。

  • 压缩在 SQL Server 的每个版本中都不可用。 有关详细信息,请参阅 Features Supported by the Editions of SQL Server 2014

  • 压缩不适用于系统表。

  • 压缩可以允许将更多行存储在页面上,但不会更改表或索引的最大行大小。

  • 当最大行大小加上压缩开销超过最大行大小 8060 字节时,无法启用表进行压缩。 例如,由于额外的压缩开销,无法压缩包含列 c1char(8000) 和 c2char(53) 的表。 使用 vardecimal 存储格式时,启用格式时将执行行大小检查。 对于行和页面压缩,在最初压缩对象时执行行大小检查,然后在插入或修改每行时进行检查。 压缩强制实施以下两个规则:

    • 对固定长度类型的更新必须始终成功。

    • 禁用数据压缩必须始终成功。 即使压缩行适合放入页面中,这意味着它小于 8060 字节,SQL Server 可防止在取消压缩后无法适应该行的更新。

  • 指定分区列表时,可将压缩类型设置为单个分区上的 ROW、PAGE 或 NONE。 如果未指定分区列表,则使用语句中指定的数据压缩属性设置所有分区。 创建表或索引时,除非另有指定,否则数据压缩将设置为 NONE。 修改表时,除非指定了其他压缩设置,否则将保留现有压缩设置。

  • 如果指定的分区列表或分区超出范围,将生成错误。

  • 非聚集索引不继承表的压缩属性。 若要压缩索引,必须显式设置索引的压缩属性。 默认情况下,创建索引时,索引的压缩设置将设置为 NONE。

  • 对堆创建聚集索引时,聚集索引会继承该堆的压缩状态,除非指定了另一压缩状态。

  • 配置堆以实现页面级压缩时,页面仅通过以下方式进行页面级压缩:

    • 数据是在启用批量优化后批量导入的。

    • 使用 INSERT INTO ... WITH (TABLOCK) 语法插入数据,并且表没有非聚集索引。

    • 通过执行带有 PAGE 压缩选项的 ALTER TABLE ... REBUILD 语句来重建表。

  • 在堆中分配的新页面作为 DML 操作的一部分,在重新构建堆之前,不会使用 PAGE 压缩。 通过删除和重新应用压缩或创建和删除聚集索引来重新生成堆。

  • 更改堆的压缩设置需要重新生成表上的所有非聚集索引,以便它们具有指向堆中新行位置的指针。

  • 可以联机或脱机启用或禁用 ROW 或 PAGE 压缩。 当执行联机操作时,对堆启用压缩功能是单线程的。

  • 启用或禁用行或页面压缩的磁盘空间要求与创建或重新生成索引相同。 对于分区数据,可以通过一次启用或禁用一个分区的压缩来减少所需的空间。

  • 若要确定分区表中分区的压缩状态,请查询 sys.partitions 目录视图的data_compression列。

  • 压缩索引时,可以使用行和页面压缩来压缩叶级页面。 非叶级页面不进行页面压缩。

  • 由于它们的大小,大值数据类型有时与特殊用途页面上的普通行数据分开存储。 数据压缩不适用于单独存储的数据。

  • 在 SQL Server 2005 中实现 vardecimal 存储格式的表将在升级时保留该设置。 可以将行压缩应用于具有 vardecimal 存储格式的表。 但是,由于行压缩是 vardecimal 存储格式的超集,因此没有理由保留 vardecimal 存储格式。 将 vardecimal 存储格式与行压缩相结合时,小数值不会获得额外的压缩。 可以将页面压缩应用于具有 vardecimal 存储格式的表;但是,vardecimal 存储格式列可能无法实现额外的压缩。

    注释

    SQL Server 2014 支持 vardecimal 存储格式;但是,由于行级压缩达到了相同的目标,因此已弃用 vardecimal 存储格式。 此功能将在Microsoft SQL Server 的未来版本中删除。 避免在新开发工作中使用此功能,并计划修改当前使用此功能的应用程序。

使用列存储和列存储存档压缩

适用于:SQL Server (SQL Server 2014 到 当前版本)。

基础

列存储表和索引始终使用列存储压缩进行存储。 可以通过配置名为存档压缩的其他压缩来进一步减小列存储数据的大小。 若要执行存档压缩,SQL Server 对数据运行 Microsoft XPRESS 压缩算法。 使用以下数据压缩类型添加或删除存档压缩:

  • 使用 COLUMNSTORE_ARCHIVE 数据压缩通过存档压缩来压缩列存储数据。

  • 使用 COLUMNSTORE 数据压缩来解压缩存档压缩。 生成的数据将继续使用列存储压缩进行压缩。

若要添加存档压缩,请使用 ALTER TABLE (Transact-SQL)ALTER INDEX (Transact-SQL) 并使用 REBUILD 选项,数据压缩 = COLUMNSTORE。

例子:

ALTER TABLE ColumnstoreTable1   
REBUILD PARTITION = 1 WITH (DATA_COMPRESSION =  COLUMNSTORE_ARCHIVE) ;  
  
ALTER TABLE ColumnstoreTable1   
REBUILD PARTITION = ALL WITH (DATA_COMPRESSION =  COLUMNSTORE_ARCHIVE) ;  
  
ALTER TABLE ColumnstoreTable1   
REBUILD PARTITION = ALL WITH (DATA_COMPRESSION =  COLUMNSTORE_ARCHIVE ON PARTITIONS (2,4)) ;  
  

若要删除存档压缩并将数据还原到列存储压缩,请使用 ALTER TABLE(Transact-SQL)ALTER INDEX(Transact-SQL),并使用 REBUILD 选项,并设置数据压缩为 COLUMNSTORE。

例子:

ALTER TABLE ColumnstoreTable1   
REBUILD PARTITION = 1 WITH (DATA_COMPRESSION =  COLUMNSTORE) ;  
  
ALTER TABLE ColumnstoreTable1   
REBUILD PARTITION = ALL WITH (DATA_COMPRESSION =  COLUMNSTORE) ;  
  
ALTER TABLE ColumnstoreTable1   
REBUILD PARTITION = ALL WITH (DATA_COMPRESSION =  COLUMNSTORE ON PARTITIONS (2,4) ) ;  
  

下一个示例将数据压缩在某些分区上设置为列存储,而在其他分区上设置为列存储存档。

ALTER TABLE ColumnstoreTable1   
REBUILD PARTITION = ALL WITH (  
    DATA_COMPRESSION =  COLUMNSTORE ON PARTITIONS (4,5),  
    DATA COMPRESSION = COLUMNSTORE_ARCHIVE ON PARTITIONS (1,2,3)  
) ;  

性能

使用存档压缩压缩压缩列存储索引会导致索引的执行速度比没有存档压缩的列存储索引慢。 仅当能够使用额外的时间和 CPU 资源来压缩和检索数据时,才使用存档压缩。

性能较慢的好处是降低存储,这对于不经常访问的数据很有用。 例如,如果每个月都有一个分区,并且大多数活动是最近几个月,则可以存档较旧的月份以减少存储要求。

元数据

以下系统视图包含有关聚集索引的数据压缩的信息:

过程 sp_estimate_data_compression_savings(Transact-SQL) 不适用于列存储索引。

压缩对分区表和索引的影响如何

对已分区表和索引使用数据压缩时,请注意以下注意事项:

  • 使用 ALTER PARTITION 语句拆分分区时,这两个分区都继承原始分区的数据压缩属性。

  • 合并两个分区时,生成的分区将继承目标分区的数据压缩属性。

  • 若要切换分区,分区的数据压缩属性必须与表的压缩属性匹配。

  • 可以使用两种语法变体来修改已分区表或索引的压缩:

    • 以下语法仅重新生成引用的分区:

      ALTER TABLE <table_name>   
      REBUILD PARTITION = 1 WITH (DATA_COMPRESSION =  <option>)  
      
    • 以下语法使用未引用的任何分区的现有压缩设置重新生成整个表:

      ALTER TABLE <table_name>   
      REBUILD PARTITION = ALL   
      WITH (DATA_COMPRESSION = PAGE ON PARTITIONS(<range>),  
      ... )  
      

    分区索引遵循使用 ALTER INDEX 的相同原则。

  • 删除聚集索引后,除非修改了分区方案,否则相应的堆分区将保留其数据压缩设置。 如果分区方案发生变化,将所有分区重新构建为未压缩状态。 若要删除聚集索引并更改分区方案,需要执行以下步骤:

    1. 删除聚集索引。

    2. 通过使用 ALTER TABLE ... REBUILD ... 选项来修改表,并指定压缩选项。

    若要删除聚集索引离线是一项非常快速的操作,因为只会删除聚集索引的上层。 当删除聚集索引 ONLINE 时,SQL Server 必须重新生成堆两次,一次用于步骤 1,一次用于步骤 2。

压缩如何影响复制

在复制中使用数据压缩时,请注意以下注意事项:

  • 当快照代理生成初始架构脚本时,新架构将为表及其索引使用相同的压缩设置。 不能仅对表启用压缩,也不能启用索引。

  • 对于事务复制,文章架构选项确定哪些依赖对象和属性需要被脚本化。 有关详细信息,请参阅 sp_addarticle

    分发代理在应用脚本时不会检查低版本订阅者。 如果选择复制压缩,则在版本较低的订阅服务器上创建表时将会失败。 对于混合拓扑,请不要启用压缩复制。

  • 对于合并复制,发布兼容性级别将替代架构选项,并确定将编写脚本的架构对象。

    对于混合拓扑,如果不需要支持新的压缩选项,则应将发布兼容性级别设置为下层订阅服务器版本。 如果需要,在创建订阅服务器后压缩表。

下表展示了用于控制复制过程中压缩的设置。

用户意向 复制表或索引的分区方案 复制压缩设置 脚本行为
复制分区方案并在分区上的订阅服务器上启用压缩。 真 实 真 实 编写分区方案和压缩设置的脚本。
复制分区方案,但不压缩订阅服务器上的数据。 真 实 编写分区方案的脚本,但不包括分区的压缩设置。
不复制分区方案,不压缩订阅服务器上的数据。 不编写分区或压缩设置的脚本。
如果发布服务器上压缩了所有分区,但不复制分区方案,则压缩订阅服务器上的表。 真 实 检查是否为所有分区启用了压缩。

在表级别编写压缩脚本。

压缩如何影响其他 SQL Server 组件

压缩发生在存储引擎中,数据呈现给处于未压缩状态的 SQL Server 的大多数其他组件。 这会将压缩对其他组件的影响限制为:

  • 批量导入和导出操作

    导出数据时,即使采用本机格式,数据也会以未压缩的行格式输出。 这可能会导致导出的数据文件的大小明显大于源数据。

    导入数据后,如果启用了目标表进行压缩,则存储引擎会将数据转换为压缩行格式。 与将数据导入未压缩表时相比,这可能会导致 CPU 使用率增加。

    将数据批量导入到包含页面压缩的堆中时,大容量导入作将尝试在插入数据时使用页面压缩来压缩数据。

  • 压缩不会影响备份和还原。

  • 压缩不会影响日志传送。

  • 数据压缩与稀疏列不兼容。 因此,不能压缩包含稀疏列的表,也不能将稀疏列添加到压缩表中。

  • 启用压缩可能会导致查询计划发生更改,因为数据使用不同页数和每页的行数进行存储。

另请参阅

行压缩实现
页面压缩实现
Unicode 压缩实现
CREATE PARTITION SCHEME (Transact-SQL)
CREATE PARTITION FUNCTION (Transact-SQL)
CREATE TABLE (Transact-SQL)
ALTER TABLE (Transact-SQL)
创建索引(Transact-SQL)
ALTER INDEX (Transact-SQL)