0

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

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

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

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

我更新了示例表,所以我没有得到更多的规范化评论。每本书只有 1 个描述:)

4

2 回答 2

2

NOLOCK您可以通过在 SQL 查询上使用或READUNCOMITTED提示来防止查询端的阻塞。

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

于 2013-02-03T15:55:55.670 回答
0

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

CREATE INDEX IDX_BookID ON #BookUpdates(BookID)

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

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

于 2013-02-03T16:01:13.343 回答