Sie können annähern, was Sie in Performance Monitor und Activity Monitor für SQL Compilations/sec
und sehen Batch Requests/sec
, während Sie einige Stapel in einem separaten Abfragefenster als Test ausführen, wie unten beschrieben.
Abfragefenster 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;
Führen Sie in Abfragefenster 2 Folgendes aus, während der obige Code ausgeführt wird. Der Code führt einfach 100 T-SQL-Stapel aus:
EXEC sys.sp_executesql N'SELECT TOP(1) o.name FROM sys.objects o;';
GO 100
Wenn Sie zurück zu Abfragefenster 1 wechseln, sehen Sie ungefähr Folgendes:
╔═══════════════╦══════════════════════╦══════════ ══════════════╦════════════════════╗
║ ElapsedTimeMS ║ SQL-Kompilierungen / Sek. ║ SQL-Neukompilierungen / Sek. ║ Stapelanforderungen / Sek. ║
╠═══════════════╬══════════════════════╬══════════ ══════════════╬════════════════════╣
║ 10020.00 ║ 10.07984031000 ║ 0.00000000000 ║ 10.07984031000 ║
╚═══════════════╩══════════════════════╩══════════ ══════════════╩════════════════════╝
Wenn wir uns diese Abfrage ansehen:
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)%'
Wir können bestätigen, dass die Testabfrage 100 Mal ausgeführt wurde.
In den obigen Ergebnissen sehen Sie, dass wir jedes Mal Kompilierungen erhalten, wenn die sp_executesql
Anweisung ausgeführt wird. Der Plan dafür wird sicherlich zwischengespeichert, aber wir sehen eine Zusammenstellung dafür; was gibt?
Die Microsoft Docs sagen dies über sp_executesql
:
sp_executesql verhält sich in Bezug auf Stapel, Namensumfang und Datenbankkontext genauso wie EXECUTE. Die Transact-SQL-Anweisung oder der Stapel im Parameter sp_executesql @stmt wird erst kompiliert, wenn die Anweisung sp_executesql ausgeführt wird. Der Inhalt von @stmt wird dann kompiliert und als Ausführungsplan ausgeführt, der vom Ausführungsplan des Stapels mit dem Namen sp_executesql getrennt ist.
Daher wird es bei jeder Ausführung sp_executesql
selbst kompiliert, auch wenn sich der Plan für den Befehlstext bereits im Plan-Cache befindet. @PaulWhite zeigt in seiner Antwort, dass die meisten Aufrufe von sp_executesql tatsächlich nicht zwischengespeichert werden.