最快速的大规模更新方式

时间:2010-06-02 02:28:20

标签: sql sql-server tsql

假设您有一个包含大约500万条记录的表格,以及一个填充了大量文本数据的nvarchar(max)列。您希望以尽可能最快的方式将此列设置为NULL SomeOtherColumn = 1

蛮力UPDATE在这里效果不佳,因为它会创建大型隐式事务并永远占用。

一次只能进行小批量50K记录的更新,但是在32核/ 64GB服务器上完成仍需要47个小时。

有没有办法更快地完成此更新?是否有任何神奇的查询提示/表格选项牺牲其他东西(如并发)以换取速度?

注意:创建临时表或临时列不是一个选项,因为此nvarchar(max)列涉及大量数据,因此占用大量空间!

PS:是的,SomeOtherColumn已被编入索引。

7 个答案:

答案 0 :(得分:8)

从我能看到的一切看来,你的问题与索引无关。

关键似乎是你的nvarchar(max)字段包含“大量”数据。考虑一下SQL为了执行此更新必须执行的操作。

由于您要更新的列可能超过8000个字符,因此它存储在页外,这意味着当该列不为NULL时,需要额外的努力来读取此列。

当您运行一批50000次更新时,SQL必须将其置于隐式事务中,以便在出现任何问题时可以回滚。为了回滚,它必须在事务日志中存储列的原始值。

假设(为简单起见)每列平均包含10,000个字节的数据,这意味着50,000行将包含大约500MB的数据,这些数据必须临时存储(在简单恢复模式下)或永久存储(在完全恢复模式下) )。

无法禁用日志,因为它会影响数据库的完整性。

我在我的狗慢桌面上运行了一个快速测试,运行甚至10,000的批次变得非常慢,但是将大小减少到1000行,这意味着临时日志大小大约为10MB,工作得非常好。

我加载了一个包含350,000行的表,并标记了50,000个用于更新的表。这在大约4分钟内完成,并且由于它线性扩展,你应该能够在我的1台2GB台式机上大约6小时内在我的狗慢台式机上更新你的全部5万亿行,所以我希望你的强大服务器支持更好的东西通过SAN或其他东西。

您可能希望将update语句作为select运行,只选择主键和大nvarchar列,并确保它以您期望的速度运行。

当然瓶颈可能是其他用户在服务器上锁定存储或内存上的内容或争用,但由于您没有提及其他用户,我将假设您在单用户模式下拥有数据库。

作为优化,您应确保事务日志位于与数据不同的物理磁盘/磁盘组上,以最大限度地缩短搜索时间。

答案 1 :(得分:4)

希望您已经将要设置为null的列上的所有索引都删除,包括全文索引。如前所述,暂时关闭事务和日志文件就可以了。备份数据通常也会截断日志文件。

答案 2 :(得分:3)

您可以将数据库恢复模式设置为Simple以减少日志记录,但如果不考虑生产环境的全部影响,请不要这样做。

桌子上有哪些索引?鉴于批量更新约。 50,000行需要很长时间,我会说你需要一个索引。

答案 3 :(得分:1)

您是否尝试过在someOtherColumn上放置索引或统计信息?

答案 4 :(得分:1)

这对我很有帮助。我用了2个小时到20分钟。

/* I'm using database recovery mode to Simple */
/* Update table statistics */

set transaction isolation level read uncommitted     

/* Your 50k update, just to have a measures of the time it will take */

set transaction isolation level READ COMMITTED

根据我的经验,在MSSQL 2005中工作,每天(自动)将4百万个46字节记录(尽管没有nvarchar(最大值))从数据库中的一个表移动到另一个表中的另一个表大约需要20分钟QuadCore 8GB,2Ghz服务器,它不会损害应用程序性能。通过移动我的意思是INSERT INTO SELECT然后删除。 CPU使用率永远不会超过30%,即使被删除的表具有28M记录并且它每分钟不断地进行4K插入但没有更新。嗯,这是我的情况,它可能会因服务器负载而异。

READ UNCOMMITTED

“指定语句(您的更新)可以读取已被其他事务修改但尚未提交的行。”就我而言,记录是只读的。

我不知道rg-tsql是什么意思,但here你会在MSSQL中找到有关事务隔离级别的信息。

答案 5 :(得分:0)

尝试索引'SomeOtherColumn'... 50K记录应该快速更新。如果已经存在索引,请查看是否需要重新组织索引以及是否已为其收集统计信息。

答案 6 :(得分:0)

如果您运行的生产环境没有足够的空间来复制所有表格,我相信您迟早会找麻烦。

如果您提供SomeOtherColumn = 1的行数信息,或许我们可以采用另一种方式,但我建议:

0)备份你的桌子 1)索引标志列 2)将表选项设置为“无日志转换”...如果可行 3)编写存储过程来运行更新

相关问题