本文讨论在 Microsoft SQL Server 2014 中查询聚集列存储索引期间出现的问题。 本文提供了此问题 的解决方案 。
摘要
在 Microsoft SQL Server 2014 中使用扫描聚集列存储索引的查询时,你可能会在较少条件下接收部分查询结果。当运行以下操作时,会出现此问题。
步骤 1
Transact-sql 语句 [插入或大容量插入] 将数据插入具有聚集列存储索引的表中。 在执行此操作的过程中,以下条件适用:
-
当 Transact-sql 语句达到 "分段" 阈值时,它将关闭具有 "分段 S1" 的 "分段 R1"。
-
段 S1 指向本地词典 D1。
-
该语句将继续向新的行数 R2 插入行。
-
当出现 "当带的 R1 已关闭" 时,还不必关闭局部字典 D1。 如果字典 D1 仍具有可用空间,则可以将其保留为打开状态,并对新的新组 R2 重用它。
步骤 2
如果 Transact-sql 语句在关闭新的 "文件" (R2)之前异常终止或被取消,请遵循以下条件:
-
列存储元数据更改发生在 subtransactions 中,该更改独立于外部事务进行提交。
-
此时,在系统表中,在 "正在建设" 或 "未隐藏" 状态下,分段 S1 将保留在系统表中,而段 S1 将引用字典 D1。
-
在系统表中没有为字典 D1 创建行。 这是因为 Transact-sql 语句从来没有机会关闭现有行。 因此,现有行仍然存在。
步骤3
在典型情况下,如果在 Transact-sql 语句结束后启动元组移动器后台任务,后台任务将删除不可见的分段 R1 和分段 S1。 如果新的 Transact-sql 语句现在已启动,并创建了包含新的带有需要新的本地字典的新段 S3 的带级 R3,则不能重用字典 D1 的内部 ID。 这是因为列存储的内存中状态会跟踪所使用的字典 Id。 因此,segment S3 将引用新的字典 D2。注意 此步骤中的条件是常见条件。 因此,不会出现损坏。
步骤4
如果 SQL Server 在元组移动器任务生效(并按步骤3中所述执行)之前丢失了字典 D1 的内存中状态,则会出现本文所述的问题。注意
-
出现此事件的原因如下:
-
SQL Server 体验内存重载,并且字典 D1 的内存中的内容从内存中退出。
-
SQL Server 实例已重启。
-
包含聚集列存储索引的数据库脱机,然后重新联机。
-
-
任何一种事件发生后,SQL Server 重新加载内存中的结构,不存在字典 D1 及其内部 ID 的记录。 这是因为当 Transact-sql 语句结束或 conceled 时,字典 D1 未保留在系统表中。
-
如果此时启动元组移动器后台任务,则不会出现错误,因为步骤3中所述的条件适用。
-
如果在元组移动器后台任务开始之前创建新的新组 R3 (按上一个项目符号项),SQL Server 会将相同的内部 ID 分配给新的字典 D1,并且它在组的 R3 中引用第 S3 段的字典 D1。
-
当元组移动器后台任务在上一个操作后启动时,它会将不可见的组内 R1 及其段 S1 与新的字典 D1 一起放置。 出现这种情况的原因是元组移动器认为新字典 D1 和原始字典 D1 是相同的。注意 出现这种情况时,不能查询 "项" 的 "项" 的内容。
解决方案
在 SQL Server 的以下累积更新中首先修复此问题:
Sql server 2014 SP1 的累积更新 1 SP1累积更新8(适用于 sql server 2014 )此问题的修补程序也包含在以下常规分发版本(GDR)更新中:
SQL Server 2014 QFE 的安全更新 此更新包括累积更新8、此重要修补程序以及所需的 MS15 058 安全更新。SQL Server 2014 GDR 的安全更新 此更新包括此重要修补程序和通过 MS15-058 的累积安全修补程序。SQL Server 2014 Service Pack 1 GDR 的 Nonsecurity 更新 此更新仅包含此重要修补程序。
SQL Server 的每个新的累积更新均包含以前的累积更新中包含的所有修补程序和所有安全修补程序。 请参阅 SQL Server 的最新累积更新:
更多信息
错误消息在当前受影响的数据库中,如果在应用此修补程序后运行 DBCC CHECKDB,将收到以下错误消息:
消息5289、级别16、状态1、表 ' t ' 上的第1行列存储索引 "cci" 的一个或多个数据值与字典中的数据值不匹配。 从备份还原数据。
在当前受影响的数据库中,当你在应用此修补程序后运行扫描受影响的表的查询时,将收到以下错误消息:
消息5288、级别16、状态1、行1列存储索引具有一个或多个与字典中的数据值不匹配的数据值。 有关详细信息,请运行 DBCC CHECKDB。
如果收到这些错误,你可以通过批量导出不受影响的列/rowgroups 的数据来保存未损坏的数据,然后在除去或创建聚集列存储索引后重新加载数据。 应启用跟踪标记10207以取消5288错误,并恢复到跳过损坏的 rowgroups 的旧行为。 注意为具有 segment S3 的此分段 R3 生成的错误消息5288和5289。 跟踪标记10207用于提取对不受缺少的字典 D1 影响的分段的 R3。
查询受影响的数据库若要确定包含列存储索引的数据库是否已受此问题影响,请运行以下查询:
select object_name(i.object_id) as table_name, i.name as index_name, p.partition_number, count(distinct s.segment_id) as damaged_rowgroups from sys.indexes i join sys.partitions p on p.object_id = i.object_id and p.index_id = i.index_id join sys.column_store_row_groups g on g.object_id = i.object_id and g.index_id = i.index_id and g.partition_number = p.partition_number join sys.column_store_segments s on s.partition_id = p.partition_id and s.segment_id = g.row_group_id where i.type in (5, 6) and s.secondary_dictionary_id <> -1 and g.state_description = 'COMPRESSED' and s.secondary_dictionary_id not in ( select dictionary_id from sys.column_store_dictionaries d where d.hobt_id = p.hobt_id and d.column_id = s.column_id ) group by object_name(i.object_id), i.name, p.partition_number
注意
-
你必须对在运行 SQL Server 的服务器上包含列存储索引的每个数据库运行此查询。 空结果集表示数据库不受影响。
-
如果没有活动可创建新的 rowgroups 或更改现有 rowgroups 的状态,则在一段时间内执行此查询。 例如,以下活动可以修改 rowgroups 的状态: index build、index 重组、bulk insert、元组移动器压缩增量存储。 在执行查询之前,可以使用跟踪标记634禁用后台元组移动器任务。 使用此命令可禁用后台任务: DBCC TRACEON (634,-1)。 查询执行完毕后,请记住使用以下命令重新启用后台任务: DBCC TRACEOFF (634,-1)。此外,请确保在运行此查询时,没有大容量插入/BCP/SELECT INTO 命令将数据插入到使用列存储索引的表中。建议使用这些步骤来阻止查询返回假正值。
状态
Microsoft 已经确认这是一个列于“适用范围”部分的 Microsoft 产品问题。