Вы можете аппроксимировать то, что вы видите в Performance Monitor и Activity Monitor для 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
Если вы переключитесь обратно в Query Window 1, вы увидите что-то вроде этого:
╔═══════════════╦══════════════════════╦══════════ ══════════════╦════════════════════╗
La ElapsedTimeMS ║ Компиляции SQL / с ║ Перекомпиляции SQL / с ║ Пакетные запросы / с ║
╠═══════════════╬══════════════════════╬══════════ ══════════════╬════════════════════╣
20 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
выполняется оператор. План для этого, безусловно, кэшируется, но мы видим компиляцию для него; что дает?
В Docs Microsoft сказать о sp_executesql
:
Процедура sp_executesql имеет такое же поведение, что и EXECUTE, в отношении пакетов, области имен и контекста базы данных. Оператор или пакет Transact-SQL в параметре sp_executesql @stmt не компилируется, пока не будет выполнен оператор sp_executesql. Содержимое @stmt затем компилируется и выполняется как план выполнения, отдельный от плана выполнения пакета, который называется sp_executesql.
Таким образом, sp_executesql
сама программа компилируется при каждом запуске, даже если план для текста команды уже находится в кэше планов. @PaulWhite показывает в своем ответе, что большинство вызовов sp_executesql фактически не кэшируются.