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

SQL Azure标量函数性能优化:转内联表值函数需求

解决标量函数转内联表值函数的问题

核心思路

标量函数在SQL Azure中会触发逐行处理逻辑,导致严重性能瓶颈。转换为内联表值函数(iTVF) 能让查询优化器生成更高效的执行计划,关键是将原函数中的变量赋值、分支判断和最终输出修正逻辑全部转换为纯集合操作。

转换后的内联函数代码

CREATE FUNCTION [dbo].[udf_GetLSLineDescByGUIDLocalised_Inline] (
    @ComputationID INT,
    @AccountGUID UNIQUEIDENTIFIER,
    @LSCode NVARCHAR(50),
    @SpecificLevelOnly INT = -1,
    @LanguageID INT
)
RETURNS TABLE
AS
RETURN (
    WITH FormatTokenCTE AS (
        SELECT ResourceString AS FormatToken
        FROM dbo.tbl_ResourceString WITH(NOLOCK)
        WHERE ResourceKey = 'General.AccountSeparator' AND LanguageID = @LanguageID
    ),
    BSData AS (
        SELECT 
            CASE
                WHEN @SpecificLevelOnly > 0 THEN
                    CASE
                        WHEN @SpecificLevelOnly = 1 THEN dbo.udf_AccountName(l1.AccountGUID, l1.Description, @LanguageID)
                        WHEN @SpecificLevelOnly = 2 THEN dbo.udf_AccountName(l2.AccountGUID, l2.Description, @LanguageID)
                        WHEN @SpecificLevelOnly = 3 THEN dbo.udf_AccountName(l3.AccountGUID, l3.Description, @LanguageID)
                        WHEN @SpecificLevelOnly = 4 THEN dbo.udf_AccountName(l4.AccountGUID, l4.Description, @LanguageID)
                        WHEN @SpecificLevelOnly = 5 AND ls.Level5ID <> 0 THEN dbo.udf_AccountName(ls.AccountGUID, ls.Description, @LanguageID)
                    END
                ELSE
                    CASE
                        WHEN l2.Description IS NULL THEN dbo.udf_AccountName(l1.AccountGUID, l1.Description, @LanguageID)
                        ELSE dbo.udf_AccountName(l1.AccountGUID, l1.Description, @LanguageID) + ft.FormatToken
                    END +
                    CASE
                        WHEN NULLIF(l2.Description, 'BLANK') IS NULL THEN ''
                        WHEN l3.Description IS NULL THEN dbo.udf_AccountName(l2.AccountGUID, l2.Description, @LanguageID)
                        ELSE dbo.udf_AccountName(l2.AccountGUID, l2.Description, @LanguageID) + ft.FormatToken
                    END +
                    CASE
                        WHEN l3.Description IS NULL THEN ''
                        WHEN ls.Level4ID = 0 THEN dbo.udf_AccountName(l3.AccountGUID, l3.Description, @LanguageID)
                        ELSE dbo.udf_AccountName(l3.AccountGUID, l3.Description, @LanguageID) + ft.FormatToken
                    END +
                    CASE
                        WHEN l4.Description IS NULL THEN ''
                        WHEN ls.Level5ID = 0 THEN dbo.udf_AccountName(l4.AccountGUID, l4.Description, @LanguageID)
                        ELSE dbo.udf_AccountName(l4.AccountGUID, l4.Description, @LanguageID) + ft.FormatToken
                    END +
                    CASE
                        WHEN ls.Level5ID <> 0 THEN dbo.udf_AccountName(ls.AccountGUID, ls.Description, @LanguageID)
                        ELSE ''
                    END
            END AS RawOutput,
            ft.FormatToken
        FROM tbl_ScheduleBS ls WITH(NOLOCK)
        CROSS JOIN FormatTokenCTE ft
        LEFT JOIN dbo.tbl_ScheduleBS l1 WITH(NOLOCK)
            ON ls.ComputationID = l1.ComputationID
            AND ls.Level1ID = l1.Level1ID
            AND l1.Level2ID = 0
        LEFT JOIN dbo.tbl_ScheduleBS l2 WITH(NOLOCK)
            ON ls.ComputationID = l2.ComputationID
            AND ls.Level1ID = l2.Level1ID
            AND ls.Level2ID = l2.Level2ID AND l2.Level2ID <> 0
            AND l2.Level3ID = 0
        LEFT JOIN dbo.tbl_ScheduleBS l3 WITH(NOLOCK)
            ON ls.ComputationID = l3.ComputationID
            AND ls.Level1ID = l3.Level1ID
            AND ls.Level2ID = l3.Level2ID AND l3.Level2ID <> 0
            AND ls.Level3ID = l3.Level3ID AND l3.Level3ID <> 0
            AND l3.Level4ID = 0
        LEFT JOIN dbo.tbl_ScheduleBS l4 WITH(NOLOCK)
            ON ls.ComputationID = l4.ComputationID
            AND ls.Level1ID = l4.Level1ID
            AND ls.Level2ID = l4.Level2ID AND l4.Level2ID <> 0
            AND ls.Level3ID = l4.Level3ID AND l4.Level3ID <> 0
            AND ls.Level4ID = l4.Level4ID AND l4.Level4ID <> 0
            AND l4.Level5ID = 0
        WHERE ls.ComputationID = @ComputationID
            AND ls.AccountGUID = @AccountGUID
            AND @LSCode = 'BS'
    ),
    OtherLSCode AS (
        SELECT 
            NULL AS RawOutput,
            ft.FormatToken
        FROM FormatTokenCTE ft
        WHERE @LSCode <> 'BS'
    )
    SELECT 
        CASE
            WHEN RawOutput LIKE ft.FormatToken + '%' THEN STUFF(RawOutput, 1, LEN(ft.FormatToken), '')
            ELSE RawOutput
        END AS OutputDesc
    FROM (
        SELECT RawOutput, FormatToken FROM BSData
        UNION ALL
        SELECT RawOutput, FormatToken FROM OtherLSCode
    ) AS Combined
);

关键转换细节

  • CTE替代变量赋值:用FormatTokenCTE获取分隔符,避免DECLARE变量,符合内联函数纯集合操作的要求。
  • 分支逻辑转为UNION ALL:原函数中50个IF分支(示例仅展示BS),每个分支对应一个子查询,通过UNION ALL合并所有分支结果。
  • 整合输出修正逻辑:将原函数末尾的@Output前缀修正逻辑直接嵌入SELECT语句,用LEN(ft.FormatToken)替代硬编码的3,适配不同长度的分隔符。
  • 保留原逻辑完整性:所有原有的CASE判断、JOIN条件和函数调用完全保留,确保输出结果与原标量函数一致。

调用方式

原查询中调用标量函数的位置,改为用CROSS APPLY或LEFT JOIN调用内联函数:

-- 示例调用
SELECT 
    main.*,
    descFn.OutputDesc
FROM YourMainTable main
CROSS APPLY dbo.udf_GetLSLineDescByGUIDLocalised_Inline(
    main.ComputationID,
    main.AccountGUID,
    main.LSCode,
    main.SpecificLevelOnly,
    main.LanguageID
) descFn;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 21:50:35