use*_*455 4 sql-server delete partitioning table
我们有一个相当大的 MS SQL 数据库,有数百万行。我创建了一个简单的脚本来删除超过 1 个月的行,但这似乎锁定了表并给应用程序带来了麻烦。
该表有一个索引的“ID”PK,还有一个我将用于此任务的“日期”列。
在不导致锁定的情况下执行此操作的最佳方法是什么?我正在考虑分区,但不确定它是否是最好的方法。提前致谢。
Ste*_*o64 10
您需要批量删除行以避免锁升级。当 SQL Server 从行锁或页锁切换到锁定整个表时,就会发生锁升级。当 SQL Server 检测到大量行锁或页锁已被占用时,锁升级可以节省内存,并且需要更多行锁或页锁来完成操作。这可能就是您遇到阻塞问题的原因。如果我没记错的话,当涉及超过 5,000 行时,行锁会升级为表锁。
如果 ID 列也是聚集索引,您可能会受益于使用 ID 列执行删除而不是使用日期列。为此,获取您要使用的日期的 ID 值,然后循环删除每批少于 5,000 行的行,其中 ID 值小于或等于所需的 ID。这仅适用于假设行按日期顺序插入的情况,这样递增的 ID 值与递增的日期值匹配。
您可以DELETE
通过检查@@rowcount
变量来确定受 影响的行数,并且可以使用 设置要影响的最大行数SET ROWCOUNT
,然后循环直到DELETE
不再删除行:
SET ROWCOUNT 4500;
DECLARE @i int;
SELECT @i = 1;
WHILE @i > 0
BEGIN
Delete from dbo.my_table Where ID < 4356;
SELECT @i = @@rowcount;
END
Run Code Online (Sandbox Code Playgroud)
消除使用已弃用 SET ROWCOUNT
语句的另一种方法是向查询添加TOP
子句DELETE
,如下所示:
DECLARE @i int = 1;
DECLARE @id int;
SET @id = COALESCE((
SELECT TOP(1) mt.ID
FROM dbo.my_table mt
WHERE mt.date < '2021-01-04T00:00:00.000'
ORDER BY mt.date DESC
), 0);
WHILE @i > 0
BEGIN
DELETE TOP(5000) mt
FROM dbo.my_table mt
WHERE mt.ID <= @ID;
SET @i = @@ROWCOUNT;
END
Run Code Online (Sandbox Code Playgroud)
在上面的代码中,我添加了一个查询来获取 2021 年 1 月 4 日或之前的行的最大 ID 值,只是为了说明这是如何工作的。
上述两种方法都会产生相同的结果,@ID
从表中删除给定值之前的所有行。锁定应该减少到使用行级锁,从而防止表锁导致其他并发进程阻塞。
作为替代方案,您可以查看数据库级别的读取提交快照隔离(RCSI),也称为行版本控制。RCSI 阻止写入者阻止读取者,但是使用行版本控制可能会产生许多影响。如果您决定走这条路,您应该彻底测试使用数据库的应用程序。在盲目启用 RCSI 之前,请仔细阅读并考虑对您的应用程序的其他影响。
归档时间: |
|
查看次数: |
1036 次 |
最近记录: |