Sp_BlitzFirstで待機を追跡しているときに、次の詳細が表示されます。
<?ClickToSeeDetails --
For 20 seconds over the last 5 seconds, SQL Server was waiting on this
particular bottleneck.
-- ?>
「最後の5秒間に20回」と読むべきでしょうか?結果はCLR_SEMAPHOREでした。
いいえ-待機統計は、サーバー自体に費やされた物理時間よりも多くなることができます(多くの場合、そうなるでしょう)。
2つの別々のスレッドがリソースを待機するために同じ1秒を費やす状況を想像してください。1秒のクロック時間に対して2秒の待機時間があります。
各スレッドには独自の待機があります。メッセージは、特定のリソースの待機時間が20秒経過したのに、最後の5秒間のクロック時間が経過したことを示しています。
別の言い方をすれば、各コアが同時に複数のクエリを実行している可能性があり、複数のコアを追加するとさらに多くの待機が発生する可能性があります。つまり、単位は実際には秒ではなくスレッド秒です。
例を示すことも役立つでしょう。 worker の最も一般的な3つの状態を考えます。
RUNNING =ワーカーは現在、非プリエンプティブまたはプリエンプティブのいずれかで実行されています。
RUNNABLE =ワーカーはスケジューラで実行する準備ができています。
SUSPENDED =ワーカーは現在中断されており、イベントがシグナルを送信するのを待機しています。
RUNNING
の状態のワーカーは、待機時間を生成できます。たとえば、ワーカーがSQLOSではなくOSでコードを実行する必要がある場合、ワーカーはプリエンプティブまたは外部の待機を開始する可能性があります。その間、関連するCPUでコードを実行しますが、待機時間は引き続き発生します。
状態がRUNNABLE
のワーカーは、待機時間を生成できます(私が知っている限り、常にそうです)。リソースが利用可能であるとワーカーに通知された場合、ワーカーは最後の待機に基づいてシグナル待機時間を蓄積する可能性があります。ワーカーが以前の4ミリ秒のクォンタムを使い果たした場合、ワーカーはSOS_SCHEDULER_YIELD
待ち時間。
SUSPENDED
の状態のワーカーは、待機時間を生成できます。ロックを待っているワーカーを考えてみましょう。必要なロックリソースが使用可能であることが通知されるまで待機時間を生成します。一部の一時停止されたワーカーは、タスクに関連付けられていないワーカーを含め、待機時間を生成しません。
私のデスクトップには4つの論理コアがあるため、デフォルトの最大ワーカー数は 512 です。それはほぼ確実に非現実的ですが、このマシンでは、すべてのワーカーが何かを同時に待機させることができれば、理論的には1秒あたり512秒の待機時間を生成できます。コア/ワーカー数が増えると、その数はさらに増える可能性があります。
SQL Serverに対してクエリを実行していない場合でも、1秒あたりの待機時間が1秒を超えることがあります。私のマシンでは、次のクエリで9〜14行が生成されるようです。
SELECT [state], last_wait_type, wait_started_ms_ticks
FROM sys.dm_os_workers
WHERE [state] IN ('SUSPENDED', 'RUNNABLE')
AND task_address IS NOT NULL
AND wait_started_ms_ticks <> 0
AND wait_started_ms_ticks >= start_quantum;
最後にサーバーを再起動してからの合計待機時間のスナップショットを取得し、10秒待機した後、それを新しい合計と比較できます。
DECLARE @start_wait_time_ms BIGINT;
SELECT @start_wait_time_ms = SUM(wait_time_ms)
FROM sys.dm_os_wait_stats
WHERE wait_type <> 'WAITFOR';
WAITFOR DELAY '00:00:10';
SELECT SUM(wait_time_ms) - @start_wait_time_ms
FROM sys.dm_os_wait_stats
WHERE wait_type <> 'WAITFOR';
時々数学がうまくいきます。最後に実行したときのデルタは101339ミリ秒でした。つまり、システムタスクだけで、1秒あたり10秒を超える待機がありました。