可能正在暂停UPDATE x SET y=NULL语句



我们已经否决了一项功能,并且正在清除一些数据。在完全删除一个列(这将需要太多的即时应用程序开发)之前,我们希望简单地清除它所包含的数据(应用程序支持的数据)。

然而,一个简单的UPDATE foo SET bar = NULL似乎异常昂贵。在数据库的测试副本中,它运行了三个多小时,然后我们取消了它

我们使用表锁和READ UNCOMMITTED隔离级别再次尝试查询,但没有成功(三个小时后取消)。

该表包含大约112000行,每行的列包含大约41400个字节(因此我们正在清除超过4GiB的数据)。虽然这是相当多的数据,但我们突然想到,将剩余的列复制到一个新表中,删除旧表并重命名新表实际上已经更快了。请注意,我们不知道UPDATE需要多少时间才能完成,否则,我们在3小时停止,但可能是每天5、6、12。

在这些操作过程中,该表的并发访问次数为零。

有人对我们的情况有什么建议吗?复制+删除+重命名真的是最好的方法吗?如果是的话,有什么特别的建议可以让它尽可能安全?

我们的一个可能天真的假设是,如果给出足够宽松的提示,DBMS将能够在正常UPDATE语句的幕后制定复制/交换策略。有可能吗?

我们最终复制并交换了表。

Stephan在评论中链接的问题包含了一些有用的指针,说明如何在操作过程中保持数据集在线。尤其是Mitch Schroeter的回答,它基本上建立了一种观点,即在转会期间将新旧桌子统一起来。

因为我们不需要让数据集保持在线,所以这太过分了(尤其是考虑到数据集的其余部分非常小)。相反:

CREATE TABLE _foobar (id INT IDENTITY PRIMARY KEY, foo INT, bar INT NULL);
SET IDENTITY_INSERT _foobar ON;
INSERT _foobar (id, foo, bar) SELECT id, foo, NULL FROM foobar;
SET IDENTITY_INSERT _foobar OFF;
DROP TABLE foobar;
EXECUTE sp_rename '_foobar', 'foobar';

整个行动耗时14秒,这对于我们的场景来说似乎很难击败。

一些提示/评论:

  • 确保CREATE TABLE语句生成匹配的模式(例如,使用VS或SSMS等工具)
  • 不要忘记IDENTITY列。这意味着您需要为INSERT语句显式地编写列列表,当然还需要为表设置IDENTITY_INSERT。有关详细信息,请参阅MSDN文档

结论:

  • 根据这一点,似乎没有简单的方法将一个正常的UPDATE事务拆分为多个事务,以在更高级别管理一致性。正如那里和HABO所建议的那样,所有解决方案似乎都需要在每个批次上扫描请求的谓词,或者使用临时表一次性存储与谓词匹配的行的关键字,并将其用于每个批次(由于PK总是被索引的,所以应该总是更快)
  • 似乎也没有简单的方法可以在保持操作在线的同时进行复制/交换。再次,请参阅此处,了解手动设置统一视图的方法
  • 如果数据集的其余部分很小(很快就可以完整复制),并且不需要保持在线,则可以使用上面更简单的方法。免责声明:如果你有DBA,请咨询你的DBA,如果你不能100%确定自己在做什么,这可能会很危险

最新更新