可能拖延 UPDATE x SET y = NULL 语句

Possibly stalling UPDATE x SET y = NULL statement

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

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

我们使用 table 锁和 READ UNCOMMITTED 隔离级别再次尝试查询,但无济于事(又三个小时后取消)。

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

table 在这些操作期间并发访问恰好为零。

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

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

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

Mitch Schroeter 的 question linked by Stephan in the comments contains some useful pointers as to how to keep the dataset online during the operation. Especially see this answer 实质上是在传输发生时建立了一个将新旧 table 联合起来的视图。

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

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 秒,这对于我们的场景来说似乎难以超越。

一些tips/comments:

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

结论:

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