あるお客様では、アプリケーションのパフォーマンスに問題が発生しています。これは、SQL Serverデータベースのデータを消費および更新する.NET 3.5 Webアプリです。現在、本番環境は、フロントエンドとしてのWindows 2008 R2マシンと、バックエンド上のSQL Server 2008 R2クラスターで構成されています。私たちのアプリはCOM +とMSDTCを使用してデータベースに接続します。
状況は次のとおりです。エンドユーザーがアプリケーションの速度低下を訴える場合があります。一部のページは、予想よりもロードに時間がかかります。何が起こっているのかを理解しようとしているときに、パフォーマンスの低下の原因である可能性のあるデータベース側の奇妙な動作を見つけることができました。予想されるよりも実行に時間がかかるSQLステートメントが時々あることに気づきました。プロファイラートレース(TSQL_Durationテンプレートを使用)を使用してこれらのステートメントの一部(主にアプリケーションのストアドプロシージャの呼び出し)を特定し、長時間実行されているクエリを特定しました。
問題は、これらのストアドプロシージャをSQL Management Studioのデータベースで直接実行すると、時間がかかる(約7/8秒)か、速くなる(1秒未満)ことです。 SQLマシン(4コア、32 GB)が他のアプリケーションで使用されておらず、これらのクエリの実行にこれほど長い時間がかかることはないため、これが発生する理由はわかりません。
私はDBAやSQL Serverの第一人者ではないので、問題を理解するのに役立つ可能性のあるものをいくつか調べてみました。問題を解決するために私が取った手順と、これまでにわかったことは次のとおりです。
WITH Waits AS
(SELECT
wait_type,
wait_time_ms / 1000.0 AS WaitS,
(wait_time_ms - signal_wait_time_ms) / 1000.0 AS ResourceS,
signal_wait_time_ms / 1000.0 AS SignalS,
waiting_tasks_count AS WaitCount,
100.0 * wait_time_ms / SUM (wait_time_ms) OVER() AS Percentage,
ROW_NUMBER() OVER(ORDER BY wait_time_ms DESC) AS RowNum
FROM sys.dm_os_wait_stats
WHERE wait_type NOT IN (
'CLR_SEMAPHORE', 'LAZYWRITER_SLEEP', 'RESOURCE_QUEUE', 'SLEEP_TASK',
'SLEEP_SYSTEMTASK', 'SQLTRACE_BUFFER_FLUSH', 'WAITFOR', 'LOGMGR_QUEUE',
'CHECKPOINT_QUEUE', 'REQUEST_FOR_DEADLOCK_SEARCH', 'XE_TIMER_EVENT', 'BROKER_TO_FLUSH',
'BROKER_TASK_STOP', 'CLR_MANUAL_EVENT', 'CLR_AUTO_EVENT', 'DISPATCHER_QUEUE_SEMAPHORE',
'FT_IFTS_SCHEDULER_IDLE_WAIT', 'XE_DISPATCHER_WAIT', 'XE_DISPATCHER_JOIN', 'BROKER_EVENTHANDLER',
'TRACEWRITE', 'FT_IFTSHC_MUTEX', 'SQLTRACE_INCREMENTAL_FLUSH_SLEEP',
'BROKER_RECEIVE_WAITFOR', 'ONDEMAND_TASK_QUEUE', 'DBMIRROR_EVENTS_QUEUE',
'DBMIRRORING_CMD', 'BROKER_TRANSMITTER', 'SQLTRACE_WAIT_ENTRIES',
'SLEEP_BPOOL_FLUSH', 'SQLTRACE_LOCK')
)
SELECT
W1.wait_type AS WaitType,
CAST (W1.WaitS AS DECIMAL(14, 2)) AS Wait_S,
CAST (W1.ResourceS AS DECIMAL(14, 2)) AS Resource_S,
CAST (W1.SignalS AS DECIMAL(14, 2)) AS Signal_S,
W1.WaitCount AS WaitCount,
CAST (W1.Percentage AS DECIMAL(4, 2)) AS Percentage,
CAST ((W1.WaitS / W1.WaitCount) AS DECIMAL (14, 4)) AS AvgWait_S,
CAST ((W1.ResourceS / W1.WaitCount) AS DECIMAL (14, 4)) AS AvgRes_S,
CAST ((W1.SignalS / W1.WaitCount) AS DECIMAL (14, 4)) AS AvgSig_S
FROM Waits AS W1
INNER JOIN Waits AS W2 ON W2.RowNum <= W1.RowNum
GROUP BY W1.RowNum, W1.wait_type, W1.WaitS, W1.ResourceS, W1.SignalS, W1.WaitCount, W1.Percentage
HAVING SUM (W2.Percentage) - W1.Percentage < 95; -- percentage threshold
GO
これが私が見つけたものです:
誰かがこのデータをもっと理解するのを手伝ってくれる?誰が何が起こっているのか理解する手助けをしてくれますか?サーバーで何かを試して理解するためにできることはありますか?アプリケーション開発チームに相談する必要がありますか?
問題の詳細な説明(実際に最もよくレイアウトされた質問の1つ)をありがとうございます。
WRITELOGは非常に一般的なタイプの待機なので、心配する必要はありません。 SOS_SCHEDULER_YIELDを見ると、CPUプレッシャーとCXPACKETが示されているため、いくつかのインデックスが欠落している可能性があり、OLTPシステムのクエリから多くのデータを取得している可能性があります。 Missing Indexes DMVを調べて、疑わしいprocにインデックスがあるかどうかを確認します(ほとんど確実に少ないでしょう)。
http://sqlfool.com/2009/04/a-look-at-missing-indexes/
これに関するsqlblog.comのJonathan Kehayiasの投稿も探してください。
また、パラメータスニッフィングもご覧ください。
http://sommarskog.se/query-plan-mysteries.html
http://pratchev.blogspot.com/2007/08/parameter-sniffing.html
それはあなたのニーズに対する完全な答えではありませんが、良い出発点です。詳細が必要な場合はお知らせください。
従業員の1人がいくつかのストアドプロシージャを書き直した後も、同様の問題が発生しました。過剰な分岐があり、動的SQLが作成されているため、where句が大幅に変更されていることがわかりました。
たとえば(もちろん簡略化):
Modelが "X"の場合、where句はProductCodeを探して特定の値と等しくなります。
Modelが "Y"の場合、where句はProductTypeを探して特定の値と等しくなります。
SQL Serverは、ストアドプロシージャが初めて実行されるときに、入力パラメーターに基づいてクエリプランを構築します。したがって、クエリプランが「ProductCode」の等しいを使用するロジックに基づいて構築されており、「ProductType」の等しいを要求している場合、クエリプランは一致せず、ほとんどの場合、フルテーブルスキャンが行われます。
ストアドプロシージャの上部に「WITH RECOMPILE」を配置してみてください。 CREATE PROCEDURE(Transact-SQL)
これを説明する最良の方法は次のとおりです。
姓でソートされた名前と電話番号のリストがあるとします。これは、姓(姓に基づくクエリプラン)を使用している人を見つけるのに最適です。ここで、市外局番203のすべての名前と電話番号が必要であるとします。リストが姓で並べ替えられている場合、市外局番203のすべての人の完全なリストを取得する唯一の方法は、上から始めて、順番に読むことです。すべてのレコード。 (全表スキャン)。
SSMSとアプリでクエリが断続的に高速かつ低速で実行されている場合は、統計情報またはパラメータースニッフィングの問題がある可能性があります。
これらのストアドプロシージャを実行し、実行プランを確認して、ルートオペレーターのプロパティ(各ステートメントの左端にある緑のノード)をプルアップします。
実際に返された行数に対して、実行プランの推定行数はいくつですか?
コンパイルされたパラメータは実際のクエリパラメータと一致しますか?
少数の行のみを返すパラメーターの実行プランが作成され、膨大な数の行を返すパラメーターを使用して同じ手順を実行すると、SQLはクエリに対して誤った実行プランを使用する場合があります。
実行プランの選択はSQL統計と密接に関連しているため、定期的に統計を再構築することをお勧めします。
提供されたパラメーターに応じて、少量のデータまたは大量のデータを返すストアード・プロシージャーがある場合、パラメーターのスニッフィングの問題がある可能性があります。
統計を再構築しても問題が解決しない場合は、OPTION (RECOMPILE)
を使用して、ストアドプロシージャで最も高価なステートメントを実行できます。
長時間実行されているクエリを特定したので、これらのプロシージャの実行プランをキャッシュからフェッチし、そこで問題を特定できるかどうかを確認できます。多くの場合、データ型の暗黙的または実行時の変換があります。また、大量のデータをパージまたは挿入する場合は、統計も更新することをお勧めします。