为什么 SQL 函数比 UDF 快

Zer*_*ity 6 t-sql sql-server user-defined-functions

虽然这是一个相当主观的问题,但我觉得有必要在这个论坛上分享。

我个人经历过,当我创建一个 UDF(即使它并不复杂)并将其用于我的 SQL 时,它会大大降低性能。但是当我使用SQL inbuild 函数时,它们碰巧工作得更快。转换、逻辑和字符串函数就是一个明显的例子。

所以,我的问题是“为什么构建函数中的 SQL 比 UDF 快”?如果有人可以指导我如何从数学或逻辑上判断/操纵函数成本,那将是一个优势。

Mar*_*ith 4

这是 SQL Server 中标量 UDF 的一个众所周知的问题。

\n\n

它们没有内联到计划中,与内联相同的逻辑相比,调用它们会增加开销。

\n\n

以下内容在我的机器上只需要不到 2 秒的时间

\n\n
WITH T10(N) AS \n(\n    SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL \n    SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL \n    SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1\n) --10 rows                                    \n, T(N) AS (SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL))\n           FROM T10 a, T10 b, T10 c, T10 d, T10 e, T10 f, T10 g)  -- 10 million rows\nSELECT MAX(N - N)\nFROM T\nOPTION (MAXDOP 1)\n
Run Code Online (Sandbox Code Playgroud)\n\n

创建简单标量 UDF

\n\n
CREATE FUNCTION dbo.F1 (@N BIGINT)\nRETURNS BIGINT \nWITH SCHEMABINDING\nAS\nBEGIN\nRETURN (@N - @N)\nEND\n
Run Code Online (Sandbox Code Playgroud)\n\n

将查询改为MAX(dbo.F1(N))改为MAX(N - N)大约需要 26 秒,STATISTICS TIME OFF开启时需要 37 秒。

\n\n

1000 万次函数调用中,每次平均增加 2.6\xce\xbcs / 3.7\xce\xbcs。

\n\n

运行 Visual Studio 探查器显示绝大多数时间都花在UDFInvoke. 调用堆栈中方法的名称可以让您了解额外开销的作用(复制参数、执行语句、设置安全上下文)。

\n\n

在此输入图像描述

\n\n

将逻辑移至内联表值函数中

\n\n
CREATE FUNCTION dbo.F2 (@N BIGINT)\nRETURNS TABLE\nRETURN(SELECT @N - @N AS X)\n
Run Code Online (Sandbox Code Playgroud)\n\n

并将查询重写为

\n\n
SELECT MAX(X)\nFROM Nums\nCROSS APPLY dbo.F2(N)\n
Run Code Online (Sandbox Code Playgroud)\n\n

执行速度与不使用任何函数的原始查询一样快。

\n