【问题标题】:Performing SQL updates in single statements vs batches在单个语句与批处理中执行 SQL 更新
【发布时间】:2013-01-18 09:43:31
【问题描述】:

我正在处理大型数据库,需要有关如何优化我的选择/更新的建议。这是一个前任:

create table Book (
   BookID int,
   Description  nvarchar(max)
)
-- 8 million rows

create table #BookUpdates (
   BookID int,
   Description  nvarchar(max)
)
-- 2 million rows

假设有 800 万本书籍,我必须更新其中 200 万本的类型。

问题:运行这些更新的时间很长。它偶尔会导致那些也试图从数据库运行语句的用户阻塞。我想出了一个解决方案,但想知道是否有更好的解决方案。我必须准备很多这样的一次性随机更新(无论出于何种原因)

-- normal update
update b set b.Description = bu.Description
from Book b
join #BookUpdates bu
   on bu.BookID = b.BookID

-- batch update
while (@BookID < @MaxBookID)
begin
   update b set b.Description = bu.Description
   from Book b
   join #BookUpdates bu
      on bu.BookID = b.BookID
   where bu.BookID >= @BookID
      and bu.BookID < @BookID + 5000

   set @BookID = @BookID + 5000
end

第二次更新速度更快。我喜欢这个解决方案,因为我可以向自己打印状态更新,了解它还剩多长时间,而且不会对我们的客户造成性能问题。

问题:我在这里遗漏了什么重要的东西吗?临时表上的索引?

我更新了EXAMPLE 表,所以我没有得到更多的标准化cmets。每本书只有 1 个描述:)

【问题讨论】:

  • 我们在谈论哪个 RDBMS? SQL Server 看起来,但只是为了确定。您能否按现在的方式显示更新的查询计划?
  • SQL 服务器。我没有查询计划,所以当我这样做时,我可能会重新发布问题。我们的数据库真的很慢,所以需要一段时间才能找到 BookID。索引会有帮助吗?
  • 两个连接 ID 上的索引几乎总是有助于加快速度,但如果没有看到实际计划就很难确定。
  • 更新主表后,bookUpdate 表怎么办?你清除更新了吗?

标签: sql performance stored-procedures


【解决方案1】:

您可以通过在 SQL 查询中使用 NOLOCKREADUNCOMITTED 提示来防止查询端阻塞。

性能的真正问题可能是日志中变化的累积。您以 5,000 组为一组进行更改的方法非常合理。因为是在批处理表中设置更新,所以不妨先计算一下表中的批处理号,然后在此基础上进行循环。

【讨论】:

    【解决方案2】:

    我会先尝试您自己的建议,并在您运行更新之前为临时表编制索引:

    CREATE INDEX IDX_BookID ON #BookUpdates(BookID)
    

    尝试使用索引和不使用索引,看看对运行时的影响是什么。如果您想避免影响您的用户进行此测试,请在工作时间之外运行它(如果可以的话)或先将 Book 复制到另一个临时表并对其进行测试。

    无论如何,考虑到数量,我希望您仍然会导致其他进程阻塞。如果您无法在没有其他进程针对此表运行的时候安排更新(这将是理想的解决方案),那么您现有的批量更新似乎是一个完全有效的解决方案。为临时表建立索引也可能对此有所帮助,因此您可以增加批量大小而不会导致阻塞。

    【讨论】:

      猜你喜欢
      • 2015-10-25
      • 1970-01-01
      • 2014-10-23
      • 2015-07-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-05-13
      • 2010-10-26
      相关资源
      最近更新 更多