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

Tsql 可能正在暂停UPDATE x SET y=NULL语句,tsql,azure-sql-database,Tsql,Azure Sql Database,我们已经弃用了一个功能,正在清除一些数据。在完全删除一个列之前(这将需要太多的即时应用程序开发),我们只想清除它包含的数据(应用程序支持这些数据) 然而,一个简单的更新foo SET bar=NULL似乎异常昂贵。在数据库的测试副本中,它运行了三个多小时,然后我们取消了它 我们再次尝试使用表锁和readuncommitted隔离级别进行查询,但没有成功(三小时后取消) 该表包含大约112000行,每行的列包含大约41400字节(因此我们正在清除超过4GiBs的数据)。虽然这是相当多的数据,但我们

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

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

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

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

在这些操作期间,表的并发访问量为零

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


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

我们最终复制并交换了表

注释中的包含一些有用的指针,说明如何在操作期间保持数据集联机。特别是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\u INSERT
    。有关详细信息,请参阅
结论:

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

记录交易的成本似乎比您预期的要高。尝试使用循环一次更新一个块,例如1000行。@HABO听起来不错,谢谢。查看这张表似乎不是一个“好”的方法(即,不需要为每个批次扫描表)。使用谓词(
条不是空的
)进行扫描需要很多时间(已经7分钟了,并且正在计数,这取决于批次的数量,加起来非常快)。我的猜测是因为列的大小,数据没有在行中内联。您知道拆分此类事务的惯用方法吗?常见的方法是
update。。。where FooId in(从Foo中选择top 1000 FooId,其中Bar不为NULL)
并循环,直到
@@RowCount
为零。在您的情况下,将适当的
FooId
s收集到一个临时表中并处理它,以避免重新扫描
Foo
。在处理临时表行时删除或标记这些行。在你找到一个(相对的)最佳点之前,尝试不同的块大小(例如100行)并没有坏处。试着从这里读一些答案@Stephan I do,谢谢。我喜欢unioned view方法,如果在操作过程中需要保持数据集在线,我们肯定会使用它。但是,由于我们没有这样做,所以我们采取了一点捷径,以一种更直接的方式重新构建了表(答案如下)。