IndexOptimize後のクエリと更新が非常に遅い


12

データベースSQL Server 2017 Enterprise CU16 14.0.3076.1

最近、デフォルトのIndex RebuildメンテナンスジョブからOla Hallengrenへの切り替えを試みましたIndexOptimize。デフォルトのインデックス再構築ジョブは問題なく数か月間実行されており、クエリと更新は許容可能な実行時間で機能していました。IndexOptimizeデータベースで実行した後:

EXECUTE dbo.IndexOptimize
@Databases = 'USER_DATABASES',
@FragmentationLow = NULL,
@FragmentationMedium = 'INDEX_REORGANIZE,INDEX_REBUILD_ONLINE,INDEX_REBUILD_OFFLINE',
@FragmentationHigh = 'INDEX_REBUILD_ONLINE,INDEX_REBUILD_OFFLINE',
@FragmentationLevel1 = 5,
@FragmentationLevel2 = 30,
@UpdateStatistics = 'ALL',
@OnlyModifiedStatistics = 'Y'

パフォーマンスが極端に低下しました。IndexOptimize100ミリ秒かかった更新ステートメントは、その後78.000ミリ秒かかり(同じプランを使用)、クエリのパフォーマンスも数桁悪化していました。

これはまだテストデータベースであるため(Oracleから運用システムを移行しています)、バックアップにIndexOptimize戻り、無効にしてすべてを通常に戻しました。

ただし、この極端なパフォーマンスの低下を引き起こす可能性のIndexOptimizeある「通常」Index Rebuildとは何が異なるのかを理解して、本番環境に移行したときにそれを回避できるようにします。何を探すべきかについての提案は大歓迎です。

遅い場合の更新ステートメントの実行計画。すなわち、
IndexOptimizeの実際の実行計画の
(できるだけ早く)

違いを見つけることができませんでした。
高速な場合は同じクエリを計画する
実際の実行計画

回答:


11

2つのメンテナンスアプローチ間で異なるサンプルレートが定義されていると思われます。@StatisticsSampleパラメーターを指定しない限り、Olaのスクリプトはデフォルトのサンプリングを使用すると信じています。

この時点では、これは推測ですが、データベースで次のクエリを実行することにより、統計で現在使用されているサンプリングレートを確認できます。

SELECT  OBJECT_SCHEMA_NAME(st.object_id) + '.' + OBJECT_NAME(st.object_id) AS TableName
    ,   col.name AS ColumnName
    ,   st.name AS StatsName
    ,   sp.last_updated
    ,   sp.rows_sampled
    ,   sp.rows
    ,   (1.0*sp.rows_sampled)/(1.0*sp.rows) AS sample_pct
FROM sys.stats st 
    INNER JOIN sys.stats_columns st_col
        ON st.object_id = st_col.object_id
        AND st.stats_id = st_col.stats_id
    INNER JOIN sys.columns col
        ON st_col.object_id = col.object_id
        AND st_col.column_id = col.column_id
    CROSS APPLY sys.dm_db_stats_properties (st.object_id, st.stats_id) sp
ORDER BY 1, 2

これが1秒(100%など)で発生している場合は、これが問題である可能性があります。@StatisticsSampleこのクエリで返されるパーセンテージのパラメータを含むオラのスクリプトをもう一度試して、問題が解決するかどうかを確認してください。


この理論の追加の裏付けとなる証拠として、実行計画XMLは、低速クエリのサンプリングレートが大きく異なる(2.18233%)ことを示しています。

<StatisticsInfo LastUpdate="2019-09-01T01:07:46.04" ModificationCount="0" 
    SamplingPercent="2.18233" Statistics="[INDX_UPP_4]" Table="[UPPDRAG]" 
    Schema="[SVALA]" Database="[ulek-sva]" />

対高速クエリ(100%):

<StatisticsInfo LastUpdate="2019-08-25T23:01:05.52" ModificationCount="555" 
    SamplingPercent="100" Statistics="[INDX_UPP_4]" Table="[UPPDRAG]" 
    Schema="[SVALA]" Database="[ulek-sva]" />

@JoshDarnell LOL、これはクエリプランでいくつかのサポート統計情報を見つけた2番目の出現で、私は見ることができませんでした。編集してくれてありがとう!
ジョンイスブレナー

ハハ、私はあなただと忘れていた、ジョン 私は😅私はあなたをストーキングしていないよ約束
ジョシュ・ダーネル

@JoshDarnell追加の洞察に感謝します。実行計画には非常に多くの情報があることを忘れないでください。
ジョンイスブレナー

喜んでお手伝いします!そして、ええ、私もいつも見逃しているものがあります(私は統計のことで燃えていますので、私はすぐにそこに行き、何が起こっているのかを見る傾向があります)。
ジョシュダーネル

この説明をありがとう、それは確かに問題でした。ほとんどの統計のデフォルトのサンプルレートは2.2%でしたが、Oracleからの移行後に作成されたいくつかのサンプルレートは100%でした。デフォルトのインデックス再構築は100%を維持しているようですが、IndexOptimizeを使用した場合、デフォルトの2.2%が同様に適用されました。@StatisticsSampleパラメーターを適用してクエリを再度実行すると、これが問題の原因であることが確認されました。
マーティンベルクストローム

5

ジョンの答えは正しい解決策です。これは、実行計画のどの部分が変更されたかについての単なる追加であり、Sentry One Plan Explorerで簡単に違いを見つける方法の例です。

IndexOptimizeがその後78.000ミリ秒かかるまでに100ミリ秒かかった更新ステートメント(同一のプランを使用)

パフォーマンスが低下したときにすべてのクエリプランを見ると、違いを簡単に見つけることができます。

性能低下

ここに画像の説明を入力してください

CPU時間と経過時間の35秒を超える2つのカウント

期待される性能

ここに画像の説明を入力してください

ずっといい

主な劣化は、この更新クエリで2回発生します。

UPDATE SVALA.INGÅENDEANALYS
                           SET 
                              UPPDRAGAVSLUTAT = @NEW$AVSLUTAT
                        WHERE INGÅENDEANALYS.ID IN 
                           (
                              SELECT IA.ID
                              FROM 
                                 SVALA.INGÅENDEANALYS  AS IA 
                                    JOIN SVALA.INGÅENDEANALYSX  AS IAX 
                                    ON IAX.INGÅENDEANALYS = IA.ID 
                                    JOIN SVALA.ANALYSMATERIAL  AS AM 
                                    ON AM.ID = IA.ANALYSMATERIALID 
                                    JOIN SVALA.ANALYSMATERIALX  AS AMX 
                                    ON AMX.ANALYSMATERIAL = AM.ID 
                                    JOIN SVALA.INSÄNTMATERIAL  AS IM 
                                    ON IM.ID = AM.INSÄNTMATERIALID 
                                    JOIN SVALA.INSÄNTMATERIALX  AS IMX 
                                    ON IMX.INSÄNTMATERIAL = IM.ID
                              WHERE IM.UPPDRAGSID = SVALA.PKGSVALA$STRIPVERSION(@NEW$ID)
                      )

パフォーマンスが低下したこのクエリの実行プラン

この更新クエリの推定クエリプランには、パフォーマンスが低下したときに非常に高い推定があります。

ここに画像の説明を入力してください

現実(実際の実行計画)ではまだ作業を行う必要がありますが、推定値が示すようにクレイジーな量ではありません。

パフォーマンスへの最大の影響は、以下の2つのスキャンとハッシュ一致結合です。

パフォーマンス低下の実際のスキャン#1

ここに画像の説明を入力してください

パフォーマンス低下の実際のスキャン#2

ここに画像の説明を入力してください


期待されるパフォーマンスを備えたこのクエリの実行計画

通常の期待されるパフォーマンスでクエリプランの推定値(または実際値)と比較すると、違いを簡単に見つけることができます。

ここに画像の説明を入力してください

また、前の2つのテーブルアクセスは発生しませんでした。

ここに画像の説明を入力してください

ここに画像の説明を入力してください

ここに画像の説明を入力してください

ハッシュ結合では、ビルド(トップ)入力が最初にハッシュテーブルに挿入されるため、この削除は表示されません。その後、このハッシュテーブルでゼロ値がプローブされ、ゼロ値が返されます。


1
計画の詳細な説明をありがとう、それは問題が発生した理由の私の理解に非常に役立ちました。私は間違いなくSentry One Plan Explorerを見てみましょう、それは非常に便利に見えます!
マーティンベルクストローム

@MartinBergströmそれは聞いて素晴らしいです、クエリプランを提供し、コメントで私たちが尋ねたすべての関連情報を提供してくれてありがとう:) プランエクスプローラーの最大の利点は、無料です!また、ssms内から実行することもできます(実行プランを右クリックして[Sentryoneプランエクスプローラーで表示]を押す)。
ランディヴァートンゲン

1

より多くの情報がなければ、暗闇の中で軽く情報を得た刺ししか取ることができないので、質問を編集してもう少し提供する必要があります。たとえば、インデックスの統計が更新されたために計画が異なる場合があるため、インデックスメンテナンス操作の前後にタイミングを指定した更新ステートメントのクエリプラン(https://www.brentozar.com/pastetheplan /は、XMLの巨大な塊で質問を埋めたり、計画のテキストに含まれる関連情報の一部を含まないスクリーングラブを提供するよりも、これに役立ちます。

ただし、次の2つの非常にシンプルなポイントがあります。

  1. 最適化の実行は確実に完了しましたか?テストが、実行時間の長いインデックスの再構築のIOと競合する場合、タイミングに影響します。
  2. 複数回テストしましたか?更新が、単純な「UPDATE TheTable SET ThisColumn = 'A Static Value」ではなく、大量のデータを考慮するクエリからのデータに基づいている場合、このデータは通常メモリにあるが、その関連照会の最初の実行がしますディスクを打つのではなく、メモリにバッファプール内にすでに必要なページを見つけることによる通常よりも遅くなります。

お返事ありがとうございます。pastetheplanリンクで質問を更新しました。最適化は間違いなく完了し、問題が発生する前日に約1時間実行されました。複数回テストを行いましたが、実際には同じ方法で2つの異なるテスト環境で実行されているデータベースの2つのコピーに影響しました。UPDATEステートメントは、影響を受けた他の多数の挿入と選択があった、ちょうど私が見つけた最も単純な例でした
マーティン・バーグストロム

「複数回」とは、インデックス最適化スクリプトを個別に複数回実行するのではなく、インデックスの1つのインスタンスが更新された後に更新を複数回試みることを意味しました(ただし、それ自体が結果を再現できることを確認するのに便利な方法です)。メモリフラッシュが問題である(またはその一部である)場合、最初のselect-from-selectsはバッファプールを準備するため、IOが大幅に減少するため、後の更新が潜在的に高速になります。
デビッドスピレット

返信が不明確だった場合はおApび申し上げます。はい、更新を複数回試しました。テスターがアプリケーションとクエリおよび更新をテストするために使用するデータベースでスローダウンが発生し、パフォーマンスが改善されることなく1日中複数回実行されました。
マーティンベルクストローム
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.