我尝试加载测试一个简单的插入存储过程
CREATE TABLE _test(ID BIGINT)
CREATE OR alter PROCEDURE dbo.test_sp
AS
BEGIN
SET NOCOUNT ON;
BEGIN
INSERT INTO _test
SELECT CAST(RAND() * 10000 AS BIGINT)
END
END
当我使用 SQLStress 工具运行此 sp 时,我得到的结果不SQL Compilation\sec
等于Batch Request\sec.
有趣的事实是SQL Re-Compilations\sec
0。
optimized for ad-hoc
和均已Forced parametrization
启用。即使我将 sp 更改为简单的SELECT 1
. 任何帮助将不胜感激。我使用 Microsoft SQL Server 2016 (SP3) (KB5003279)。
编译与优化不同。
编译本身很便宜。每当计划缓存中找不到与提交的文本完全匹配的内容时,就会发生这种情况。优化的成本要高得多。
编译可能需要也可能不需要查询优化器。简单的命令则不然。您会注意到有单独的查询优化计数器。编译并不一定会导致优化。
大多数不需要查询优化器的命令都不会被缓存,因为它不值得。这些通常被称为“零成本计划”,并且可能根本不是查询。
例如,
SELECT @@SPID
是一个零成本计划SET STATISTICS XML ON
。只有后者被缓存为例外,因为它很常见,大多数类似的命令都不是。它们只是根据需要进行编译。SQL压力工具提交:
这一切所做的就是调用一个存储过程。它被认为是零成本并且不被缓存。当然,存储过程本身会被缓存,但调用它的文本不会被缓存。
这就是您在每次迭代中看到的“编译”内容,即调用
EXECUTE
本身。该过程将按照您的预期进行缓存和重用。不必太担心每秒的 SQL 编译次数。相反,请注意优化的数量。即使对于一个简单的计划,调用查询优化器也比编译昂贵得多。
如果您确实希望示例不显示任何编译,请使工具提交的批处理更加复杂,以便服务器认为值得对其进行缓存和重用。即使这样也可以:
相关阅读: Fabiano Amorim 的《SQL Compilations/sec》并不是您想象的那样。
* 以这种方式调用存储过程会产生(少量)成本。直接将过程作为 RPC 调用更为有效,但您使用的工具不会公开该功能。