循环SQL Server Update语句的性能不佳

时间:2016-09-16 14:55:03

标签: sql sql-server

所以我有一个存储过程需要定期更新一个包含大约7000万条记录的大表。我通常总是遵循循环更新的标准,以避免锁定我的任何其他大表,并且我通常没有看到性能影响太大。

问题: 我看到,与没有循环逻辑的原始运行时相比,当我使用循环时,我的执行时间增加了10或20倍。

例如:

如果我要运行以下查询,我会在大约1.5分钟内更新300万条记录。

    UPDATE [db1].[dbo].[Preferences]
    SET LastUpdate = Getdate()
    WHERE
    LastUpdate >= CAST(CONVERT( Varchar(10), DATEADD(day,-1,GETDATE()), 110) as DateTime) 
    AND 
    LastUpdate < CAST(CONVERT( Varchar(10), GETDATE(), 110) as DateTime)
    AND (@PreferenceID is null or @PreferenceID = PreferenceID)

这是我的常规更新语句,后面没有循环机制。基本上,参数@PreferenceID要么提供ID,要么保留为null。根据它,它将更新今天所有lastUpdate的日期或仅更新一个preferenceID。在我的测试用例中,我使用了1个preferenceID,因此正在填充@PreferenceID。

所以当我添加循环到这个语句时,它从1.5分钟到20分钟。

以下是循环语句:

BEGIN
    SET ROWCOUNT  10000

        UPDATE [DB1].[dbo].[Preferences]
        SET LastUpdate = Getdate()
        WHERE
        LastUpdate >= CAST(CONVERT( Varchar(10), DATEADD(day,-1,GETDATE()), 110) as DateTime) 
        AND 
        LastUpdate < CAST(CONVERT( Varchar(10), GETDATE(), 110) as DateTime)
        AND (@PreferenceID is null or @PreferenceID = PreferenceID)

   WHILE @@ROWCOUNT > 0

        UPDATE [DB1].[dbo].[Preferences]
        SET LastUpdate = Getdate()
        WHERE
        LastUpdate >= CAST(CONVERT( Varchar(10), DATEADD(day,-1,GETDATE()), 110) as DateTime) 
        AND 
        LastUpdate < CAST(CONVERT( Varchar(10), GETDATE(), 110) as DateTime)
        AND (@PreferenceID is null or @PreferenceID = PreferenceID)


SET ROWCOUNT  0
END

所以我的核心问题是为什么我的执行时间会因为一次循环10k记录而增加太多?我可以发布有关表结构的更多详细信息,但我不确定这是否只是一个坚定的规则,与仅仅一次完整批量更新相比,它将成为循环更新的性能影响。

提前感谢任何人可以提供的建议。

2 个答案:

答案 0 :(得分:2)

所以,我怀疑这个速度较慢,因为在每个循环中你的查询必须找出要更新的记录集,即评估这个:

Stopping

我还会注意到,您的第二次更新与第一次更新完全不同 - 尝试在一天午夜之前运行这两种更新 - 您将在第二组更新中获得不同的结果。

答案 1 :(得分:1)

您可以将所有内容保存在变量中,并尝试循环

DECLARE @dt DATETIME =  CAST(CONVERT( Varchar(10), GETDATE(), 110) as DateTime)
DECLARE @dtAdd DATETIME = CAST(CONVERT( Varchar(10), DATEADD(day,-1,GETDATE()), 110) as DateTime) 

UPDATE [DB1].[dbo].[Preferences]
    SET LastUpdate = @dt
    WHERE
    LastUpdate >= @dtAdd
    AND 
    LastUpdate < @dt
    AND (@PreferenceID is null or @PreferenceID = PreferenceID)