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 は "作成中" または非表示の状態でシステム テーブルに残り、セグメント S1 はディクショナリ D1 を参照します。
  • システム テーブルにディクショナリ D1 の行が作成されていません。 これは、Transact-SQL ステートメントに既存の行を閉じる機会がないためです。 したがって、既存の行は保持されます。

手順 3

一般的な状況では、Transact-SQL ステートメントが終了した後にタプル ムーバー バックグラウンド タスクが開始すると、バックグラウンド タスクは非表示の行グループ R1 とセグメント S1 を削除します。 新しい Transact-SQL ステートメントが現在開始され、新しいローカル辞書を必要とする新しいセグメント S3 を持つ行グループ R3 が作成された場合、辞書 D1 の内部 ID を再利用することはできません。 これは、列ストアのメモリ内の状態により、使用される辞書 ID が追跡されるためです。 したがって、セグメント S3 は新しい辞書 D2 を参照します。

注: この手順の条件は一般的な条件です。 したがって、破損は発生しません。

手順 4

タプル ムーバー タスクが有効になる前に (および手順 3 で説明したとおりに実行される) 前に、SQL Server がディクショナリ 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' に、ディクショナリ内のデータ値と一致しない 1 つ以上のデータ値が含まれています。 バックアップからデータを復元します。

現在影響を受けているデータベースで、この修正プログラムの適用後に影響を受けるテーブルをスキャンするクエリを実行すると、次のエラー メッセージが表示されます。

注

メッセージ 5288、レベル 16、状態 1、行 1
列ストア インデックスに、辞書内のデータ値と一致しない 1 つ以上のデータ値が含まれています。 詳細については、DBCC CHECKDB を実行してください。

これらのエラーが発生した場合は、影響を受けない列/行グループのデータを一括エクスポートし、クラスター化列ストア インデックスを削除または作成した後にデータを再読み込みすることで、破損していないデータを保存できます。 5288 エラーを抑制し、破損した行グループをスキップする以前の動作に戻すには、トレース フラグ 10207 を有効にする必要があります。

注: セグメント 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 製品の問題であることを確認しました。