过度更新有多糟糕?
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”来创建。将现有列更新为自身;即使值没有改变,更新也会在约束上失败。
【讨论】:
以上是关于过度更新有多糟糕?的主要内容,如果未能解决你的问题,请参考以下文章