【问题标题】:Is SQL Server smart enough not to UPDATE if values are the same?如果值相同,SQL Server 是否足够聪明而不会更新?
【发布时间】:2012-02-26 05:38:36
【问题描述】:

在工作中,我们一直在破解一个存储过程,我们注意到了一些事情。

对于我们的一个更新语句,我们注意到如果这些值与之前的值相同,我们会获得性能提升。

我们没有说

UPDATE t1 SET A=5

列已经等于 5。我们正在做这样的事情:

UPDATE t1 SET A = Qty*4.3

无论如何,如果 UPDATE 操作中的值评估为相同,SQL Server 是否足够聪明,不会执行该操作,还是我只是被其他一些现象愚弄了?

【问题讨论】:

    标签: sql-server database-performance


    【解决方案1】:

    从 TSQLs 输出来看,即使是相同的值,它也会认为 UPDATE 已执行。

    CREATE TABLE test (id INT, val int);
    GO
    
    INSERT INTO test VALUES(1, 1);
    GO
    (1 row(s) affected)
    
    UPDATE test SET val=1 WHERE id=1;
    GO
    (1 row(s) affected)
    

    当涉及到实际的磁盘写入时,我当然希望不需要它。

    编辑:请参阅@AbeMiessler 的答案,以更深入地分析写入日志/磁盘部分的工作原理。

    【讨论】:

    • 问题分析得很好,顺便说一句
    • 我认为写入磁盘不会立即发生。我认为问题是“页面是否被标记为脏”
    • @ChrisDiver 好点,SQL 管理器没有显示我能找到的统计数据,因此删除该部分并推迟到 AbeMiessler 答案中的链接以获得明确的答案。
    【解决方案2】:

    SQL 在执行其他任何操作之前必须实际计算数值结果,它必须这样做以便知道它必须用什么值来“做某事”。即使这样,它也需要读取表中的值来进行比较。

    我想说的是,如果是这种情况,它实际上会降低读取值的效率,将其与您尝试更新的值进行比较,然后做出决定是否应该提交更新操作。在您的情况下,它必须先读取Qty,然后才能确定需要在A 字段中输入的内容,但即便如此,当它比较值时,它也可能已经完成更新并继续剩下的忙碌的一天:)

    【讨论】:

    • 我不同意。对于更新,它必须执行读取,以确认实际上有一行要更新,并在它可以发出更新之前对行和可能的索引加锁。因此,如果读取仍然完成,并且确定实际上没有数据被更改,它可以跳过实际的写入阶段。
    【解决方案3】:

    根据表索引的特定状态,您可能会看到一些性能提升。

    如果表已编入索引,并且更新不需要移动任何数据(集群)或不需要更改索引(非集群),那么您可能会看到收益。

    如果你告诉 SQL 更新,它就会更新。所以,我会着眼于硬件方面(例如,索引)。

    【讨论】:

      【解决方案4】:

      是的,您会看到一些性能提升。我建议阅读这篇文章以获得更好的理解(它将解释为什么比我能做到的更好):

      https://sqlkiwi.blogspot.com/2010/08/the-impact-of-non-updating-updates.html

      【讨论】:

        【解决方案5】:

        我必须自己进行测试才能看到。我想我会分享结果。

        首先,是的,即使值相同,也会发生更新。

        我创建了一个包含以下列的测试表:
        Key
        Value
        LastUpdatedTime

        然后我插入:

        INSERT INTO KeyValue VALUES ('TestKey1', 'TestValue1', GETDATE())
        

        然后我创建了一个触发器以在发生更新时更新LastUpdatedTime

        CREATE TRIGGER UpdateLastUpdatedTime 
           ON  KeyValue
           AFTER UPDATE
        AS 
        BEGIN
            SET NOCOUNT ON;
            DECLARE @key VARCHAR(50) = (SELECT [Key] FROM INSERTED)
            UPDATE KeyValue SET LastUpdatedTime = GETDATE() WHERE [Key] = @key
        END
        

        然后我对列进行了更新,并将其设置为与原来相同的值:

        UPDATE KeyValue Set [Value] = 'TestValue1' WHERE [Key] = 'TestKey1'
        

        LastUpdatedTime 确实已更新,因此触发了触发器。

        现在,我猜如果没有触发器,UPDATE 可能不会发生,但我猜它仍然会发生,特别是因为触发器是 AFTER UPDATE

        【讨论】:

          猜你喜欢
          • 2020-08-06
          • 2011-11-09
          • 2015-05-21
          • 2023-02-09
          • 1970-01-01
          • 1970-01-01
          • 2020-09-10
          • 1970-01-01
          • 2023-03-20
          相关资源
          最近更新 更多