Bạn có thể tính gần đúng những gì bạn thấy trong Trình theo dõi hiệu suất và Trình giám sát hoạt động SQL Compilations/sec
và Batch Requests/sec
trong khi chạy một số lô trong cửa sổ truy vấn riêng dưới dạng thử nghiệm, như chi tiết bên dưới.
Cửa sổ truy vấn 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;
Trong Cửa sổ truy vấn 2, hãy chạy đoạn mã sau trong khi đoạn mã trên đang chạy. Mã chỉ đơn giản thực hiện 100 lô T-SQL:
EXEC sys.sp_executesql N'SELECT TOP(1) o.name FROM sys.objects o;';
GO 100
Nếu bạn quay lại Cửa sổ truy vấn 1, bạn sẽ thấy một cái gì đó như thế này:
╔═══════════════╦══════════════════════╦══════════ ══════════════╦════════════════════╗
ElapsedTimeMS Biên dịch SQL / giây Rec Biên dịch lại SQL / giây Request Yêu cầu hàng loạt / giây
╠═══════════════╬══════════════════════╬══════════ ══════════════╬════════════════════╣
10020.00 10.07984031000 0,0000000000 ║ 10.07984031000
╚═══════════════╩══════════════════════╩══════════ ══════════════╩════════════════════╝
Nếu chúng ta xem xét truy vấn này:
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)%'
Chúng tôi có thể xác nhận đã có 100 lần thực hiện truy vấn thử nghiệm.
Trong các kết quả trên, bạn có thể thấy chúng tôi đang nhận được biên soạn mỗi lần các sp_executesql
thực thi tuyên bố. Kế hoạch cho điều đó chắc chắn đang được lưu trữ, nhưng chúng ta thấy một phần tổng hợp cho nó; đưa cái gì?
Các Microsoft Docs nói điều này về sp_executesql
:
sp_executesql có hành vi tương tự như EXECUTE liên quan đến các lô, phạm vi tên và bối cảnh cơ sở dữ liệu. Câu lệnh hoặc lô Transact-SQL trong tham số sp_executesql @stmt không được biên dịch cho đến khi câu lệnh sp_executesql được thực thi. Nội dung của @stmt sau đó được biên dịch và thực thi như một kế hoạch thực hiện tách biệt với kế hoạch thực hiện của lô được gọi là sp_executesql.
Vì vậy, sp_executesql
chính nó đang được biên dịch mỗi khi nó chạy, ngay cả khi kế hoạch cho văn bản lệnh đã có trong bộ đệm của kế hoạch. @PaulWhite cho thấy trong câu trả lời của mình rằng hầu hết các cuộc gọi đến sp_executesql trên thực tế không được lưu trong bộ nhớ cache.