在SQL Server中删除1百万行

时间:2014-07-16 16:00:30

标签: sql-server

我正在处理客户端的数据库,由于软件中的错误,需要删除大约100万行。是否有一种有效的方法来删除它们:

DELETE FROM table_1 where condition1 = 'value' ?

8 个答案:

答案 0 :(得分:59)

这是上面建议的批量删除的结构。不要一次尝试1M ......

批处理的大小和waitfor延迟显然是可变的,并且取决于您的服务器功能以及缓解争用的需要。您可能需要手动删除某些行,测量它们的耗时,并将批量大小调整为服务器可以处理的内容。如上所述,超过5000的任何东西都可能导致锁定(我不知道)。

这最好在数小时之后完成......但是对于SQL来说,1M行真的不是很多。如果您在SSMS中观看消息,可能需要一段时间才能显示打印输出,但是经过几批后,请注意它不会实时更新。

修改:添加了停止时间@MAXRUNTIME& @BSTOPATMAXTIME。如果您将@BSTOPATMAXTIME设置为1,则脚本将在所需的时间停留在其上,例如上午8:00。通过这种方式,您可以在夜间开始计划,并在早上8点开始生产。

编辑:答案非常受欢迎,因此我每次评论都添加RAISERROR代替PRINT

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

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

    DELETE TOP(@BATCHSIZE)
    FROM SOMETABLE
    WHERE 1=2

    SET @BATCHSIZE=@@ROWCOUNT
    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
    WAITFOR DELAY @WAITFORVAL 
END

答案 1 :(得分:11)

BEGIN TRANSACTION     
    DoAgain:
    DELETE TOP (1000)
    FROM <YourTable>
    IF @@ROWCOUNT > 0
    GOTO DoAgain
COMMIT TRANSACTION

答案 2 :(得分:4)

这是我用过的东西:

  1. 如果错误数据与good-

    混合在一起
    INSERT INTO #table 
       SELECT columns 
       FROM old_table 
       WHERE statement to exclude bad rows
    
    TRUNCATE old_table
    
    INSERT INTO old_table 
       SELECT columns FROM #table
    

答案 3 :(得分:3)

不确定这会有多好但是如果你喜欢下面的内容(假设table_1是一个独立的表;我的意思是没有其他表引用)

  1. 创建table_1的重复表格,如table_1_dup

  2. insert into table_1_dup select * from table_1 where condition1 <> 'value';

  3. drop table table_1

  4. sp_rename table_1_dup table_1

答案 4 :(得分:3)

也许是Uri Dimant的解决方案

WHILE 1 = 1
BEGIN
   DELETE TOP(2000)
   FROM Foo
   WHERE <predicate>;
   IF @@ROWCOUNT < 2000 BREAK;
END

(链接:https://social.msdn.microsoft.com/Forums/sqlserver/en-US/b5225ca7-f16a-4b80-b64f-3576c6aa4d1f/how-to-quickly-delete-millions-of-rows?forum=transactsql

答案 5 :(得分:2)

如果您在维修时无法承受数据库的生产,请小批量生产。另见:How to efficiently delete rows while NOT using Truncate Table in a 500,000+ rows table

如果您赶时间并且需要尽可能快的方式:

  • 将数据库停止生产
  • 删除所有非聚集索引和触发器
  • 删除记录(或者如果大多数记录不好,请复制+删除+重命名表)
  • (如果适用)修复因放弃触发器而导致的不一致
  • 重新创建索引和触发器
  • 将数据库重新投入生产

答案 6 :(得分:0)

信不信由你,我的桌子上有300万个50万条记录

我写了这句话

DELETE TOP(500000) FROM MyTable

,我手动执行了大约7次, 每次执行大约需要50秒,但是最终,这解决了问题

答案 7 :(得分:0)

您可以用来立即删除表中的所有数据

truncate Table_Name