CREATE COLUMNSTORE INDEX (Transact-SQL)

适用于:SQL ServerAzure SQL DatabaseAzure SQL Managed InstanceAzure Synapse Analytics分析平台系统(PDW)Microsoft Fabric中的SQL数据库

将行存储表转换为聚集列存储索引,或创建非聚集列存储索引。 使用列存储索引可以有效地对 OLTP 工作负荷运行实时作分析,或改进数据仓库工作负荷的数据压缩和查询性能。

遵循 列存储索引中的新增 功能,了解此功能的最新改进。

  • SQL Server 2022(16.x)中引入了有序聚集列存储索引。 有关详细信息,请参阅 CREATE COLUMNSTORE INDEX。 关于有序列存储索引的可用性,请参阅 列存储索引:概述

  • 从 SQL Server 2016 (13.x)开始,可以将表创建为聚集列存储索引。 不再需要先创建行存储表,然后将其转换为聚集列存储索引。

  • 有关列存储索引设计指南的信息,请参阅 列存储索引 - 设计指南

Transact-SQL 语法约定

Syntax

Azure SQL 数据库和 Azure SQL 托管实例AUTD 的语法:

-- Create a clustered columnstore index on disk-based table.
CREATE CLUSTERED COLUMNSTORE INDEX index_name
    ON { database_name.schema_name.table_name | schema_name.table_name | table_name }
    [ ORDER (column [ , ...n ] ) ]
    [ WITH ( <with_option> [ , ...n ] ) ]
    [ ON <on_option> ]
[ ; ]

-- Create a nonclustered columnstore index on a disk-based table.
CREATE [ NONCLUSTERED ]  COLUMNSTORE INDEX index_name
    ON { database_name.schema_name.table_name | schema_name.table_name | table_name }
        ( column  [ , ...n ] )
    [ ORDER (column [ , ...n ] ) ]
    [ WHERE <filter_expression> [ AND <filter_expression> ] ]
    [ WITH ( <with_option> [ , ...n ] ) ]
    [ ON <on_option> ]
[ ; ]

<with_option> ::=
      DROP_EXISTING = { ON | OFF } -- default is OFF
    | MAXDOP = max_degree_of_parallelism
    | ONLINE = { ON | OFF }
    | COMPRESSION_DELAY  = { 0 | delay [ MINUTES ] }
    | DATA_COMPRESSION = { COLUMNSTORE | COLUMNSTORE_ARCHIVE }
      [ ON PARTITIONS ( { partition_number_expression | range } [ , ...n ] ) ]

<on_option>::=
      partition_scheme_name ( column_name )
    | filegroup_name
    | "default"

<filter_expression> ::=
      column_name IN ( constant [ , ...n ]
    | column_name { IS | IS NOT | = | <> | != | > | >= | !> | < | <= | !< } constant )

SQL Server 的语法:

-- Create a clustered columnstore index on disk-based table.
CREATE CLUSTERED COLUMNSTORE INDEX index_name
    ON { database_name.schema_name.table_name | schema_name.table_name | table_name }
    [ WITH ( <with_option> [ , ...n ] ) ]
    [ ORDER (column [ , ...n ] ) ]
    [ ON <on_option> ]
[ ; ]

-- Create a nonclustered columnstore index on a disk-based table.
CREATE [ NONCLUSTERED ]  COLUMNSTORE INDEX index_name
    ON { database_name.schema_name.table_name | schema_name.table_name | table_name }
        ( column  [ , ...n ] )
    [ ORDER (column [ , ...n ] ) ]
    [ WHERE <filter_expression> [ AND <filter_expression> ] ]
    [ WITH ( <with_option> [ , ...n ] ) ]
    [ ON <on_option> ]
[ ; ]

<with_option> ::=
      DROP_EXISTING = { ON | OFF } -- default is OFF
    | MAXDOP = max_degree_of_parallelism
    | ONLINE = { ON | OFF }
    | COMPRESSION_DELAY  = { 0 | delay [ MINUTES ] }
    | DATA_COMPRESSION = { COLUMNSTORE | COLUMNSTORE_ARCHIVE }
      [ ON PARTITIONS ( { partition_number_expression | range } [ , ...n ] ) ]

<on_option>::=
      partition_scheme_name ( column_name )
    | filegroup_name
    | "default"

<filter_expression> ::=
      column_name IN ( constant [ , ...n ]
    | column_name { IS | IS NOT | = | <> | != | > | >= | !> | < | <= | !< } constant )

Azure Synapse Analytics 和分析平台系统的语法(PDW):

CREATE CLUSTERED COLUMNSTORE INDEX index_name
    ON { database_name.schema_name.table_name | schema_name.table_name | table_name }
    [ ORDER ( column [ , ...n ] ) ]
    [ WITH ( DROP_EXISTING = { ON | OFF } ) ] -- default is OFF
[;]

版本可用性

某些选项在所有数据库引擎版本中都不可用。 下表显示了群集列存储和非聚集列存储索引中引入选项时的版本:

Option CLUSTERED NONCLUSTERED
COMPRESSION_DELAY SQL Server 2016 (13.x) SQL Server 2016 (13.x)
DATA_COMPRESSION SQL Server 2016 (13.x) SQL Server 2016 (13.x)
ONLINE SQL Server 2019 (15.x) SQL Server 2017 (14.x)
WHERE 子句 N/A SQL Server 2016 (13.x)
ORDER 子句 SQL Server 2016 (13.x) SQL Server 2025 (17.x)

Azure SQL 数据库和 Azure SQL 托管实例AUTD 中提供了所有选项。

有关功能可用性的详细信息,请参阅 列存储索引中的新增功能。

Arguments

创建聚集列存储索引

创建聚集列存储索引,其中所有数据都按列进行压缩和存储。 索引包括表中的所有列,并存储整个表。 如果现有表是堆或聚集索引,则会将其转换为聚集列存储索引。 如果表已存储为聚集列存储索引,则会删除现有索引并重新生成。

Important

在 Fabric 中的 SQL 数据库中,必须在它所属的表所在的同一批或事务中创建聚集列存储索引。 在创建聚集列存储索引后,将聚集列存储索引添加到表可能会导致以下错误:

Msg 35354, Level 16, State 1, Line 63, The statement failed because a clustered columnstore index cannot be created on a table enabled for Change Feed. Consider disabling Change Feed and then creating the clustered columnstore index.

index_name

指定新索引的名称。

如果表已有聚集列存储索引,则可以指定与现有索引相同的名称,也可以使用 DROP EXISTING 选项指定新名称。

在[ database_name]。 [ schema_name ] . | schema_name 。 ] table_name

指定要存储为聚集列存储索引的表的一部分、两部分或三部分的名称。 如果表是堆或具有聚集索引,则表将从行存储转换为列存储。 如果表已是列存储,则此语句将重新生成聚集列存储索引。

聚集列存储的 ORDER

column_store_order_ordinal使用sys.index_columns中的列来确定聚集列存储索引的列的顺序。 列存储排序有助于消除 ,尤其是字符串数据。 有关详细信息,请参阅 使用有序列存储索引和列存储索引进行性能优化- 设计指南

若要转换为有序聚集列存储索引,现有索引必须是聚集列存储索引。 使用 DROP_EXISTING 选项。

LOB 数据类型(最大)长度数据类型不能是有序聚集列存储索引的键。

创建有序聚集列存储索引时,请使用MAXDOP = 1最高质量的排序选项,以换取语句持续时间显著延长。CREATE INDEX 若要尽快创建索引,请不要限制 MAXDOP。 压缩和排序的最高质量有助于查询列存储索引。

关于有序列存储索引的可用性,请参阅 列存储索引:概述

WITH 选项

DROP_EXISTING = [OFF] |上

DROP_EXISTING = ON 指定删除现有索引并创建新的列存储索引。

CREATE CLUSTERED COLUMNSTORE INDEX cci
    ON Sales.OrderLines WITH (DROP_EXISTING = ON);

默认值DROP_EXISTING = OFF,预期索引名称与现有名称相同。 如果指定的索引名称已存在,则会发生错误。

MAXDOP = max_degree_of_parallelism

此选项可以在索引作期间替代现有的最大并行度服务器配置。 使用 MAXDOP 限制并行计划执行中使用的处理器数。 最大值为 64 个处理器。

max_degree_of_parallelism 值可以是:

  • 1,这意味着禁止并行计划生成。
  • >1,这意味着根据当前系统工作负荷,将并行索引作中使用的最大处理器数限制为指定数目或更少。 例如,当 MAXDOP = 4 时,使用的处理器数为 4 或更少。
  • 0(默认值),这意味着根据当前系统工作负荷使用实际处理器数或更少。
CREATE CLUSTERED COLUMNSTORE INDEX cci
    ON Sales.OrderLines WITH (MAXDOP = 2);

有关详细信息,请参阅 服务器配置:最大并行度配置并行索引作

COMPRESSION_DELAY = 0 | 延迟 [ 分钟 ]

对于基于磁盘的表, 延迟 指定处于关闭状态的增量行组必须保留在增量行组中的最小分钟数。 然后,SQL Server 可以将它压缩到压缩的行组中。 由于基于磁盘的表不会跟踪各个行的插入和更新时间,因此 SQL Server 会将延迟应用于处于关闭状态的增量行组。

默认为 0 分钟。

CREATE CLUSTERED COLUMNSTORE INDEX cci
    ON Sales.OrderLines WITH (COMPRESSION_DELAY = 10 MINUTES);

有关何时使用COMPRESSION_DELAY的建议,请参阅 列存储索引入门,以获取实时作分析

DATA_COMPRESSION = COLUMNSTORE |COLUMNSTORE_ARCHIVE

为指定的表、分区号或分区范围指定数据压缩选项。 选项如下所示:

  • COLUMNSTORE 是默认值,指定使用性能最高的列存储压缩进行压缩。 此选项是典型的选择。
  • COLUMNSTORE_ARCHIVE 进一步将表或分区压缩为较小的大小。 对于存档等情况,使用此选项需要更小的存储大小,并且可以为存储和检索提供更多时间。
CREATE CLUSTERED COLUMNSTORE INDEX cci
    ON Sales.OrderLines WITH (DATA_COMPRESSION = COLUMNSTORE_ARCHIVE);

有关压缩的详细信息,请参阅数据压缩

ONLINE = [ON |OFF]
  • ON 指定列存储索引保持联机和可用,同时生成索引的新副本。
  • OFF 指定在生成新副本时,索引不可用。
CREATE CLUSTERED COLUMNSTORE INDEX cci
    ON Sales.OrderLines WITH (ONLINE = ON);

ON 选项

使用这些选项,可以指定数据存储的选项,例如分区方案、特定文件组或默认文件组。 如果未指定 ON 选项,索引将使用现有表的设置分区或文件组设置。

partition_scheme_namecolumn_name )指定表的分区方案。 该分区方案必须已存在于数据库中。 若要创建分区方案,请参阅 CREATE PARTITION SCHEME

column_name 指定分区索引所依据的列。 该列必须与 partition_scheme_name 使用的分区函数参数的数据类型、长度和精度相匹配。

filegroup_name 指定用于存储聚集列存储索引的文件组。 如果未指定位置且未对表进行分区,索引将使用与基础表或视图相同的文件组。 文件组必须已存在。

若要在默认文件组上创建索引,请使用 "default"[default]。 如果指定 "default",则 QUOTED_IDENTIFIER 选项必须为 ON 当前会话。 QUOTED_IDENTIFIER 默认设置为 ON。 有关详细信息,请参阅 SET QUOTED_IDENTIFIER

创建[非聚类]列存储索引

在存储为堆或聚集索引的行存储表上创建非聚集列存储索引。 索引可以具有筛选条件,无需包含基础表的所有列。 列存储索引需要足够的空间来存储数据的副本。 可以更新索引,并在基础表更改时对其进行更新。 聚集索引上的非聚集列存储索引可实现实时分析。

index_name

指定索引的名称。 index_name 在表中必须唯一,但不必在数据库中是唯一的。 索引名称必须遵循 标识符规则。

[ ,...n ]

指定要存储的列。 非聚集列存储索引限制为 1,024 列。

每个列都必须是列存储索引支持的数据类型。 请参阅受支持数据类型列表的限制 和限制

在[ database_name]。 [ schema_name ] . | schema_name 。 ] table_name

指定包含索引的表的一个、两部分或三部分的名称。

非聚集列存储的 ORDER

非聚集列存储索引子句中指定的 ORDER 列必须是索引的键列的子集。

column_store_order_ordinal使用sys.index_columns中的列来确定非聚集列存储索引的列的顺序。 列存储排序有助于消除 ,尤其是字符串数据。 有关详细信息,请参阅 使用有序列存储索引和列存储索引进行性能优化- 设计指南。 这些文章中的设计和性能注意事项通常适用于聚集列存储索引和非聚集列存储索引。

LOB 数据类型(最大)长度数据类型不能是有序的非聚集列存储索引的键。

创建有序的非聚集列存储索引时,请使用 MAXDOP = 1 质量最高的排序选项,以换取语句的 CREATE INDEX 持续时间明显更长。 若要尽快创建索引,请不要限制 MAXDOP。 压缩和排序的最高质量有助于查询列存储索引。

有关有序列存储索引可用性,请参阅 有序列索引可用性

WITH 选项

DROP_EXISTING = { OFF |ON }

  • DROP_EXISTING = 开

    删除现有索引并重新生成。 指定的索引名称必须与当前现有索引相同;但是,可以修改索引定义。 例如,可以指定不同的列或索引选项。

  • DROP_EXISTING = 关闭

    如果指定的索引名称已存在,则会显示错误。 无法使用DROP_EXISTING更改索引类型。 在向后兼容的语法中,WITH DROP_EXISTING等效于 WITH DROP_EXISTING = ON。

MAXDOP = max_degree_of_parallelism

替代 服务器配置:索引作期间的最大并行度 配置选项。 使用 MAXDOP 限制并行计划执行中使用的处理器数。 最大值为 64 个处理器。

max_degree_of_parallelism 值可以是:

  • 1,这意味着禁止并行计划生成。
  • >1,这意味着根据当前系统工作负荷,将并行索引作中使用的最大处理器数限制为指定数目或更少。 例如,当 MAXDOP = 4 时,使用的处理器数为 4 或更少。
  • 0(默认值),这意味着根据当前系统工作负荷使用实际处理器数或更少。

有关详细信息,请参阅 配置并行索引作

Note

Microsoft SQL Server 的每个版本中都不提供并行索引作。 有关 SQL Server 各个版次支持的功能列表,请参阅 SQL Server 2022 的各个版次及其支持的功能

ONLINE = [ON |OFF]
  • ON 指定列存储索引保持联机和可用,同时生成索引的新副本。
  • OFF 指定在生成新副本时,索引不可用。 在非聚集索引中,基表仍可用。 在完成新索引之前,仅使用非聚集列存储索引来满足查询。
CREATE COLUMNSTORE INDEX ncci
    ON Sales.OrderLines(StockItemID, Quantity, UnitPrice, TaxRate) WITH (ONLINE = ON);
COMPRESSION_DELAY = 0 | 延迟 [ 分钟 ]

指定行在有资格迁移到压缩行组之前,行在增量行组中保留多长时间的下限。 例如,你可以说,如果行未更改 120 分钟,该行有资格压缩为列式存储格式。

对于基于磁盘的表的列存储索引,不会跟踪插入或更新行的时间。 相反,增量行组关闭时间用作行的代理。 默认持续时间为 0 分钟。 行在增量行组中累积 100 万行后迁移到列存储,并且标记为已关闭。

DATA_COMPRESSION

为指定的表、分区号或分区范围指定数据压缩选项。 仅适用于列存储索引,包括非聚集索引和聚集索引。 选项如下所示:

  • COLUMNSTORE 是默认值,指定使用性能最高的列存储压缩进行压缩。 此选项是典型的选择。
  • COLUMNSTORE_ARCHIVE 进一步将表或分区压缩为较小的大小。 可以使用此选项进行存档,或者对于需要更小的存储大小的其他情况,并且可以为存储和检索提供更多时间。

有关压缩的详细信息,请参阅数据压缩

filter_expression<在哪>里 [ 和 <filter_expression> ]

此选项称为筛选器谓词,指定要包含在索引中的行。 SQL Server 针对筛选索引中的数据行创建筛选统计信息。

筛选器谓词使用简单的比较逻辑。 不允许使用 NULL 文本的比较运算符。 请改用 IS NULLIS NOT NULL 运算符。

下面是表的筛选器谓词 Production.BillOfMaterials 的一些示例:

  • WHERE StartDate > '20000101' AND EndDate <= '20000630'
  • WHERE ComponentID IN (533, 324, 753)
  • WHERE StartDate IN ('20000404', '20000905') AND EndDate IS NOT NULL

有关筛选索引的指南,请参阅 “创建筛选索引”。

ON 选项

以下选项指定在其中创建索引的文件组。

partition_scheme_namecolumn_name

指定用于定义已分区索引的分区映射到的文件组的分区方案。 分区方案必须通过执行 CREATE PARTITION SCHEME 存在于数据库中。

column_name 指定分区索引所依据的列。 该列必须与 partition_scheme_name 使用的分区函数参数的数据类型、长度和精度相匹配。 column_name 不限于索引定义中的列。 对列存储索引进行分区时,数据库引擎会将分区列添加为索引的列(如果尚未指定)。

如果表已分区,并且未指定 partition_scheme_name文件组 ,则索引将放置在同一分区方案中,并使用与基础表相同的分区列。

分区表上的列存储索引必须对齐分区。 有关分区索引的详细信息,请参阅 已分区表和索引

filegroup_name

指定要在其中创建索引的文件组名称。 如果未指定 filegroup_name 且未对表进行分区,索引将使用与基础表相同的文件组。 文件组必须已存在。

"default"

在默认文件组上创建指定的索引。

在此上下文中,术语默认值不是关键字。 它是默认文件组的标识符,必须按 In 或 in ON "default"ON [default]. 如果 "default" 指定,则当前会话QUOTED_IDENTIFIER选项必须为 ON,这是默认设置。 有关详细信息,请参阅 SET QUOTED_IDENTIFIER

Permissions

需要对表具有 ALTER 权限。

Remarks

可以在临时表上创建列存储索引。 删除表或会话结束时,也会删除索引。

在 Fabric SQL 数据库中,具有聚集列存储索引的表不会 镜像到 Fabric OneLake

筛选索引

筛选索引是优化的非聚集索引,适用于从表中选择少量行的查询。 它使用筛选器谓词为表中部分数据编制索引。 设计良好的筛选索引可以提高查询性能、降低存储成本以及降低维护成本。

筛选索引所需的 SET 选项

每当出现以下任一情况时,都需要所需值列中的 SET 选项:

  • 创建筛选索引。
  • INSERT、UPDATE、DELETE 或 MERGE作修改筛选索引中的数据。
  • 查询优化器使用筛选的索引生成查询计划。
SET 选项 所需的值 默认服务器值 默认的 OLE DB 和 ODBC 值 默认 DB-Library 值
ANSI_NULLS ON ON ON OFF
ANSI_PADDING ON ON ON OFF
ANSI_WARNINGS 1 ON ON ON OFF
ARITHABORT ON ON OFF OFF
CONCAT_NULL_YIELDS_NULL ON ON ON OFF
NUMERIC_ROUNDABORT OFF OFF OFF OFF
QUOTED_IDENTIFIER ON ON ON OFF

1 当数据库兼容性级别设置为 90 或更高版本时,ANSI_WARNINGS设置为 ON 将 ARITHABORT 隐式设置为 ON。 如果数据库兼容性级别设置为 80 或更早版本,则必须将 ARITHABORT 选项显式设置为 ON。

如果 SET 选项不正确,可能会出现以下情况:

  • 未创建筛选索引。

  • 数据库引擎生成错误,并回滚更改索引中的数据的 INSERT、UPDATE、DELETE 或 MERGE 语句。

  • 查询优化器不考虑任何 Transact-SQL 语句的执行计划中的索引。

有关筛选索引的详细信息,请参阅 “创建筛选索引”。

局限性

列存储索引中的每个列都必须是以下常见业务数据类型之一:

  • datetimeoffset [ ( n ) ]
  • datetime2 [ ( n ) ]
  • datetime
  • smalldatetime
  • date
  • time [ ( n ) ]
  • float [ ( n ) ]
  • real [ ( n ) ]
  • 十进制 [ ( 精度 [ , 刻度 ] ] ] ]
  • numeric [ ( precision [ , scale ] ] ] ]
  • money
  • smallmoney
  • bigint
  • int
  • smallint
  • tinyint
  • bit
  • nvarchar [ ( n ) ]
  • nvarchar(max)1
  • nchar [ ( n ) ]
  • varchar [ ( n ) ]
  • varchar(max)1
  • char [ ( n ) ]
  • varbinary [ ( n ) ]
  • varbinary(max)1
  • binary [ ( n ) ]
  • uniqueidentifier2

1 仅适用于群集列存储索引中的 SQL Server 2017(14.x)和 Azure SQL 数据库(高级层、标准层(S3 及更高版本),以及所有 vCore 产品/服务层。

2 适用于 SQL Server 2014(12.x)及更高版本。

如果基础表具有列存储索引不支持的数据类型的列,则必须从非聚集列存储索引中省略该列。

大于 8 KB 的大型对象(LOB)数据存储在行外 LOB 存储中,只需指向列段中存储的物理位置的指针。 存储的数据的大小不会在 sys.column_store_segmentssys.column_store_dictionariessys.dm_db_column_store_row_group_physical_stats中报告。

使用下列任何数据类型的列不能包含在列存储索引中:

  • ntext文本图像
  • nvarchar(max)varchar(max)varbinary(max)1
  • rowversion (和 时间戳
  • sql_variant
  • CLR 类型(hierarchyid 和空间类型)
  • xml
  • uniqueidentifier2

1 适用于 SQL Server 2016(13.x)及早期版本,以及非聚集列存储索引。

2 适用于 SQL Server 2012 (11.x)。

非聚集列存储索引:

  • 不能超过 1,024 列。
  • 无法创建为基于约束的索引。 对具有列存储索引的表具有唯一约束、主键约束和外键约束。 始终使用行存储索引强制实施约束。 不能使用列存储(聚集索引或非聚集索引)强制实施约束。
  • 不能包含稀疏列。
  • 无法使用 ALTER INDEX 语句进行更改。 若要更改非聚集索引,必须删除并重新创建列存储索引。 可以使用 ALTER INDEX 禁用和重新生成列存储索引。
  • 无法使用 INCLUDE 关键字创建。
  • 无法在索引列列表中指定 ASCDESC 关键字。 列存储索引根据压缩算法进行排序。
  • 在Azure SQL Database中,Microsoft Fabric中的SQL数据库、Azure SQL托管实例AUTD和SQL Server 2025(17.x)可以通过包含 ORDER 该子句来排序。 有关详细信息,请参阅 使用有序列存储索引进行性能优化
  • 不能在非聚集列存储索引中包含 nvarchar(max)varchar(max)varbinary(max) 类型的 LOB 列。 只有聚集列存储索引支持 LOB 类型,从 SQL Server 2017 (14.x) 版本开始,Azure SQL 数据库(在高级层、标准层(S3 及更高版本)和所有 vCore 产品/服务层级配置)。 以前的版本不支持聚集列存储索引和非聚集列存储索引中的 LOB 类型。
  • 从 SQL Server 2016 (13.x)开始,可以在索引视图上创建非聚集列存储索引。

列存储索引不能与以下功能结合使用:

  • 计算列。 从 SQL Server 2017 (14.x)开始,聚集列存储索引可以包含非持久化计算列。 但是,在 SQL Server 2017(14.x)中,聚集列存储索引不能包含持久化计算列,并且无法在计算列上创建非聚集索引。
  • 页面和行压缩以及 vardecimal 存储格式。 (列存储索引已以不同的格式压缩。
  • 使用聚集列存储索引进行复制。 支持非聚集列存储索引。 有关详细信息,请参阅 sp_addarticle
  • Filestream.

不能对具有聚集列存储索引的表使用游标或触发器。 此限制不适用于非聚集列存储索引。 可以对具有非聚集列存储索引的表使用游标和触发器。

SQL Server 2014 (12.x) 特定限制:

以下限制仅适用于 SQL Server 2014 (12.x)。 在此版本中,可以使用可更新的聚集列存储索引。 非聚集列存储索引仍然是只读的。

  • 更改跟踪。 不能对列存储索引使用更改跟踪。
  • 更改数据捕获。 无法在具有聚集列存储索引的表上启用此功能。 从 SQL Server 2016 (13.x)开始,可以在具有非聚集列存储索引的表上启用更改数据捕获。
  • 可读辅助数据库。 无法从 AlwaysOn 可读可用性组的可读辅助数据库访问聚集列存储索引(CCI)。 可以从可读辅助数据库访问非聚集列存储索引 (NCCI)。
  • 多个活动结果集(MARS)。 SQL Server 2014 (12.x) 使用此功能对具有列存储索引的表进行只读连接。 但是,SQL Server 2014 (12.x) 不支持对具有列存储索引的表上的并发数据作语言(DML)作使用此功能。 如果尝试将该功能用于此目的,SQL Server 将终止连接并取消事务。
  • 无法在视图或索引视图中创建非聚集列存储索引。

有关列存储索引的性能优势和限制的信息,请参阅 列存储索引:概述

Metadata

列存储索引中的所有列都作为包含的列存储在元数据中。 列存储索引没有键列。 以下系统视图提供有关列存储索引的信息:

示例:将表从行存储转换为列存储

A. 将堆转换为聚集列存储索引

本示例创建一个表作为堆,然后将其转换为名为 <a0/> 的聚集列存储索引。 创建聚集列存储索引会将整个表的存储从行存储更改为列存储。

CREATE TABLE dbo.SimpleTable
(
    ProductKey INT NOT NULL,
    OrderDateKey INT NOT NULL,
    DueDateKey INT NOT NULL,
    ShipDateKey INT NOT NULL
);
GO

CREATE CLUSTERED COLUMNSTORE INDEX cci_Simple
    ON dbo.SimpleTable;
GO

B. 将聚集索引转换为具有相同名称的聚集列存储索引

此示例创建具有聚集索引的表,然后演示了将聚集索引转换为聚集列存储索引的语法。 创建聚集列存储索引会将整个表的存储从行存储更改为列存储。

CREATE TABLE dbo.SimpleTable2
(
    ProductKey INT NOT NULL,
    OrderDateKey INT NOT NULL,
    DueDateKey INT NOT NULL,
    ShipDateKey INT NOT NULL
);
GO

CREATE CLUSTERED INDEX cl_simple
    ON dbo.SimpleTable2(ProductKey);
GO

CREATE CLUSTERED COLUMNSTORE INDEX cl_simple
    ON dbo.SimpleTable2 WITH (DROP_EXISTING = ON);
GO

C. 将行存储表转换为列存储索引时处理非聚集索引

此示例演示如何在将行存储表转换为列存储索引时处理非聚集索引。 从 SQL Server 2016(13.x 开始),无需执行特殊作。 SQL Server 会自动定义和重新生成新的聚集列存储索引上的非聚集索引。

如果要删除非聚集索引,请先使用 DROP INDEX 语句,然后再创建列存储索引。 DROP EXISTING 选项仅删除正在转换的聚集索引。 它不会删除非聚集索引。

在 SQL Server 2012(11.x)和 SQL Server 2014(12.x)中,不能对列存储索引创建非聚集索引。

--Create the table for use with this example.
CREATE TABLE dbo.SimpleTable
(
    ProductKey INT NOT NULL,
    OrderDateKey INT NOT NULL,
    DueDateKey INT NOT NULL,
    ShipDateKey INT NOT NULL
);
GO

--Create two nonclustered indexes for use with this example
CREATE INDEX nc1_simple ON dbo.SimpleTable(OrderDateKey);
CREATE INDEX nc2_simple ON dbo.SimpleTable(DueDateKey);
GO

仅对于 SQL Server 2012 (11.x) 和 SQL Server 2014 (12.x),必须删除非聚集索引才能创建列存储索引。

DROP INDEX dbo.SimpleTable.nc1_simple;
DROP INDEX dbo.SimpleTable.nc2_simple;

--Convert the rowstore table to a columnstore index.
CREATE CLUSTERED COLUMNSTORE INDEX cci_simple
    ON dbo.SimpleTable;
GO

D. 将大型事实数据表从行存储转换为列存储

此示例说明如何将大型事实数据表从行存储表转换为列存储表。

  1. 创建一个小表,以在此示例中使用。

    --Create a rowstore table with a clustered index and a nonclustered index.
    CREATE TABLE dbo.MyFactTable
    (
        ProductKey INT NOT NULL,
        OrderDateKey INT NOT NULL,
        DueDateKey INT NOT NULL,
        ShipDateKey INT NOT NULL INDEX IDX_CL_MyFactTable CLUSTERED (ProductKey)
    );
    
    --Add a nonclustered index.
    CREATE INDEX my_index
        ON dbo.MyFactTable(ProductKey, OrderDateKey);
    
  2. 从行存储表中删除所有非聚集索引。 你可能想要 编写索引的脚本,以便稍后重新创建索引

    --Drop all nonclustered indexes
    DROP INDEX my_index
        ON dbo.MyFactTable;
    
  3. 将行存储表转换为具有聚集列存储索引的列存储表。

    首先,查找现有聚集行存储索引的名称。 在步骤 1 中,我们将索引的名称设置为 IDX_CL_MyFactTable。 如果未指定索引名称,则会为其指定自动生成的唯一索引名称。 可以使用以下示例查询检索自动生成的名称:

    SELECT i.object_id,
           i.name,
           t.object_id,
           t.name
    FROM sys.indexes AS i
         INNER JOIN sys.tables AS t
             ON i.object_id = t.object_id
    WHERE i.type_desc = 'CLUSTERED'
          AND t.name = 'MyFactTable';
    

    选项 1:删除现有聚集索引 IDX_CL_MyFactTable,并转换为 MyFactTable 列存储。 更改新的聚集列存储索引的名称。

    --Drop the clustered rowstore index.
    DROP INDEX [IDX_CL_MyFactTable]
        ON dbo.MyFactTable;
    GO
    
    --Create a new clustered columnstore index with the name MyCCI.
    CREATE CLUSTERED COLUMNSTORE INDEX IDX_CCL_MyFactTable
        ON dbo.MyFactTable;
    GO
    

    选项 2:转换为列存储,并重复使用现有的行存储聚集索引名称。

    --Create the clustered columnstore index,
    --replacing the existing rowstore clustered index of the same name
    CREATE CLUSTERED COLUMNSTORE INDEX [IDX_CL_MyFactTable]
        ON dbo.MyFactTable WITH (DROP_EXISTING = ON);
    

E. 将列存储表转换为具有聚集索引的行存储表

若要将列存储表转换为具有聚集索引的行存储表,请使用具有DROP_EXISTING选项的 CREATE INDEX 语句。

CREATE CLUSTERED INDEX [IDX_CL_MyFactTable]
    ON dbo.[MyFactTable](ProductKey) WITH (DROP_EXISTING = ON);

F. 将列存储表转换为行存储堆

若要将列存储表转换为行存储堆,请删除聚集列存储索引。 通常不建议这样做,但有些用途可能较窄。 有关堆的详细信息,请参阅 堆(没有聚集索引的表)。

DROP INDEX [IDX_CL_MyFactTable]
    ON dbo.[MyFactTable];

G. 通过重新组织列存储索引进行碎片整理

有两种方法可以维护聚集列存储索引。 从 SQL Server 2016(13.x)开始,请使用 ALTER INDEX...REORGANIZE 而不是 REBUILD。 有关详细信息,请参阅 列存储索引行组。 在早期版本的 SQL Server 中,可以将 CREATE CLUSTERED COLUMNSTORE INDEX 与 DROP_EXISTING=ON 或 ALTER INDEX 和 REBUILD 选项配合使用。 这两种方法都取得了相同的结果。

首先确定聚集列存储索引名称。MyFactTable

SELECT i.object_id,
       i.name,
       t.object_id,
       t.name
FROM sys.indexes AS i
     INNER JOIN sys.tables AS t
         ON i.object_id = t.object_id
WHERE i.type_desc = 'CLUSTERED COLUMNSTORE'
      AND t.name = 'MyFactTable';

通过对列存储索引执行 REORGANIZE 来删除碎片。

--Rebuild the entire index by using ALTER INDEX and the REBUILD option.
ALTER INDEX IDX_CL_MyFactTable
    ON dbo.[MyFactTable] REORGANIZE;

非聚集列存储索引的示例

A. 在行存储表上创建列存储索引作为辅助索引

此示例在行存储表上创建非聚集列存储索引。 在这种情况下,只能创建一个列存储索引。 列存储索引需要额外的存储,因为它包含行存储表中数据的副本。 此示例创建一个简单的表和一个行存储聚集索引,然后演示了创建非聚集列存储索引的语法。

CREATE TABLE dbo.SimpleTable
(
    ProductKey INT NOT NULL,
    OrderDateKey INT NOT NULL,
    DueDateKey INT NOT NULL,
    ShipDateKey INT NOT NULL
);
GO

CREATE CLUSTERED INDEX cl_simple
    ON dbo.SimpleTable(ProductKey);
GO

CREATE NONCLUSTERED COLUMNSTORE INDEX csindx_simple
    ON dbo.SimpleTable(OrderDateKey, DueDateKey, ShipDateKey);
GO

B. 使用所有选项创建基本非聚集列存储索引

以下示例演示了在 DEFAULT 文件组上创建非聚集列存储索引的语法,并将最大并行度(MAXDOP)指定为 2。

CREATE NONCLUSTERED COLUMNSTORE INDEX csindx_simple
    ON SimpleTable(OrderDateKey, DueDateKey, ShipDateKey) WITH (DROP_EXISTING = ON, MAXDOP = 2)
    ON "DEFAULT";
GO

C. 使用筛选的谓词创建非聚集列存储索引

以下示例在示例数据库中的 Production.BillOfMaterialsAdventureWorks2025 上创建经过筛选的非聚集列存储索引。 筛选器谓词可以包含不是筛选索引中的键列的列。 此示例中的谓词仅选择非 NULL 行 EndDate

IF EXISTS (SELECT name
           FROM sys.indexes
           WHERE name = N'FIBillOfMaterialsWithEndDate'
                 AND object_id = OBJECT_ID(N'Production.BillOfMaterials'))
    DROP INDEX FIBillOfMaterialsWithEndDate
        ON Production.BillOfMaterials;
GO

CREATE NONCLUSTERED COLUMNSTORE INDEX "FIBillOfMaterialsWithEndDate"
    ON Production.BillOfMaterials(ComponentID, StartDate)
    WHERE EndDate IS NOT NULL;

D. 更改非聚集列存储索引中的数据

适用于:SQL Server 2012 (11.x) 到 SQL Server 2014 (12.x)。

在 SQL Server 2014(12.x)和早期版本中,在表上创建非聚集列存储索引后,不能直接修改该表中的数据。 具有 INSERT、UPDATE、DELETE 或 MERGE 的查询失败,并返回错误消息。 下面是可用于添加或修改表中数据的选项:

  • 禁用或删除列存储索引。 然后,可以更新表中的数据。 如果禁用列存储索引,可以在完成数据更新时重新生成列存储索引。 例如:

    ALTER INDEX mycolumnstoreindex
        ON dbo.mytable DISABLE;
    
    -- update the data in mytable as necessary
    ALTER INDEX mycolumnstoreindex
        ON dbo.mytable REBUILD;
    
  • 将数据加载到没有列存储索引的临时表中。 在暂存表上生成列存储索引。 将暂存表移动到主表的空分区。

  • 将具有列存储索引的表中的分区切换到一个空的暂存表。 如果暂存表上有列存储索引,请禁用列存储索引。 进行更新。 创建(或重新创建)列存储索引。 将临时表切换回主表的(现在为空)分区。

示例:Azure Synapse Analytics、Analytics 平台系统(PDW)

A. 将聚集索引更改为聚集列存储索引

通过将 CREATE CLUSTERED COLUMNSTORE INDEX 语句与 DROP_EXISTING = ON 配合使用,可以:

  • 将聚集索引更改为聚集列存储索引。

  • 重新生成聚集列存储索引。

此示例将 xDimProduct 表创建为具有聚集索引的行存储表。 然后,该示例使用 CREATE CLUSTERED COLUMNSTORE INDEX 将表从行存储表更改为列存储表。

-- Uses AdventureWorks
IF EXISTS (SELECT name
           FROM sys.tables
           WHERE name = N'xDimProduct'
                 AND object_id = OBJECT_ID(N'xDimProduct'))
    DROP TABLE xDimProduct;

--Create a distributed table with a clustered index.
CREATE TABLE xDimProduct
(
    ProductKey,
    ProductAlternateKey,
    ProductSubcategoryKey
)
WITH (DISTRIBUTION = HASH(ProductKey), CLUSTERED INDEX(ProductKey)) AS
SELECT ProductKey,
       ProductAlternateKey,
       ProductSubcategoryKey
FROM DimProduct;

使用 sys.indexes 查找系统元数据中为新表自动创建的聚集索引的名称。 例如:

SELECT i.object_id,
       i.name,
       t.object_id,
       t.name,
       i.type_desc
FROM sys.indexes AS i
     INNER JOIN sys.tables AS t
         ON i.object_id = t.object_id
WHERE i.type_desc = 'CLUSTERED'
      AND t.name = 'xdimProduct';

现在,可以选择:

  1. 删除具有自动创建名称的现有聚集列存储索引,然后使用用户定义的名称创建新的聚集列存储索引。
  2. 删除现有索引并将其替换为聚集列存储索引,保留相同的系统生成名称,例如 ClusteredIndex_1bd8af8797f7453182903cc68df48541

例如:

--1. DROP the existing clustered columnstore index with an automatically-created name, for example:
DROP INDEX ClusteredIndex_1bd8af8797f7453182903cc68df48541
    ON xdimProduct;
GO

CREATE CLUSTERED COLUMNSTORE INDEX [<new_index_name>]
    ON xdimProduct;
GO

--Or,
--2. Change the existing clustered index to a clustered columnstore index with the same name.
CREATE CLUSTERED COLUMNSTORE INDEX [ClusteredIndex_1bd8af8797f7453182903cc68df48541]
    ON xdimProduct WITH (DROP_EXISTING = ON);
GO

B. 重新生成聚集列存储索引

在前面的示例中,此示例使用 CREATE CLUSTERED COLUMNSTORE INDEX 重新生成现有的聚集列存储索引,称为 cci_xDimProduct

--Rebuild the existing clustered columnstore index.
CREATE CLUSTERED COLUMNSTORE INDEX cci_xDimProduct
    ON xdimProduct WITH (DROP_EXISTING = ON);

C. 更改聚集列存储索引的名称

若要更改聚集列存储索引的名称,请删除现有的聚集列存储索引,然后使用新名称重新创建索引。

建议将此作限制为小型或空表。 删除大型聚集列存储索引并使用不同的名称重新生成需要很长时间。

此示例引用 cci_xDimProduct 上一示例中的聚集列存储索引。 此示例删除 cci_xDimProduct 聚集列存储索引,然后使用名称 mycci_xDimProduct重新创建聚集列存储索引。

--For illustration purposes, drop the clustered columnstore index.
--The table continues to be distributed, but changes to a heap.
DROP INDEX cci_xdimProduct
    ON xDimProduct;

--Create a clustered index with a new name, mycci_xDimProduct.
CREATE CLUSTERED COLUMNSTORE INDEX mycci_xDimProduct
    ON xdimProduct WITH (DROP_EXISTING = OFF);

D. 将列存储表转换为具有聚集索引的行存储表

你可能希望删除聚集列存储索引并创建聚集索引。 删除聚集列存储索引时,表将更改为行存储格式。 此示例将列存储表转换为具有相同名称的聚集索引的行存储表。 不会丢失任何数据。 所有数据都转到行存储表,列出的列将成为聚集索引中的键列。

--Drop the clustered columnstore index and create a clustered rowstore index.
--All of the columns are stored in the rowstore clustered index.
--The columns listed are the included columns in the index.
CREATE CLUSTERED INDEX cci_xDimProduct
    ON xdimProduct(ProductKey, ProductAlternateKey, ProductSubcategoryKey, WeightUnitMeasureCode) WITH (DROP_EXISTING = ON);

E. 将列存储表转换回行存储堆

使用 DROP INDEX 删除聚集列存储索引,并将表转换为行存储堆。 此示例将 cci_xDimProduct 表转换为行存储堆。 该表继续分布,但存储为堆。

--Drop the clustered columnstore index. The table continues to be distributed, but changes to a heap.
DROP INDEX cci_xdimProduct
    ON xdimProduct;

F. 在没有索引的表上创建有序聚集列存储索引

默认情况下,无序列存储索引涵盖所有列,而无需指定列列表。 有序列存储索引允许指定列的顺序。 该列表不需要包括所有列。

有关详细信息,请参阅 使用有序列存储索引进行性能优化

CREATE CLUSTERED COLUMNSTORE INDEX cci
    ON Sales.OrderLines ORDER(SHIPDATE);

G. 将聚集列存储索引转换为有序聚集列存储索引

CREATE CLUSTERED COLUMNSTORE INDEX cci
    ON Sales.OrderLines ORDER(SHIPDATE) WITH (DROP_EXISTING = ON);

H. 将列添加到有序聚集列存储索引的排序

可以为列存储索引中的列指定顺序。 原始有序聚集列存储索引仅在列上 SHIPDATE 排序。 以下示例将 PRODUCTKEY 列添加到排序中。 关于有序列存储索引的可用性,请参阅 列存储索引:概述

CREATE CLUSTERED COLUMNSTORE INDEX cci
    ON Sales.OrderLines ORDER(SHIPDATE, PRODUCTKEY) WITH (DROP_EXISTING = ON);

I. 更改有序列的序号

原始排序的聚集列存储索引已排序,SHIPDATEPRODUCTKEY 以下示例将排序更改为 PRODUCTKEYSHIPDATE 关于有序列存储索引的可用性,请参阅 列存储索引:概述

CREATE CLUSTERED COLUMNSTORE INDEX cci
    ON Sales.OrderLines ORDER(PRODUCTKEY, SHIPDATE) WITH (DROP_EXISTING = ON);

J. 创建有序聚集列存储索引

可以使用排序键创建聚集列存储索引。 创建有序聚集列存储索引时,应应用查询提示 MAXDOP = 1 ,以获得最大排序质量和最短持续时间。 关于有序列存储索引的可用性,请参阅 列存储索引:概述

CREATE CLUSTERED COLUMNSTORE INDEX [OrderedCCI]
    ON dbo.FactResellerSalesPartCategoryFull ORDER(EnglishProductSubcategoryName, EnglishProductName) WITH (MAXDOP = 1, DROP_EXISTING = ON);