web-dev-qa-db-ja.com

行を削除すると、非クラスター化インデックスがより多くの領域を使用するのはなぜですか?

75億行と5つのインデックスを持つ大きなテーブルがあります。およそ1000万行を削除すると、非クラスター化インデックスが格納されているページの数を増やしているように見えます。

dm_db_partition_statsに対するクエリを書いて、ページ内の(後-前)の違いを報告します。

dm_db_partition_stats deltas

インデックス1はクラスター化インデックス、インデックス2は主キーです。その他は非クラスター化および非固有です。

それらの非クラスター化インデックスでページが増加するのはなぜですか?
最低でも同じ数字が続くと予想していました。
パフォーマンスカウンターが削除中のページ分割の増加を報告しているのを見ています。

削除するときに、ゴーストレコードを別のページに移動する必要がありますか?これは「一意名」と関係がありますか?

現在RCSIの展開を進めていますが、現在RCSIはオフになっています。

これは、可用性グループのプライマリノードです。スナップショットがなんとなくセカンダリで使用されていることを知っています。それが関連性があれば私は驚かれます。詳細については、これについて(dbccページの出力を見て)掘り下げるつもりです。これは誰かが似たようなものを見たことを望んでいる。

23
Michael J Swart

私を非常に楽しませる1つの可能なシナリオ:

  • 行が最初に書き込まれたのは、データベースでコミットされた読み取りスナップショット(RCSI)、スナップショット分離(SI)、または可用性グループ(AG)が有効になっていない場合です。
  • RCSIまたはSIが有効になっているか、データベースが可用性グループに追加されました
  • 削除中に、RCSI/SI/AG読み取りをサポートするために、削除された行に14バイトのタイムスタンプが追加されました

このサーバーはAGのプライマリであるため、セカンダリと同様に影響を受けます。バージョン情報はプライマリに追加されます-データページはプライマリとセカンダリの両方でまったく同じです。セカンダリはバージョンストアを利用して、AGによって行が更新されている間に読み取りを行いますが、セカンダリは独自のバージョンのタイムスタンプをページに書き込みません。それらは、プライマリーの作業からバージョンを継承するだけです。

成長を実証するために、スタックオーバーフローデータベースのエクスポート(RCSIが有効になっていない)を使用して、Postsテーブルに一連のインデックスを作成しました。 sp_BlitzIndex @Mode = 2でインデックスのサイズを確認しました(スプレッドシートにコピー/貼り付け、情報の密度を最大にするために少しクリーンアップしました):

sp_BlitzIndex before

次に、行の約半分を削除しました。

BEGIN TRAN;
DELETE dbo.Posts WHERE Id % 2 = 0;
GO

面白いことに、削除が行われている間、データファイルもタイムスタンプに対応できるように拡張されていました。 SSMSのディスク使用量レポートは、成長イベントを示しています。これは、説明するための上部です:

Growth events

(削除するとデータベースが大きくなるデモがお奨めです。)削除の実行中に、sp_BlitzIndexを再度実行しました。クラスタ化インデックスの行は少なくなっていますが、そのサイズはすでに約1.5GB増加しています。 AcceptedAnswerIdの非クラスター化インデックスは劇的に成長しました。これらは、ほとんどがnullである小さな値のインデックスであるため、インデックスサイズがほぼ2倍になりました。

sp_BlitzIndex during deletion

削除が完了するのを待つ必要はないので、デモを中止します。重要な点:RCSI、SI、またはAGが有効になる前に実装されたテーブルで大きな削除を行うと、インデックス(クラスター化を含む)が実際に大きくなり、バージョンストアのタイムスタンプの追加に対応できます。

29
Brent Ozar