过度更新有多糟糕?

Posted

技术标签:

【中文标题】过度更新有多糟糕?【英文标题】:How bad is overupdating? 【发布时间】:2011-07-13 17:45:29 【问题描述】:

我有以下查询,我想知道 CASE 构造有多糟糕,当 E.EAOpID 不为空时,它会强制 DB 引擎用 E.EAOpID 中已包含的值覆盖 E.EAOpID

UPDATE E
SET E.EAOpID =  CASE
                    WHEN E.EAOpID IS NULL THEN @operationID
                    ELSE E.EAOpID
                END,
    E.AverageCapacity = E.AverageCapacity + 1,
    E.Average = E.Average - (E.Average - E.Value) / E.AverageCapacity
FROM
(
    SELECT E.EAOpID, E.AverageCapacity, E.Average, P.Value
    FROM Probes AS P
    INNER JOIN Estimates AS E ON P.EstimateID = E.ID
    WHERE P.EAOpID = @operationID
) AS E;

也许将这个更新分成两个更新更便宜:

1

UPDATE E
SET E.EAOpID = @operationID
FROM
(
    SELECT E.EAOpID, E.AverageCapacity, E.Average, P.Value
    FROM Probes AS P
    INNER JOIN Estimates AS E ON P.EstimateID = E.ID
    WHERE   P.EAOpID = @operationID
        AND E.EAOpID IS NULL -- Additional statement here
) AS E;

2

UPDATE E
SET E.AverageCapacity = E.AverageCapacity + 1,
    E.Average = E.Average - (E.Average - E.Value) / E.AverageCapacity
FROM
(
    SELECT E.EAOpID, E.AverageCapacity, E.Average, P.Value
    FROM Probes AS P
    INNER JOIN Estimates AS E ON P.EstimateID = E.ID
    WHERE P.EAOpID = @operationID
) AS E;

【问题讨论】:

这张表上的索引是什么样的? 你为什么不使用 Profiler 测量每个的性能。这确实是确定您的查询性能以及将完成多少次读取/写入的唯一方法。 好的,我明白了,谢谢(目前没有索引,但是添加索引没问题,我担心理论问题) 除了 Randy 关于测试的观点,我想你会发现在很多情况下(除非有很多索引引用该列),检查值是否不同将是至少与不检查就覆盖它一样昂贵 - 特别是如果你最终不得不在大量实例中覆盖它。 关于“检查值是否不同”这不是关于速度,而是关于查询的逻辑,我需要检查它,因为我不希望它只在不同的情况下改变 【参考方案1】:

即使值没有更改,更新一行也只需要很少的资源。您可以通过检查更改来施加更多负载。当您的系统高度精炼并且您接近边缘时,您可能会考虑这样的优化,但它会在列表中排名靠后。

【讨论】:

【参考方案2】:

两次更新将使用几乎两倍的资源,因为您将读取/更新同一组行。最好在一个查询中包含所有内容。我不知道如何衡量 case 语句需要多少额外的处理,但我知道以下使用更少的编码逻辑执行相同数量的工作。改成

UPDATE E
 SET E.EAOpID =  CASE
                     WHEN E.EAOpID IS NULL THEN @operationID
                     ELSE E.EAOpID
                 END, 
 (etc)

UPDATE E
 SET E.EAOpID = isnull(E.EAOpID, @operationID), 
 (etc)

(如果你开心的话,你可以用coalesce代替isnull。)

【讨论】:

是的,我也觉得使用两次更新是比较耗资源的操作,顺便感谢ISNULL(...)...【参考方案3】:

您在表上使用的 SQL Server 功能越多,开销就越大,即使是无操作 UPDATE。

在索引维护之外执行操作和额外读取。

触发器(触发触发器)、外键(仍然检查完整性)、约束(检查规则)等

例如:向一个表添加一个约束,该约束会因某些现有值而失败,但使用“WITH NOCHECK”来创建。将现有列更新为自身;即使值没有改变,更新也会在约束上失败。

【讨论】:

以上是关于过度更新有多糟糕?的主要内容,如果未能解决你的问题,请参考以下文章

过度使用 DataTable 是否很糟糕?

使用 WITH 和过度分区困难更新表

糟糕的 SQL 读取性能(罪魁祸首更新统计数据?)

PHP到底有多糟糕?

热更新有多重要?游戏代码热更新杂谈

多次打开和关闭 SQL 连接有多糟糕?确切的效果是啥?