Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/database/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql server 在SQL Server中从多个表中删除多条记录的最佳做法_Sql Server_Database_Sql Server 2014_Spring Jdbc - Fatal编程技术网

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的每个子项,然后硬删除父项并提交
  • 类似于2。但使用过程并将要删除的ID保存在表变量中,这样我就不需要向父表添加新的
    [deleted]
  • 选择要删除的id
    从[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排序,以确保只删除较旧的记录,怎么样