sql-server – 多语句TVF与内联TVF性能
| 副标题[/!--empirenews.page--] 比较 Palindrome question上的一些答案(仅限10k用户,因为我删除了答案),我的结果令人困惑. 我提出了一个multi-statement,schema-bound TVF,我认为它比运行标准功能更快.我也认为多语句TVF会被“内联”,虽然我错了,但你会在下面看到.这个问题是关于这两种风格的TVF的性能差异.首先,您需要查看代码. 这是多语句TVF: IF OBJECT_ID('dbo.IsPalindrome') IS NOT NULL
DROP FUNCTION dbo.IsPalindrome;
GO
CREATE FUNCTION dbo.IsPalindrome
(
    @Word NVARCHAR(500)
) 
RETURNS @t TABLE
(
    IsPalindrome BIT NOT NULL
)
WITH SCHEMABINDING
AS
BEGIN
    DECLARE @IsPalindrome BIT;
    DECLARE @LeftChunk NVARCHAR(250);
    DECLARE @RightChunk NVARCHAR(250);
    DECLARE @StrLen INT;
    DECLARE @Pos INT;
    SET @RightChunk = '';
    SET @IsPalindrome = 0;
    SET @StrLen = LEN(@Word) / 2;
    IF @StrLen % 2 = 1 SET @StrLen = @StrLen - 1;
    SET @Pos = LEN(@Word);
    SET @LeftChunk = LEFT(@Word,@StrLen);
    WHILE @Pos > (LEN(@Word) - @StrLen)
    BEGIN
        SET @RightChunk = @RightChunk + SUBSTRING(@Word,@Pos,1)
        SET @Pos = @Pos - 1;
    END
    IF @LeftChunk = @RightChunk SET @IsPalindrome = 1;
    INSERT INTO @t VALUES (@IsPalindrome);
    RETURN
END
GO内联TVF: IF OBJECT_ID('dbo.InlineIsPalindrome') IS NOT NULL
DROP FUNCTION dbo.InlineIsPalindrome;
GO
CREATE FUNCTION dbo.InlineIsPalindrome
(
    @Word NVARCHAR(500)
)
RETURNS TABLE
WITH SCHEMABINDING
AS RETURN (
    WITH Nums AS
    (
      SELECT
        N = number
      FROM
        dbo.Numbers
    )
    SELECT
      IsPalindrome =
        CASE
          WHEN EXISTS
          (
            SELECT N
            FROM Nums
            WHERE N <= L / 2
              AND SUBSTRING(S,N,1) <> SUBSTRING(S,1 + L - N,1)
          )
          THEN 0
          ELSE 1
        END
    FROM
      (SELECT LTRIM(RTRIM(@Word)),LEN(@Word)) AS v (S,L)
);
GO上述函数中的Numbers表定义为: CREATE TABLE dbo.Numbers
(
    Number INT NOT NULL 
);注意:数字表没有任何索引,也没有主键,并且包含1,000,000行. 试验台临时表: IF OBJECT_ID('tempdb.dbo.#Words') IS NOT NULL
DROP TABLE #Words;
GO
CREATE TABLE #Words 
(
    Word VARCHAR(500) NOT NULL
);
INSERT INTO #Words(Word) 
SELECT o.name + REVERSE(w.name)
FROM sys.objects o
CROSS APPLY (
    SELECT o.name
    FROM sys.objects o
) w;在我的测试系统上,上面的INSERT导致将16900行插入到#Words表中. 为了测试这两种变化,我设置了STATISTICS IO,TIME ON;并使用以下内容: SELECT w.Word,p.IsPalindrome
FROM #Words w
    CROSS APPLY dbo.IsPalindrome(w.Word) p
ORDER BY w.Word;
SELECT w.Word,p.IsPalindrome
FROM #Words w
    CROSS APPLY dbo.InlineIsPalindrome(w.Word) p
ORDER BY w.Word;我期望InlineIsPalindrome版本明显更快,但是以下结果不支持该假设. 多语句TVF: 
 内联TVF: 
 执行计划如下: 在这种情况下,为什么内联变量比多语句变量慢得多? 在回应@AaronBertrand的评论时,我修改了dbo.InlineIsPalindrome函数,以限制CTE返回的行与输入字的长度相匹配: CREATE FUNCTION dbo.InlineIsPalindrome
(
    @Word NVARCHAR(500)
)
RETURNS TABLE
WITH SCHEMABINDING
AS RETURN (
    WITH Nums AS
    (
      SELECT
        N = number
      FROM
        dbo.Numbers
      WHERE 
        number <= LEN(@Word)
    )
    SELECT
      IsPalindrome =
        CASE
          WHEN EXISTS
          (
            SELECT N
            FROM Nums
            WHERE N <= L / 2
              AND SUBSTRING(S,L)
);正如@MartinSmith建议的那样,我已经在dbo.Numbers表中添加了一个主键和聚簇索引,这肯定有助于并且更接近人们期望在生产环境中看到的内容. 现在重新运行上面的测试会产生以下统计信息: 交叉申请dbo.IsPalindrome(w.Word)p: 
 dbo.FunctionIsPalindrome(w.Word): 
 交叉申请dbo.InlineIsPalindrome(w.Word)p: 
 我在SQL Server 2012 SP3,v11.0.6020,Developer Edition上测试了这个. (编辑:源码网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! | 

