KB3067257 - 修复:SQL Server 2014 中聚集列存储索引的查询出现部分结果

应用对象
SQL Server 2014 Developer - duplicate (do not use) SQL Server 2014 Enterprise - duplicate (do not use) SQL Server 2014 Standard - duplicate (do not use)

本文讨论在查询 Microsoft SQL Server 2014 中的聚集列存储索引时发生的问题。 本文提供了此问题 的解决方法 。

摘要

当您使用查询扫描 Microsoft SQL Server 2014 中的聚集列存储索引时,在极少数情况下,您可能会收到部分查询结果。

运行以下操作时会出现此问题。

步骤 1

Transact-SQL 语句 [INSERT 或 BULK-INSERT] 将数据插入到具有聚集列存储索引的表中。 在此操作期间,以下情况适用:

  • 当 Transact-SQL 语句达到行组阈值时,它将关闭具有段 S1 的行组 R1。
  • 段 S1 指向本地字典 D1。
  • 语句继续将行插入到新行组 R2。
  • 关闭行组 R1 后,本地字典 D1 也不必关闭。 如果字典 D1 仍有可用空间,则可以保持打开状态,并将其重复用于新行组 R2。

步骤 2

如果 Transact-SQL 语句在关闭新行组 R2 之前异常结束或取消,则适用以下情况:

  • 列存储元数据更改发生在独立于外部事务提交的子事务中。
  • 此时,行组 R1 以“正在构造”或 INVISIBLE 状态保留在系统表中,并且段 S1 引用字典 D1。
  • 系统表中没有为字典 D1 创建行。 这是因为 Transact-SQL 语句永远没有机会关闭现有行。 因此,现有行将保留。

步骤 3

在典型情况下,如果元组移动器后台任务在 Transact-SQL 语句结束后启动,则后台任务将删除不可见的行组 R1 和段 S1。 如果现在启动新的 Transact-SQL 语句,并创建具有需要新本地字典的新段 S3 的行组 R3,则无法重复使用字典 D1 的内部 ID。 这是因为列存储的内存中状态会跟踪所使用的字典 ID。 因此,段 S3 将引用新字典 D2。

注意 此步骤中的条件是常见条件。 因此不会发生损坏。

步骤 4

如果SQL Server在元组移动器任务生效 (并按照步骤 3) 中所述执行操作之前丢失了字典 D1 的内存中状态,则会出现本文中描述的问题。

便笺

  • 此事件是由以下任何原因导致的:

    • SQL Server 遇到内存过载,字典 D1 的内存中内容会从内存中逐出。
    • 重启 SQL Server 的实例。
    • 包含聚集列存储索引的数据库脱机然后重新联机。
  • 在发生以上任一事件且 SQL Server 重新加载内存中结构后,将不会有字典 D1 及其内部 ID 的记录。 这是因为在 Transact-SQL 语句结束或加速时,字典 D1 未保留在系统表中。

  • 如果元组移动器后台任务此时启动,则不会发生错误,因为步骤 3 中描述的条件适用。

  • 如果在元组移动器后台任务开始之前创建了新行组 R3 (按照上一个项目符号项) ,SQL Server 会为新词典 D1 分配相同的内部 ID,并引用行组 R3 中段 S3 的字典 D1。

  • 当元组移动器后台任务在上一个操作后启动时,它会删除不可见的行组 R1 及其段 S1 以及新的字典 D1。 发生这种情况是因为元组移动器认为新字典 D1 和 S1 引用的原始字典 D1 相同。

    注意 出现此情况时,无法查询行组 R3 的内容。

解决方法

此问题已首先在 SQL Server 的以下累积更新中修复:

SQL Server 2014 SP1 累积更新 1
        
         SQL Server 2014 累积更新 8
此问题的修补程序也包含在以下常规分发版本 (GDR) 更新中:

SQL Server 2014 QFE 的安全更新  
此更新包括累积更新 8、此重要修补程序以及所需的 MS15-058 安全更新。

SQL Server 2014 GDR 安全更新  
此更新包括此重要修补程序以及通过 MS15-058 累积的安全修补程序。

SQL Server 2014 Service Pack 1 GDR 非安全更新  
此更新仅包括此重要修补程序。

关于 SQL Server 的累积更新

SQL Server 的每个新累积更新都包含上一个累积更新中包含的所有修补程序和所有安全修补程序。 查看 SQL Server 的最新累积更新:

      

详细信息

错误消息 在当前受影响的数据库中,如果在应用此修补程序后运行 DBCC CHECKDB,将收到以下错误消息:

注意

消息 5289,级别 16,状态 1,行 1
表“t”上的聚集列存储索引“cci”有一个或多个数据值与字典中的数据值不匹配。 从备份还原数据。

在当前受影响的数据库中,当你在应用此修补程序后运行扫描受影响表的查询时,会收到以下错误消息:

注意

消息 5288,级别 16,状态 1,行 1
列存储索引具有一个或多个与字典中的数据值不匹配的数据值。 有关详细信息,请运行 DBCC CHECKDB。

如果收到这些错误,可以通过批量导出不受影响的列/行组的数据,然后在删除或创建聚集列存储索引后重新加载数据来保存未损坏的数据。 应启用跟踪标志 10207 以禁止显示 5288 错误,并还原到跳过损坏行组的旧行为。

注意:将为此具有段 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 的服务器上包含列存储索引的每个数据库运行此查询。 空的结果集表示数据库不受影响。

  • 在没有将创建新行组或更改现有行组状态的活动的时间段内执行此查询。 例如,以下活动可以修改行组的状态:索引生成、索引重组、批量插入、元组移动器压缩增量存储。

    在执行查询之前,可以使用跟踪标志 634 禁用后台元组移动器任务。 使用此命令禁用后台任务: DBCC TRACEON ( 634 , -1 ) 。 查询执行完毕后,请记住使用以下命令重新启用后台任务: DBCC TRACEOFF ( 634 , -1 ) 。

    还要确保在运行此查询时,没有 BULK INSERT/BCP/SELECT-INTO 命令将数据插入到使用列存储索引的表中。

    建议使用这些步骤来防止查询返回误报。

状态

Microsoft 已确认在 "适用于" 部分中所列的 Microsoft 产品中存在问题。