使用 SQL 标量函数的查询如何在 5 分钟内从 运行 变为 5 小时

How can a query with a SQL scalar function go from running in 5 minutes to 5 hours

我一直在使用这个功能,它很常用来删除非字母数字字符。

ALTER Function [dbo].[RemoveNonAlphaCharacters](@Temp VarChar(1000))
Returns VarChar(1000)
AS
Begin

    Declare @KeepValues as varchar(50)
    Set @KeepValues = '%[^a-z0-9]%'
    While PatIndex(@KeepValues, @Temp) > 0
        Set @Temp = Stuff(@Temp, PatIndex(@KeepValues, @Temp), 1, '')

    Return @Temp
End

这从 运行宁用了 5 分钟变成了 5 小时。是什么原因造成的?当我从查询中删除函数时,它会在 5 分钟内返回完成。此查询已 运行 数百次。

数据还是一样,索引还是一样,没有碎片化。磁盘space 180GB左右也足够了,内存也很充足,基本上,两个运行之间没有任何变化。我还检查了 SQL 探查器是否有任何痕迹,但我只能找到 运行 的内部痕迹,主要是 Microsoft Telemetry 服务(2016 开发人员版)

我真的很困惑,我知道标量函数不是最有效的,但是 运行ning 时间的急剧增加让我感到困惑。

正如我在评论中提到的,您的问题在这里有 2 倍:

  1. 您有一个 Multi-line 标量函数,众所周知,它通常性能不佳。 (即使您使用 SQL Server 2019,该函数也不会内联。)
  2. 你的函数中有一个 WHILEdo 表现不佳,因为 SQL 是一种 set-based 语言,因此不是为了很好地执行迭代过程。

我假设该函数的意图是它执行它调用的操作,并且只保留字符串中的数字和字母。由于您没有注意到版本,因此我建议使用内联 table-value 函数。我将 假设 ,但是,您可以访问足够新的版本来使用 STRING_AGG 不过:

CREATE FUNCTION dbo.RemoveNonAlphaCharacters (@InputString varchar(1000))
RETURNS table
AS RETURN
    WITH N AS(
        SELECT N
        FROM (VALUES(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL))N(N)),
    Tally AS(
        SELECT TOP (LEN(@InputString))
               ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS I
        FROM N N1, N N2, N N3),
    Chars AS(
        SELECT I,
               SUBSTRING(@InputString,I,1) AS C
        FROM Tally)
    SELECT STRING_AGG(C,'') WITHIN GROUP (ORDER BY I) AS OutputString
    FROM Chars
    WHERE C LIKE '[A-z]'
       OR C LIKE '[0-9]';

然后你可以在 FROM:

中使用 CROSS APPLY 调用所述函数
SELECT V.YourString,
       RNAC.OutputString
FROM (VALUES('abc 123-789'),('Apples & Pears'),('Mr O''Mally'))V(YourString)
     CROSS APPLY dbo.RemoveNonAlphaCharacters(V.YourString) RNAC;

如果您使用的不是最新版本的 SQL 服务器,则需要将 STRING_AGG 调用替换为“旧”FOR XML PATH(以及 STUFF) 方法。