我正在使用大型数据库,需要有关如何优化我的选择/更新的建议。这是一个例子:
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表,因此我没有获得更多的规范化注释。每本书只有1个描述:)
答案 0 :(得分:2)
您可以通过对SQL查询使用NOLOCK
或READUNCOMITTED
提示来阻止查询方面的阻止。
性能的真正问题可能是日志中的更改积累。您以5,000为一组批量更改的方法非常合理。因为您要在批处理表中设置更新,所以您也可以计算表中的批号,然后根据它进行循环。
答案 1 :(得分:0)
我会首先尝试你自己的建议,然后在运行更新之前索引临时表:
CREATE INDEX IDX_BookID ON #BookUpdates(BookID)
尝试使用索引而不使用索引,看看对运行时的影响是什么。如果您想避免影响用户进行此测试,请在工作时间以外运行(如果可以)或先将Book复制到另一个临时表并对其进行测试。
无论如何,考虑到音量,我预计你仍然会阻止其他进程。如果您无法在没有其他进程针对此表运行时安排更新(这将是理想的解决方案),则您现有的批量更新似乎是一个完全有效的解决方案。索引临时表也可能对此有所帮助,因此您可以增加批量大小而不会导致阻塞。