对简单过程进行负载测试时编译/秒高

Art*_*yan 4 sql-server stored-procedures sql-server-2016 performance-counters performance-testing

我正在尝试加载测试一个简单的插入存储过程:

CREATE TABLE _test(ID BIGINT)
GO
CREATE OR ALTER PROCEDURE dbo.test_sp
AS
BEGIN
    SET NOCOUNT ON;
    BEGIN
        INSERT INTO _test
        SELECT CAST(RAND() * 10000 AS BIGINT)
    END
END
Run Code Online (Sandbox Code Playgroud)

当我使用 SQL Stress 工具执行此存储过程时,我得到的SQL Compilations/sec等于Batch Requests/sec。有趣的是,SQL 重新编译/秒为零。

性能计数器

两者都针对临时工作负载进行优化,并启用强制参数化。即使我将程序更改为简单的,图片也是一样的SELECT 1

我正在使用 Microsoft SQL Server 2016 (SP3) (KB5003279)。

探查器跟踪显示该工具发送了一个简单的EXEC dbo.test_sp

Pau*_*ite 13

编译优化不同

\n

编译本身很便宜。每当计划缓存中找不到匹配项时就会发生这种情况。优化的成本要高得多。

\n

编译可能需要也可能不需要查询优化器。简单的命令则不然。您会注意到有单独的查询优化计数器。编译并不一定导致优化

\n

大多数不需要查询优化器的命令都不会被缓存,因为它不值得。这些通常被称为“零成本计划”,并且可能根本不是查询。

\n

例如,SELECT @@SPID是一个零成本计划SET STATISTICS XML ON。只有后者作为例外被缓存,因为它很常见;大多数类似的命令都不是。它们只是根据需要进行编译。

\n

SQL压力工具提交:

\n
EXECUTE dbo.test_sp;\n
Run Code Online (Sandbox Code Playgroud)\n

这一切所做的就是调用一个存储过程。它是即席SQL,被认为是零成本,并且不被缓存。当然,存储过程主体会被缓存,但调用它的文本不会被缓存。

\n

这就是您在每次迭代中看到的“编译”\xe2\x80\x94EXECUTE。存储过程的已编译计划将按照您的预期进行缓存和重用。

\n

不必太担心每秒的 SQL 编译次数注意优化的数量。调用查询优化器比简单的编译要昂贵得多。

\n

如果您确实希望示例不显示任何编译,请使工具提交的批处理更加复杂,以便服务器认为值得对其进行缓存和重用。即使这样也可以:

\n
DECLARE @s smallint = (SELECT @@SPID);\nEXECUTE dbo.test_sp;\n
Run Code Online (Sandbox Code Playgroud)\n

这不会显着减少 CPU 或增加吞吐量,因为编译文本的EXECUTE成本很小。

\n

相关阅读:SQL Compilations/sec 并不是你想象的那样

\n
\n

* 将存储过程作为语言事件调用会产生(少量)成本。直接将过程作为 RPC 调用更为有效,但您使用的工具不会公开该功能。

\n

您可以通过 RPC 而不是大多数编程语言的语言事件来调用存储过程,通常是将命令类型设置为“存储过程”。

\n

以下 PowerShell 脚本示例由 Dan Guzman 提供:

\n
EXECUTE dbo.test_sp;\n
Run Code Online (Sandbox Code Playgroud)\n