以下で詳しく説明するように、テストとして別のクエリウィンドウでいくつかのバッチを実行しながら、パフォーマンスモニターとアクティビティモニターでSQL Compilations/sec
とBatch Requests/sec
に表示されるものを概算できます。
クエリウィンドウ1:
DECLARE @t1 datetime;
DECLARE @t2 datetime;
DECLARE @CompVal1 int;
DECLARE @CompVal2 int;
DECLARE @ReCompVal1 int;
DECLARE @ReCompVal2 int;
DECLARE @BatchVal1 int;
DECLARE @BatchVal2 int;
DECLARE @ElapsedMS decimal(10,2);
SELECT @t1 = GETDATE()
, @CompVal1 = (
SELECT spi.cntr_value
FROM sys.sysperfinfo spi
WHERE spi.counter_name = 'SQL Compilations/sec '
)
, @ReCompVal1 = (
SELECT spi.cntr_value
FROM sys.sysperfinfo spi
WHERE spi.counter_name = 'SQL Re-Compilations/sec '
)
, @BatchVal1 = (
SELECT spi.cntr_value
FROM sys.sysperfinfo spi
WHERE spi.counter_name = 'Batch Requests/sec '
);
WAITFOR DELAY '00:00:10.000';
SELECT @t2 = GETDATE()
, @CompVal2 = (
SELECT spi.cntr_value
FROM sys.sysperfinfo spi
WHERE spi.counter_name = 'SQL Compilations/sec '
)
, @ReCompVal2 = (
SELECT spi.cntr_value
FROM sys.sysperfinfo spi
WHERE spi.counter_name = 'SQL Re-Compilations/sec '
)
, @BatchVal2 = (
SELECT spi.cntr_value
FROM sys.sysperfinfo spi
WHERE spi.counter_name = 'Batch Requests/sec '
);
SET @ElapsedMS = DATEDIFF(MILLISECOND, @t1, @t2);
SELECT ElapsedTimeMS = @ElapsedMS
, [SQL Compilations/sec] = (@CompVal2 - @CompVal1) / @ElapsedMS * 1000
, [SQL Recompilations/sec] = (@ReCompVal2 - @ReCompVal1) / @ElapsedMS * 1000
, [Batch Requests/sec] = (@BatchVal2 - @BatchVal1) / @ElapsedMS * 1000;
クエリウィンドウ2で、上記のコードの実行中に次を実行します。コードは単に100個のT-SQLバッチを実行します。
EXEC sys.sp_executesql N'SELECT TOP(1) o.name FROM sys.objects o;';
GO 100
クエリウィンドウ1に戻ると、次のように表示されます。
╔═══════════════╦══════════════════════╦══════════ ══════════════╦════════════════════╗
║ElapsedTimeMS║SQLコンパイル/秒║SQL再コンパイル/秒║バッチリクエスト/秒║
╠═══════════════╬══════════════════════╬══════════ ══════════════╬════════════════════╣
║10020.00║10.07984031000║0.00000000000║10.07984031000║
╚═══════════════╩══════════════════════╩══════════ ══════════════╩════════════════════╝
このクエリを見てみると、
SELECT dest.text
, deqs.execution_count
FROM sys.dm_exec_query_stats deqs
CROSS APPLY sys.dm_exec_sql_text(deqs.plan_handle) dest
WHERE dest.text LIKE 'SELECT TOP(1)%'
テストクエリが100回実行されたことを確認できます。
上記の結果では、ステートメントが実行されるたびにコンパイルが行われていることがわかりますsp_executesql
。その計画は確かにキャッシュされていますが、そのためのコンパイルが見られます。何が出るの?
マイクロソフトドキュメントでは、これをについて言いますsp_executesql
:
sp_executesqlは、バッチ、名前のスコープ、およびデータベースコンテキストに関して、EXECUTEと同じ動作をします。sp_executesql @stmtパラメータのTransact-SQLステートメントまたはバッチは、sp_executesqlステートメントが実行されるまでコンパイルされません。次に、@ stmtの内容がコンパイルされ、sp_executesqlを呼び出したバッチの実行プランとは別の実行プランとして実行されます。
したがって、コマンドテキストのプランが既にプランキャッシュにある場合でも、実行されるたびにsp_executesql
それ自体がコンパイルされます。@PaulWhiteは彼の回答で、sp_executesqlへのほとんどの呼び出しが実際にはキャッシュされていないことを示しています。