この記事では、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ディクショナリ D1 のメモリ内状態が失われると (手順 3 で説明されているように実行)、この記事で説明されている問題が発生します。
メモ
このイベントは、次のいずれかの理由で発生します。
- SQL Serverメモリ オーバーロードが発生し、ディクショナリ D1 のメモリ内コンテンツがメモリから削除されます。
- SQL Serverのインスタンスが再起動されます。
- クラスター化列ストア インデックスを含むデータベースはオフラインになり、オンラインに戻ります。
これらのイベントのいずれかが発生し、SQL Serverメモリ内の構造体を再読み込みした後、ディクショナリ D1 とその内部 ID が存在したレコードはありません。 これは、Transact-SQL ステートメントが終了または譲歩されたときに、ディクショナリ D1 がシステム テーブルに保持されなかったためです。
この時点でタプルムーバーのバックグラウンド タスクが開始された場合、手順 3 で説明されている条件が適用されるため、エラーは発生しません。
タプルムーバーのバックグラウンド タスクが開始される前に新しい行グループ R3 が作成された場合 (前の箇条書き項目ごとに)、SQL Serverは同じ内部 ID を新しいディクショナリ D1 に割り当て、行グループ R3 のセグメント S3 のディクショナリ D1 を参照します。
前のアクションの後にタプルムーバーのバックグラウンド タスクが開始されると、非表示の行グループ R1 とそのセグメント S1 と新しいディクショナリ D1 がドロップされます。 これは、タプルムーバーが、S1 が参照する新しいディクショナリ D1 と元のディクショナリ 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 を実行してください。
これらのエラーが発生した場合は、影響を受けない列/行グループのデータを一括エクスポートし、クラスター化列ストア インデックスを削除または作成した後にデータを再読み込みすることで、データを保存できます。 トレース フラグ 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 製品の問題であることを確認しました。