Sql server 在SQL Server中从多个表中删除多条记录的最佳做法
有一个包含数百万条记录的父表和三个外键指向父表主键的子表。像这样:Sql server 在SQL Server中从多个表中删除多条记录的最佳做法,sql-server,database,sql-server-2014,spring-jdbc,Sql Server,Database,Sql Server 2014,Spring Jdbc,有一个包含数百万条记录的父表和三个外键指向父表主键的子表。像这样: Parent parent_id (PK) \ Child1 | child1_id (PK) |---- parent_id (FK) | | Child2 | child2_id (PK) |
Parent
parent_id (PK) \ Child1
| child1_id (PK)
|---- parent_id (FK)
|
| Child2
| child2_id (PK)
|---- parent_id (FK)
|
| Child3
| child3_id (PK)
|---- parent_id (FK)
从父项
中硬删除数十万条记录的最佳做法是什么?我想在以下条件下删除:delete FROM PARENT,其中[STATUS]=“DONE”
。是否有一种方法在执行删除时不锁定表?以便在所有这些表中插入其他记录?
我能想到的选择是:
CASCADE DELETE
更新父集合[DELETED]=1,其中[STATUS]='DONE'
,删除具有这些父ID的每个子项,然后硬删除父项并提交[deleted]
列从[STATUS]=“DONE”
的父项中选择父项\u id,然后通过所有这些id执行批量删除。(这个性能非常差,所以我放弃它)我使用的是SQL Server 2014和spring jdbc。我更喜欢使用TOP x批量删除 因此,对于每个子表:
DELETE TOP 10000
FROM child1
FROM child 1 as c1
INNER join parent
On parent_Id = c1.parent_id
AND parent.[STATUS] = 'DONE'
对每个子表重复多个批次
可以定期删除没有子记录的父记录
DELETE TOP 10000
FROM parent
FROM parent as p
Left outer join child1 c1
On p.parent_Id = c1.parent_id
AND c1.child_id IS NULL
Left outer join child2 c2
On p.parent_Id = c2.parent_id
AND c2.child_id IS NULL
Left outer join child3 c3
On p.parent_Id = c3.parent_id
AND c3.child_id IS NULL
WHERE parent.[STATUS] = 'DONE'
每个父级有多少子级将决定您运行父级删除的频率。当然,你可以改变X,我会测试的很小,然后增加到50000
是否有一种方法在执行删除时不锁定表
对。正如您所建议的,分批操作而不是一次对数百万条记录进行操作将改进并发访问
我从不使用级联删除,因为它是阴险的:它可以很好地处理大量的行,但对数以百万计的行停止。我从不使用TOP-any,因为它是不合逻辑的:它使用任意数字,而不是数据的某个方面
每次我写这样的程序时,我都使用相同的技术。从底部开始,循环沿主键删除数据的子集。当delete返回0个受影响的行时,移动到下一个表,依此类推,直到可以删除顶行,不留下悬空引用。基本删除如下所示:
while @nrows > 0 begin
delete from Child3
where -- limitation criteria -- and
parent_id = (
select min(parent_id)
from Parent
where Status = 'DONE'
)
set @nrows = @@rowcount
done
如果您不能一次删除一个parent\u id
的所有行,出于性能原因,请查找一些限制子集,然后循环该子集。也许是一个日期,一次删除一个月或一年。如果您可以一次删除多个父项,请一次选择其中的一个子集,并使用exists
而不仅仅是最小值
幸运的是,出于这个目的,您不需要用户定义的事务。不管怎样,行都是toast,您可以在任何位置、任何时间重新启动,无论是否存在任何“DONE”父级 我建议对外键使用级联删除,每次删除多达50000条记录。删除大量的记录通常会在把它分解成更小的批次时加速。我是一个测量操作进度的爱好者,所以我会考虑编写一个程序来删除小部分的记录。要么继续级联删除,要么自己做。我不能只做
删除前10000名。。。其中parent.[STATUS]=“DONE”
因为可以插入新的“DONE”记录,我不想删除这些记录。我可能会将要删除的所有记录的id保存在一个表变量或临时表中,然后按照您的建议批量删除。在where语句中添加一个子句,按日期限制或按id排序,以确保只删除较旧的记录,怎么样