从SQL Server中的多个表中删除许多记录的最佳实践

时间:2016-07-23 08:46:21

标签: sql-server database sql-server-2014 spring-jdbc

拥有包含数百万条记录和三个子表的父表,外键指向父表的主键。像这样:

  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'。有没有办法在删除发生时不锁定表格?那么其他记录可以插入所有这些表中吗? 我能想到的选择:

  1. 在外键上使用CASCADE DELETE
  2. 使用软删除:启动事务UPDATE parent SET [DELETED] = 1 WHERE [STATUS] = 'DONE',删除具有这些父ID的每个子项,然后硬删除父项并提交。
  3. 类似于2.但是使用一个过程并将这些ID保存在表变量中,这样我就不需要在[DELETED]表中添加新的Parent列。
  4. 选择要删除的ID SELECT parent_id FROM parent WHERE [STATUS] = 'DONE',然后通过所有这些ID进行批量删除。 (这非常糟糕,所以我放弃了它。)
  5. 我正在使用SQL Server 2014和spring jdbc。

2 个答案:

答案 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而不是最小值。

幸运的是,为此您不需要用户定义的交易。无论如何,这些行都是吐司,无论是否有任何“完成”行,您都可以随时随地重新启动。父母仍然存在。