これはサーバーの過負荷の症状ですか?


12

アプリケーションのスローダウンを診断しようとしています。このために、SQL Server 拡張イベントを記録しました。

  • この質問では、1つの特定のストアドプロシージャを見ています。
  • しかし、リンゴからリンゴへの調査として同様に使用できる12個のストアドプロシージャのコアセットがあります。
  • ストアドプロシージャの1つを手動で実行すると、常に高速に実行されます
  • また、ユーザーが再試行した場合、高速で実行されます。

ストアドプロシージャの実行時間は大きく異なります。このストアドプロシージャの実行の多くは1秒未満で返されます。

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

そして、その「高速」バケットについては、1秒よりはるかに少ないです。実際には約90ミリ秒です。

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

しかし、2秒、3秒、4秒待たなければならない長いユーザーがいます。12、13、14秒待たなければならない人もいます。それから、22、23、24秒待たなければならない本当に貧しい魂がいます。

そして、30秒後、クライアントアプリケーションはあきらめ、クエリを中止し、ユーザーは30秒待つ必要がありました。

原因を見つけるための相関

だから私は相関させようとしました:

  • 期間と論理読み取り
  • 継続時間と物理読み取り
  • 期間とCPU時間

また、相関関係を与えるものはありません。原因はないようです

  • 継続時間と論理読み取り少しでも多くの論理読み取りでも、継続時間は大きく変動します:

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

  • 期間対物理読み取りクエリがキャッシュから提供されず、多くの物理読み取りが必要な場合でも、期間には影響しません。

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

  • duration vs cpu time:クエリが0秒のCPU時間を使用した場合でも、2.5秒のCPU時間を使用した場合でも、期間の変動は同じです。

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

ボーナスDuration v Physical ReadsDuration v CPU timeが非常に似ていることに気付きました。これは、CPU時間を物理読み取りと相関させようとすると証明されます。

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

多くのCPU使用率がI / Oに由来することが判明しました。誰かわかったね!

それで、実行時間の違いを説明できるクエリを実行する行為について何もなければ、それはそれがCPUまたはハードドライブとは無関係な何かであることを意味しますか?

CPUまたはハードドライブがボトルネックだった場合。それがボトルネックではないでしょうか?

ボトルネックはCPUであると仮定した場合、このサーバーのCPUの電力が不足していること:

  • その後、より多くのCPU時間を使用した実行に時間がかかりませんか?
  • 過負荷のCPUを使用して他の人と完了する必要がありますか?

ハードドライブについても同様です。ハードドライブがボトルネックであると仮定した場合、ハードドライブがこのサーバーに十分なランダムスループットを持たないこと:

  • その後、より多くの物理読み取りを使用した実行には時間がかかりませんか?
  • 過負荷のハードドライブI / Oを使用して他の人と完了する必要があるためですか?

ストアドプロシージャ自体は、書き込みも実行も要求もしません。

  • 通常、0行(90%)を返します。
  • 時折、1行(7%)を返します。
  • まれに2行(1.4%)が返されます。
  • そして最悪の場合、2行以上を返しました(一度に12行を返しました)

したがって、異常な量のデータを返しているわけではありません。

サーバーのCPU使用率

サーバーのプロセッサ使用率は平均で約1.8%で、ときどき最大18%のスパイクがあります。したがって、CPU負荷が問題であるとは思えません。

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

そのため、サーバーのCPUが過負荷になっていないようです。

しかし、サーバー仮想です...

宇宙の外に何か?

私が想像できる唯一のことは、サーバーの宇宙の外に存在するものです。

  • 論理読み取りでない場合
  • 物理的な読み取りではありません
  • CPUの使用ではありません
  • そして、それはCPU負荷ではありません

また、ストアドプロシージャのパラメーターとは異なります(同じクエリを手動で発行し、27秒はかからないため、0秒ほどかかります)。

サーバーが同じコンパイル済みストアドプロシージャを実行するのに、0秒ではなく30秒かかることもあると考えられます。

  • チェックポイント?

仮想サーバーです

  • ホストが過負荷ですか?
  • 同じホスト上の別のVM?

サーバーの拡張イベントを通過します。クエリが突然20秒かかる場合、特に何も起こりません。正常に実行された後、正常に実行しないことを決定します。

  • 2秒
  • 1秒
  • 30秒
  • 3秒
  • 2秒

そして、私が見つけることができる他の特に精力的なアイテムはありません。2時間ごとのトランザクションログバックアップではありません。

他に何ありますか?

「サーバー」以外に言えることはありますか?

編集:時刻で関連付ける

期間をすべてに関連付けていることに気付きました:

  • 論理読み取り
  • 物理的な読み取り
  • CPU使用率

しかし、私がそれを相関させなかった一つのことは、時間帯でした。おそらく、2時間ごとのトランザクションログバックアップ問題です。

または、チェックポイント中にチャックでスローダウン発生する可能性がありますか?

いいえ:

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

Intel Xeon Goldクアッドコア6142。

編集-人々はクエリ実行計画を仮定しています

人々は、クエリの実行プランが「高速」と「低速」で異なる必要があると仮定しています。ではない。

そして、これを検査からすぐに見ることができます。

質問の期間が長いのは、実行計画が「悪い」ためではないことがわかります。

  • より論理的な読み取りを行ったもの
  • より多くの結合とキー検索からより多くのCPUを消費したもの

読み取りの増加、またはCPUの増加がクエリの継続時間の増加の原因である場合は、上記で既に見たでしょう。相関関係はありません。

ただし、CPU読み取り領域の製品メトリックと期間を相関させてみましょう。

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

相関関係はさらに少なくなります-これは逆説です。


編集:散布図を更新して、多数の値を持つExcel散布図のバグを回避しました。

次のステップ

次のステップは、ブロックされたクエリのイベントをサーバーで生成するように誰かに依頼することです-5秒後:

EXEC sp_configure 'blocked process threshold', '5';
RECONFIGURE

クエリが4秒間ブロックされるかどうかは説明されません。ただし、クエリを5秒間ブロックしているものは、おそらく4秒間もブロックします。

スロープラン

実行される2つのストアドプロシージャのスロープランは次のとおりです。

  • `EXECUTE FindFrob @CustomerID = 7383、@ StartDate = '20190725 04:00:00.000'、@ EndDate = '20190726 04:00:00.000'
  • `EXECUTE FindFrob @CustomerID = 7383、@ StartDate = '20190725 04:00:00.000'、@ EndDate = '20190726 04:00:00.000'

同じストアドプロシージャを同じパラメータで、連続して実行します。

| Duration (us) | CPU time (us) | Logical reads | Physical reads | 
|---------------|---------------|---------------|----------------|
|    13,984,446 |        47,000 |         5,110 |            771 |
|     4,603,566 |        47,000 |         5,126 |            740 |

コール1:

|--Nested Loops(Left Semi Join, OUTER REFERENCES:([Contoso2].[dbo].[Frobs].[FrobGUID]) OPTIMIZED)
    |--Nested Loops(Inner Join, OUTER REFERENCES:([Contoso2].[dbo].[FrobTransactions].[OnFrobGUID]))
    |    |--Nested Loops(Inner Join, OUTER REFERENCES:([Contoso2].[dbo].[FrobTransactions].[RowNumber]) OPTIMIZED)
    |    |    |--Nested Loops(Inner Join, OUTER REFERENCES:([tpi].[TransactionGUID]) OPTIMIZED)
    |    |    |    |--Nested Loops(Inner Join, OUTER REFERENCES:([tpi].[TransactionGUID]) OPTIMIZED)
    |    |    |    |    |--Index Seek(OBJECT:([Contoso2].[dbo].[TransactionPatronInfo].[IX_TransactionPatronInfo_CustomerID_TransactionGUID] AS [tpi]), SEEK:([tpi].[CustomerID]=[@CustomerID]) ORDERED FORWARD)
    |    |    |    |    |--Index Seek(OBJECT:([Contoso2].[dbo].[Transactions].[IX_Transactions_TransactionGUIDTransactionDate]), SEEK:([Contoso2].[dbo].[Transactions].[TransactionGUID]=[Contoso2].[dbo
    |    |    |    |--Index Seek(OBJECT:([Contoso2].[dbo].[FrobTransactions].[IX_FrobTransactions2_MoneyAppearsOncePerTransaction]), SEEK:([Contoso2].[dbo].[FrobTransactions].[TransactionGUID]=[Contos
    |    |    |--Clustered Index Seek(OBJECT:([Contoso2].[dbo].[FrobTransactions].[IX_FrobTransactions_RowNumber]), SEEK:([Contoso2].[dbo].[FrobTransactions].[RowNumber]=[Contoso2].[dbo].[Fin
    |    |--Clustered Index Seek(OBJECT:([Contoso2].[dbo].[Frobs].[PK_Frobs_FrobGUID]), SEEK:([Contoso2].[dbo].[Frobs].[FrobGUID]=[Contoso2].[dbo].[FrobTransactions].[OnFrobGUID]),  WHERE:([Contos
    |--Filter(WHERE:([Expr1009]>(1)))
     |--Compute Scalar(DEFINE:([Expr1009]=CONVERT_IMPLICIT(int,[Expr1012],0)))
          |--Stream Aggregate(DEFINE:([Expr1012]=Count(*)))
           |--Index Seek(OBJECT:([Contoso2].[dbo].[FrobTransactions].[IX_FrobTransactins_OnFrobGUID]), SEEK:([Contoso2].[dbo].[FrobTransactions].[OnFrobGUID]=[Contoso2].[dbo].[Frobs].[LC

呼び出し2

|--Nested Loops(Left Semi Join, OUTER REFERENCES:([Contoso2].[dbo].[Frobs].[FrobGUID]) OPTIMIZED)
    |--Nested Loops(Inner Join, OUTER REFERENCES:([Contoso2].[dbo].[FrobTransactions].[OnFrobGUID]))
    |    |--Nested Loops(Inner Join, OUTER REFERENCES:([Contoso2].[dbo].[FrobTransactions].[RowNumber]) OPTIMIZED)
    |    |    |--Nested Loops(Inner Join, OUTER REFERENCES:([tpi].[TransactionGUID]) OPTIMIZED)
    |    |    |    |--Nested Loops(Inner Join, OUTER REFERENCES:([tpi].[TransactionGUID]) OPTIMIZED)
    |    |    |    |    |--Index Seek(OBJECT:([Contoso2].[dbo].[TransactionPatronInfo].[IX_TransactionPatronInfo_CustomerID_TransactionGUID] AS [tpi]), SEEK:([tpi].[CustomerID]=[@CustomerID]) ORDERED FORWARD)
    |    |    |    |    |--Index Seek(OBJECT:([Contoso2].[dbo].[Transactions].[IX_Transactions_TransactionGUIDTransactionDate]), SEEK:([Contoso2].[dbo].[Transactions].[TransactionGUID]=[Contoso2].[dbo
    |    |    |    |--Index Seek(OBJECT:([Contoso2].[dbo].[FrobTransactions].[IX_FrobTransactions2_MoneyAppearsOncePerTransaction]), SEEK:([Contoso2].[dbo].[FrobTransactions].[TransactionGUID]=[Contos
    |    |    |--Clustered Index Seek(OBJECT:([Contoso2].[dbo].[FrobTransactions].[IX_FrobTransactions_RowNumber]), SEEK:([Contoso2].[dbo].[FrobTransactions].[RowNumber]=[Contoso2].[dbo].[Fin
    |    |--Clustered Index Seek(OBJECT:([Contoso2].[dbo].[Frobs].[PK_Frobs_FrobGUID]), SEEK:([Contoso2].[dbo].[Frobs].[FrobGUID]=[Contoso2].[dbo].[FrobTransactions].[OnFrobGUID]),  WHERE:([Contos
    |--Filter(WHERE:([Expr1009]>(1)))
     |--Compute Scalar(DEFINE:([Expr1009]=CONVERT_IMPLICIT(int,[Expr1012],0)))
          |--Stream Aggregate(DEFINE:([Expr1012]=Count(*)))
           |--Index Seek(OBJECT:([Contoso2].[dbo].[FrobTransactions].[IX_FrobTransactins_OnFrobGUID]), SEEK:([Contoso2].[dbo].[FrobTransactions].[OnFrobGUID]=[Contoso2].[dbo].[Frobs].[LC

計画が同一であることは理にかなっています。同じストアドプロシージャを同じパラメータで実行しています。


2
クエリプラン(良い実行と悪い実行)を投稿できますか?
キンシャー

4
ここから私の最初の推測では...ブロックされるだろう
ティボーKaraszi

3
誰がこれを支持しましたか?クエリプランが欠けていても、非常に詳細で徹底的に調査された質問です。私から+1!
ベレース

4
クエリプランが「同一」であるという結論に至りましたか?彼らは同じ形をしているという意味ですか?私たちも比較できるように、どこかに投稿してください。それらが同一であると言っても、それらが同一であることを意味しません。
アーロンバートランド

3
使用acutal実行計画の追加PasteThePlanすることは私たちに、クエリが待機していたもののアイデアを与えることができます。
ランディヴァートンゲン

回答:


2

wait_statsを見ると、SQLサーバーの最大のボトルネックが何であるかがわかります。

最近、外部アプリケーションが断続的に遅くなるという問題を経験しました。ただし、サーバー自体でのストアドプロシージャの実行は常に高速でした。

パフォーマンスの監視では、SQLキャッシュやサーバーのRAM使用量とIOについては何も心配する必要はありませんでした。

調査の絞り込みに役立ったのは、SQLで収集された待機統計をクエリすることでした。 sys.dm_os_wait_stats

SQLSkills Webサイトの優れたスクリプト最も経験しているを示します。その後、原因を特定するために検索を絞り込むことができます。

待機が大きな問題であることがわかったら、このスクリプトは、待機しているセッション/データベースを絞り込むのに役立ちます。

SELECT OSW.session_id,
       OSW.wait_duration_ms,
       OSW.wait_type,
       DB_NAME(EXR.database_id) AS DatabaseName
FROM sys.dm_os_waiting_tasks OSW
INNER JOIN sys.dm_exec_sessions EXS ON OSW.session_id = EXS.session_id
INNER JOIN sys.dm_exec_requests EXR ON EXR.session_id = OSW.session_id
OPTION(Recompile);

上記のクエリと詳細は、MSSQLTips Webサイトからのものです。

sp_BlitzFirstBrent OzarのWebサイトのスクリプトも、スローダウンの原因を示しています。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.