あるお客様では、アプリケーションのパフォーマンスに問題があります。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の第一人者ではない私は、問題を理解するのに役立つかもしれないものを調べようとしてきました。以下は、問題を解決しようとするためにとったステップと、これまでに発見したことです。
- アプリケーションによって呼び出されるすべてのTSQLコードは、ストアドプロシージャで記述されます。
- SQL Serverプロファイラーで長時間実行されるクエリの一部を特定しましたが、Management Studioで実行すると、実行に時間がかかる(4〜10秒)か、迅速に実行(1秒未満)します。パラメーターに渡された同じデータを使用して、まったく同じクエリを実行しています。これらのクエリは、主に選択ステートメントを含むストアドプロシージャです。
- 待機およびキューの統計を調べて、いくつかのリソースで待機しているプロセスがあるかどうかを確認しようとしました。次のクエリを実行しました。
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
私が見つけたものは次のとおりです。
- DBCC SQLPERFを使用して統計情報をリセットした後(約1〜2時間後)、私が最も持っている待機タイプはSOS_SCHEDULER_YIELDおよびWRITELOGです。
- (約1日の実行後)時間の経過とともに、データベースで最も多く発生する待機タイプは、それぞれの平均待機時間が長くない場合でも、CXPACKET(67%)とOLEDB(17%)です。また、SQL Profilerで識別される実行時間の長いステートメントは、複数の結果セット(多くの場合3)を返すストアドプロシージャの呼び出しであることに気付きました。ここで並列問題が発生する可能性はありますか?これが問題の原因であるかどうかを特定する方法はありますか?
- OLEDBの待機は、リンクサーバーなどのOLEDBリソースの呼び出しが原因で発生する可能性があることをどこかで読みました。インデックスサービスマシン(MSIDXS)に接続するリンクサーバーがありますが、長時間実行されていると識別されたステートメントはいずれもそのリンクサーバーを使用しません。
- 私が持っている平均待機時間は、LCK_M_Xタイプの待機時間(平均約1.5秒)の方が長くなっていますが、これらの待機タイプは他のタイプと比較してそれほど頻繁に発生しません(たとえば、64 LCK_M_X待機対同じ期間の10,823 CXPACKET待機) )。
- 私が気づいたことの1つは、MSDTCサービスがクラスター化されていないことです。SQL Serverサービスはクラスター化されますが、MSDTCはクラスター化されません。これによりパフォーマンスが低下することはありますか?アプリはエンタープライズサービス(DCOM)を使用してデータベースにアクセスするため、MSDTCを使用していますが、サーバーはクライアントによってインストールおよび構成されていません。
誰でもこのデータをさらに理解するのを手伝ってもらえますか?誰が私に何が起こっているのか理解するのに手を貸してもらえますか?サーバーで何かを試して理解するためにできることはありますか?アプリケーション開発チームと話す必要がありますか?
exec()
関数を使用すると、観察された動作を説明できます。この場合、sp_executesql
通常使用すると、動的SQLステートメントの問題が解決されます。