web-dev-qa-db-ja.com

クエリオプティマイザーは断片化されたインデックスを無視しますか?

シナリオ:インデックスのあるOLTPテーブルがあります。多くの挿入、更新、削除、およびインデックスフラグメントが1日以内に頻繁に表示されます。インデックス作成の1日の間に、オプティマイザーは2日目または3日目のインデックスを使用しますが、オプティマイザーはそれを完全にスキップします。これはexactly同じクエリ用です。

頭の中で質問:インデックスはこれらのプランを最適化するために作成されているので、なぜ一部のクエリプランはインデックスをスキップするのですか?

この投稿への質問:オプティマイザは、10億のレコードがあり、インデックスが作成され、その後2時間後にすべての10億のレコードが削除され、5億の新しいレコードがあるシナリオなど、非常に断片化されたインデックスをスキップできますか?

このテーブルにインデックスを追加しても、テーブルの性質(データがすぐに入力され、データがすぐに出力される)のためにまったく役に立たないと考え始めていますが、オプティマイザが1日1日かかる理由を理解したいだけです。計画でインデックスを使用しますが、2日目は使用しません。

6
user541852587

私の知る限り、オプティマイザはインデックスの断片化を認識していません。断片化されたインデックスをスキャンするプランを選択する場合、これは問題になる可能性があります。

ただし、オプティマイザは割り当てられたデータサイズを認識しています。インデックスページに多くの空き領域がある場合(おそらく内部の断片化が原因)、これによりインデックスが使用される可能性が低くなります。 50%の空き領域は、IOの2倍の量をスキャンすることを意味します。ただし、ランダムアクセスの場合、それほど重要ではないはずです。

ただし、これは大きな影響ではありません。 might何が表示されているかを説明します。

この小さな影響がクエリプランを反転させてインデックスを使用しない場合、クエリオプティマイザーの観点から見ると、インデックスが最初から非常に優れていることはありません。これは、改善できるヒントになるかもしれません。

また、オプティマイザは、バッファプールにキャッシュされるインデックスの量を推測しているようです。 XML実行プランには、それへの参照がいくつかあります。私はそれについて詳しく知りません。

このテーブルにインデックスを追加してもまったく役に立たないと思い始めています

私はそんなに遠くないでしょう。多分必要なのは、正しい場所での再構築またはドロップDML作成シーケンスだけですか?または、これはクエリチューニングの問題にすぎない可能性があります(実際の実行プランを含めて新しい質問をしてください)。

6
usr

最初に頭に浮かぶのは、古くなった統計であり、インデックス自体の断片化ではありません。

インデックスが(再)構築された直後は、インデックスに関連付けられた統計が正確です。ヒストグラムの範囲はすべての値をカバーします。テーブルのデータが変化しても、統計はすぐには更新されません。正確なしきい値、つまり統計の自動更新が実行される前に削除または挿入する必要がある行数を覚えていません。

私たちのシステムでも同様の動作が見られました。私たちのシステムの単純化されたワークフローは次のとおりです。

N日間のデータを含む約1億行のテーブルがあります。日中に新しい行が追加され、インデックス付きの列のdatetime値が増加します。データは1日を通してバッチで追加されます(通常、一度に1K〜10K)。午前0時に、保守手順はN日より古いすべての値を削除し、インデックスを再構築します。

また、別の手順では、日ごとに10分ごとにデータを要約し、要約を更新します。要約は、詳細度の低いデータが含まれているものの、長期間保持されます。

要約手順のパフォーマンスは午前中には良好でしたが、その日の後半に悪化していることに気付きました。実行計画を確認したところ、違うことがわかりました。朝と夕方に実行される同じクエリには、異なる計画がありました(私はOPTION(RECOMPILE)を使用しました)。

そこで、組み込みのしきい値に依存することなく、関連する統計を1日中更新する手順を追加しました。

CREATE PROCEDURE [dbo].[RebuildStatisticsOnMyTable]
WITH EXECUTE AS OWNER
AS
BEGIN
    SET NOCOUNT ON;
    BEGIN TRY
        UPDATE STATISTICS [dbo].[MyTableStats] ([IX_ImportantIndex], [IX_AnotherIndex]);
    END TRY
    BEGIN CATCH
        -- handle errors
        ...
    END CATCH;
END

1日を通してこのような定期的な統計の更新により、要約手順のパフォーマンスは良好で安定しています。私は少し実験する必要があり、統計を更新するための適切な期間を見つけました。

これはSQL Server 2008上にあり、私の知る限り2012年にも適用されます。 2014には異なる改善されたカーディナリティエスティメーターがあり、(私が理解している限り)統計ヒストグラムの範囲を超えるタイムスタンプが増加する行が追加された場合に、統計を効果的に推定し、適切な予測を生成できます。これの詳細な説明を見た場所を今は覚えていません。おそらく、Paul WhiteまたはAaron Bertrandによるブログ投稿でした。したがって、2014年にアップグレードする場合、これらの統計情報を強制的に1日中更新する必要はないでしょう。

3