循环与调用函数的 SQL 性能差异

Posted

技术标签:

【中文标题】循环与调用函数的 SQL 性能差异【英文标题】:SQL Performance Difference of Looping vs Invoking a function 【发布时间】:2017-08-10 05:43:32 【问题描述】:

我有一个插入记录的存储过程。

我必须为具有特定逻辑的列计算日期值。目前我已经为插入的数据创建了一个循环,并进行计算以填充日期。

问题是我需要避免使用循环来插入数据,并且需要将它们作为批处理插入。为此,我必须将日期计算逻辑移至函数中。

循环数据(当前有)和使用函数在性能方面会有什么不同。

这是我的存储过程:

WHILE @C <= @WeeklyDataCount
BEGIN
    DECLARE @PopulateDate DATE;

    SELECT 
        @Value = D.Value, 
        @FromDate = D.FromDate
    FROM 
        #WeeklyData D
    WHERE 
        D.AutoId = @C;

    -- Sample Date calculation logic that needs to move to a function
    @DayCount = SELECT COUNT(*)
                FROM DayTable

    @Counter2 = 1;

    WHILE @Counter2 < @DayCount
    BEGIN
        SET @PopulateDate = DATEADD(DAY, (-1 * @Counter2), @FromDate);
        SET @Counter2 = @Counter2 + 1;
    END
    -- End of Day Calculation Logic

    INSERT INTO TABLE1 (Value, PopulateDay)  
    VALUES(@Value, @PopulateDate)

    SET @C= @C +1;
END

【问题讨论】:

一般来说,使用 SQL 应该避免循环。如果没有样本数据(最好是 DDL+DML)和期望的结果,很难给出准确的答案。 (Some logic) 你能告诉我们它是什么吗?也许可以用一些“吸引人”的语句替换整个循环。 @Rokuto - 我已经更新了答案 你的内循环可以改写为SET @PopulateDate = DATEADD(DAY,(-1 * ((@DayCount*(@DayCount - 1))/2)),@FromDate);(link公式,它是n个连续自然数乘以-1的总和)。 正如 Zohar 所说,您应该避免使用游标和 while 循环。如果可能且不必要(如您的情况),请避免逐行处理,因为 SQL Server 引擎(和其他 DBMS)能够通过集合执行得非常好和快速。 Here 是关于循环、游标和基于集合的方式性能比较的文章。 【参考方案1】:

您的整个循环可以用一个语句替换(我假设表 DayTable#WeeklyData 中的每一行都相等)。

INSERT INTO TABLE1 (Value,PopulateDay)
SELECT
    D.Value,
    DATEADD(DAY,(-1 * ((DayCount * (DayCount - 1))/2)),D.FromDate)
FROM #WeeklyData D
CROSS JOIN (SELECT COUNT(*) AS DayCount FROM DayTable) C
    WHERE D.AutoId <= @WeeklyDataCount

【讨论】:

以上是关于循环与调用函数的 SQL 性能差异的主要内容,如果未能解决你的问题,请参考以下文章

使用LIKE子句正确格式化sql查询

JVM函数调用与从本机方法返回的性能?

存储过程 - 函数性能差异

SQL 连接与单表:性能差异?

Java 方法直接调用 vs 单元素循环调用

从 Matlab 调用的 Mex 函数和数值差异