You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何在WHERE子句中使用函数会导致性能大幅差异?

为何提取通配符搜索逻辑到函数后性能暴跌近10倍?

为消除多存储过程中的重复SQL逻辑、保证代码同步,我把共用的两端通配符WHERE条件提取成了标量函数。原以为这种场景下本来就是索引扫描,性能不会有太大差异,结果实际运行后性能差了近10倍。

原查询

SELECT COUNT(1) 
FROM MyTable 
WHERE MyField LIKE '%term1%' 
   OR MyField LIKE '%term2%' 
   OR MyField LIKE '%term3%'

提取的标量函数

CREATE FUNCTION dbo.fn_MyFunc
    (@CodeResult VARCHAR(MAX))
RETURNS BIT
WITH SCHEMABINDING, RETURNS NULL ON NULL INPUT  
AS
BEGIN
    RETURN 
        CASE 
            WHEN @CodeResult LIKE '%term1%' 
                 OR @CodeResult LIKE '%term2%' 
                 OR @CodeResult LIKE '%term3%' 
                THEN 1
                ELSE 0
        END;
END;

改写后的查询

SELECT COUNT(1) 
FROM MyTable 
WHERE dbo.fn_MyFunc(MyField) = 1

性能差距的核心原因

  • 逐行执行的开销:SQL Server的标量函数默认是逐行调用,扫描MyTable的每一行时,都要单独执行一次fn_MyFunc的逻辑。而原查询的多个LIKE OR是作为集合运算的一部分,优化器可以批量处理所有行的模式匹配,效率远高于逐行调用函数。
  • 优化器无法穿透函数逻辑:标量函数对查询优化器来说是“黑盒”,它无法分析函数内部的LIKE逻辑,也就做不了任何优化(比如合并模式匹配规则)。而原查询中,优化器能直接处理LIKE条件,甚至可能对多个OR的匹配逻辑做内部合并优化。
  • VARCHAR(MAX)的额外损耗:函数参数用了VARCHAR(MAX),如果MyField本身是更小的VARCHAR类型(比如VARCHAR(200)),每次调用函数都会触发隐式类型转换,这个损耗在逐行执行时会被大幅放大。

解决方案

改用**内联表值函数(ITVF)**替代标量函数,内联表值函数的逻辑会被优化器直接展开,和原查询的执行逻辑几乎一致,既能复用代码又不损失性能:

内联表值函数定义

CREATE FUNCTION dbo.fn_MyFunc_ITVF(@CodeResult VARCHAR(MAX))
RETURNS TABLE
WITH SCHEMABINDING
AS
RETURN SELECT 1 AS MatchResult
WHERE @CodeResult LIKE '%term1%' 
   OR @CodeResult LIKE '%term2%' 
   OR @CodeResult LIKE '%term3%';

改写后的查询

SELECT COUNT(1)
FROM MyTable
CROSS APPLY dbo.fn_MyFunc_ITVF(MyField) f;

如果不需要动态参数,也可以用视图封装WHERE逻辑;若需动态参数,内联表值函数是最优选择。

内容的提问来源于stack exchange,提问作者Vladimirs

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 10:37:18