拥有包含数百万条记录和三个子表的父表,外键指向父表的主键。像这样:
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)
从Parent
硬删除数十万条记录的最佳做法是什么?我想删除以下条件:DELETE FROM PARENT WHERE [STATUS] = 'DONE'
。有没有办法在删除发生时不锁定表格?那么其他记录可以插入所有这些表中吗?
我能想到的选择:
CASCADE DELETE
。UPDATE parent SET [DELETED] = 1 WHERE [STATUS] = 'DONE'
,删除具有这些父ID的每个子项,然后硬删除父项并提交。[DELETED]
表中添加新的Parent
列。 SELECT parent_id FROM parent WHERE [STATUS] = 'DONE'
,然后通过所有这些ID进行批量删除。 (这非常糟糕,所以我放弃了它。)我正在使用SQL Server 2014和spring jdbc。
答案 0 :(得分:1)
我更喜欢使用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
答案 1 :(得分:1)
有没有办法在发生删除时不锁定表格?
是。正如您所建议的那样,一次批量操作而不是一次运行数百万条记录将改善并发访问。
我从不使用级联删除,因为它是阴险的:它可以很好地处理多个行,但是数百万人会感冒。而且我从不使用TOP,因为它不合逻辑:它使用任意数字而不是数据的某些方面。
每次我写这样的程序时,我都使用了相同的技术。从底部开始,循环沿主键删除数据的子集。当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_id
的所有行,出于性能原因,请找到一些限制子集,并在其上循环。也许是约会,一次删除一个月或一年。如果您可以一次删除多个父项,请一次选择一个子集,并使用exists
而不是最小值。
幸运的是,为此您不需要用户定义的交易。无论如何,这些行都是吐司,无论是否有任何“完成”行,您都可以随时随地重新启动。父母仍然存在。