如何从MS Server上的SQL中的几个相关表中删除大量数据

时间:2017-05-09 16:56:24

标签: sql sql-server inner-join

给定一个“主”表,它有一个主键,需要从中删除大量行(可能大约200M)。此外,还有大约30个与主表相关的“相关”表,并且还必须从每个表中删除相关行。预计需要从每个相关表中删除大约相当大的行数(或更多)。

当然可以更改条件来分区要删除的数据量,并运行几次,但无论如何,我需要一个有效的解决方案来实现这一点。

John Rees建议在Delete Large Number of Rows Is Very Slow - SQL Server 中的单个表中执行大量删除的方法,但问题在于它在单个表中执行多个事务删除。这可能会使db处于不一致状态。

John Gibb提出了一种从How do I delete from multiple tables using INNER JOIN in SQL server 中删除几个相关表的方法,但它没有考虑从这些表中删除的数据量大的可能性。

如何将这两个解决方案组合成一种从多个相关表中删除大量行的有效方法? (我是SQL的新手)

也许重要的是要注意,在这个问题的范围内,每个“相关”表只与“主”表相关

1 个答案:

答案 0 :(得分:1)

我认为这就是你之后......

在从主表中删除相同的4000行之前,这将从具有外键引用的表中删除4000行(假设为1:1)。

它将循环直到完成,或者它达到停止时间(如果启用)。

DECLARE @BATCHSIZE INT, @ITERATION INT, @TOTALROWS INT, @MAXRUNTIME VARCHAR(8), @BSTOPATMAXTIME BIT, @MSG VARCHAR(500)
SET DEADLOCK_PRIORITY LOW;
SET @BATCHSIZE = 4000
SET @MAXRUNTIME = '08:00:00' -- 8AM
SET @BSTOPATMAXTIME = 1 -- ENFORCE 8AM STOP TIME
SET @ITERATION = 0 -- LEAVE THIS
SET @TOTALROWS = 0 -- LEAVE THIS

IF OBJECT_ID('TEMPDB..#TMPLIST') IS NOT NULL DROP TABLE #TMPLIST
CREATE TABLE #TMPLIST (ID BIGINT)

WHILE @BATCHSIZE>0
BEGIN
    -- IF @BSTOPATMAXTIME = 1, THEN WE'LL STOP THE WHOLE JOB AT A SET TIME...
    IF CONVERT(VARCHAR(8),GETDATE(),108) >= @MAXRUNTIME AND @BSTOPATMAXTIME=1
    BEGIN
        RETURN
    END

    TRUNCATE TABLE #TMPLIST

    INSERT INTO #TMPLIST (ID)
    SELECT TOP(@BATCHSIZE) ID
    FROM MAINTABLE
    WHERE X=Y -- DELETE CRITERIA HERE...  

    SET @BATCHSIZE=@@ROWCOUNT

    DELETE T1
    FROM SOMETABLE1 T1
    WHERE EXISTS (SELECT 1 FROM #TMPLIST T WHERE T1.MAINID=T.ID)

    DELETE T2
    FROM SOMETABLE2 T2
    WHERE EXISTS (SELECT 1 FROM #TMPLIST T WHERE T2.MAINID=T.ID)

    DELETE T3
    FROM SOMETABLE3 T3
    WHERE EXISTS (SELECT 1 FROM #TMPLIST T WHERE T3.MAINID=T.ID)

    DELETE M
    FROM MAINTABLE M
    WHERE EXISTS (SELECT 1 FROM #TMPLIST T WHERE T3.MAINID=M.ID)

    SET @ITERATION=@ITERATION+1
    SET @TOTALROWS=@TOTALROWS+@BATCHSIZE
    SET @MSG = 'Iteration: ' + CAST(@ITERATION AS VARCHAR) + ' Total deletes:' + CAST(@TOTALROWS AS VARCHAR)
    RAISERROR (@MSG, 0, 1) WITH NOWAIT
END