SQL Server 2019 中标量 UDF 不内联是因不满足白名单条件:返回类型为 sql_variant、含 GOTO/未初始化变量/sp_executesql、引用 CHECKSUM/OPTION (RECOMPILE)、嵌套多层表达式或访问视图/链接服务器等,均被优化器直接降级为传统执行。

标量函数在 SQL Server 2019 中默认可能不内联,不是因为没开功能,而是它根本不符合内联条件——强行依赖内联来“修复性能”反而容易踩坑。
哪些标量 UDF 根本不会被内联
SQL Server 2019 的 Scalar UDF Inlining 是自动触发的,但有严格白名单。只要函数里出现以下任意一项,query_tsql_scalar_udf_inlined XEvent 就不会记录,说明完全跳过内联:
- 返回类型是
sql_variant(KB4538581 明确指出 CU2/CU7 会报错或失败) - 用了
GOTO、未初始化变量、sp_executesql调用 - 包含
CHECKSUM()、OPTION (RECOMPILE)或嵌套多层标量表达式 - 函数体里有引用视图、链接服务器或权限敏感对象(CU9 权限错误即源于此)
这类函数即使兼容级别设为 150,优化器也会直接降级为传统标量执行——你看到的“失效”,其实是按设计拒绝内联。
如何确认当前函数是否真被内联
别只看执行计划图标,得查真实行为:
- 开启扩展事件:
CREATE EVENT SESSION [udf_inline_trace] ON SERVER ADD EVENT sqlserver.query_tsql_scalar_udf_inlined - 运行查询后检查该事件是否触发;若无记录,说明未内联
- 对比
sys.dm_exec_query_stats中同一查询的last_execution_type_desc:值为BATCH才算真正受益于内联路径 - 若发现内联后性能反而下降(KB4538581 提到 CU7 修复可能引发回归),可临时启用
DBCC TRACEON(13156, -1)禁用该修复
比“修复内联”更有效的替代方案
与其反复调试让标量函数勉强内联,不如直接替换掉它:
- 把简单计算逻辑(如
dbo.CalculateTax(OrderAmount))直接写进查询,换成OrderAmount * 0.08 - 把查单值的标量函数(如
dbo.GetDiscount(@ProductID))改写为内联表值函数(RETURNS TABLE),再用CROSS APPLY关联 - 对高频列计算,优先建
PERSISTED计算列,避免每次查询都调用函数 - 若必须封装逻辑,且涉及多表关联,直接用视图或 CTE 替代函数调用
内联只是缓解手段,不是银弹。SQL Server 对标量函数的“黑盒”限制本质没变——真正可控的优化,永远来自把逻辑拉回查询层面。

















