【问题标题】: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 关于测试的观点,我想你会发现在很多情况下(除非有很多索引引用该列),检查值是否不同将是至少与不检查就覆盖它一样昂贵 - 特别是如果你最终不得不在大量实例中覆盖它。
  • 关于“检查值是否不同”这不是关于速度,而是关于查询的逻辑,我需要检查它,因为我不希望它只在不同的情况下改变

标签: sql sql-server sql-server-2008 sql-optimization


【解决方案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”来创建。将现有列更新为自身;即使值没有改变,更新也会在约束上失败。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-11-24
      • 2011-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-12-09
      相关资源
      最近更新 更多