web-dev-qa-db-ja.com

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

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

最近、デフォルトのインデックス再構築メンテナンスジョブから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'

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

これはまだテストデータベースなので(Oracleから本番システムを移行しています)、バックアップに戻ってIndexOptimizeを無効にし、すべてを通常に戻しました。

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

遅い場合のupdateステートメントの実行計画。つまり.
IndexOptimize後
実際の実行計画(できるだけ早く)

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

12

2つのメンテナンスアプローチ間で異なる サンプルレート が定義されていると思います。 @StatisticsSample parameter を指定しない限り、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パラメータを含むOlaのスクリプトを再試行して、問題が解決するかどうかを確認してください。


この理論を裏付ける追加の証拠として、実行プラン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]" />
11
John Eisbrener

ジョンの答え が正しい解決策です。これは、実行プランのどの部分が変更されたか、および Sentry One Plan Explorer を使用して簡単に違いを見つける方法の例に関する追加です。

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

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

パフォーマンスの低下

enter image description here

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

期待されるパフォーマンス

enter image description here

はるかに良い

主な低下は、この更新クエリで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)
                      )

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

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

enter image description here

実際には(実際の実行計画)、それでも機能する必要がありますが、見積もりが示す狂った量ではありません。

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

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

enter image description here

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

enter image description here


予想されるパフォーマンスを備えたこのクエリの実行プラン

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

enter image description here

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

enter image description here

enter image description here

enter image description here

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

5
Randi Vertongen

詳細情報がないと、暗闇の中で情報の少ない刺し傷しか受けられないため、質問を編集してもう少し詳しく説明する必要があります。たとえば、インデックスの統計が更新されたために計画が異なる可能性があるため、インデックスのメンテナンス操作の前後に、タイミングを指定したその更新ステートメントのクエリプラン( https://www.brentozar .com/pastetheplan / これは、XMLの巨大なチャンクである可能性のあるもので質問を埋めたり、計画のテキストに含まれる関連情報の一部が含まれていないスクリーングラブを与えたりするのではなく、これに役立ちます) 。

ただし、2つの非常に単純な点が次のとおりです。

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