SQL批量删除

Tom*_*son 11 sql t-sql sql-server sql-server-administration

我在SQL Server 2005中有一个表,其中有大约40亿行.我需要删除大约20亿这些行.如果我尝试在单个事务中执行此操作,则事务日志将填满并且失败.我没有任何额外的空间来使事务日志更大.我认为最好的方法是批量删除语句(批量为~10000?).

我可以使用游标执行此操作,但这是一种标准/简单/聪明的方法吗?

PS此表没有标识列作为PK.PK由整数外键和日期组成.

Sta*_*zev 8

您要删除的行与要保留的行的区别是什么?这对你有用吗:

while exists (select 1 from your_table where <your_condition>)
delete top(10000) from your_table
where <your_condition>
Run Code Online (Sandbox Code Playgroud)

  • 您可以使用WHILE(1 = 1)而不是检查IF EXISTS,而在DELETE之后使用IF @@ ROWCOUNT = 0 BREAK (3认同)
  • where 条件基本上是:WHERE DateTimeInserted &lt; DATEDIFF(d, GETDATE(), 5)。我可以尝试一下,但我担心因为这将循环约 200,000 次,所以 select 语句将执行 200,000 次,并且在 2-40 亿行的表上可能需要长达半小时(根据经验)。如果真是这样的话,这个声明要运行11年!:) (2认同)

Nic*_*ias 7

您可以"轻咬"删除,这也意味着您不会对数据库造成大量负载.如果您的t-log备份每10分钟运行一次,那么您应该可以在相同的时间间隔内运行一次或两次.您可以将其安排为SQL代理作业

尝试这样的事情:

DECLARE @count int
SET @count = 10000

    DELETE  FROM table1 
    WHERE table1id IN (
        SELECT TOP (@count) tableid
        FROM table1
        WHERE x='y'
    )
Run Code Online (Sandbox Code Playgroud)

  • 这看起来不错.从2005年开始,你可以实际做到:DELETE TOP(@count)FROM ... (4认同)

Tom*_*m H 5

除了将其与语句一起放入批处理中以截断日志,您可能还想尝试以下技巧:

  • 除了其他条件之外,添加与聚集索引中的第一列匹配的条件
  • 如果可能的话,从表中删除任何索引,然后在删除完成后将它们放回去,并且不会干扰数据库中发生的任何其他事情,但保留聚集索引

例如,对于上面的第一点,如果您的 PK 是聚类的,那么找到一个与您要删除每个批次的行数大致匹配的范围,然后使用它:

DECLARE @max_id INT, @start_id INT, @end_id INT, @interval INT
SELECT @start_id = MIN(id), @max_id = MAX(id) FROM My_Table
SET @interval = 100000  -- You need to determine the right number here
SET @end_id = @start_id + @interval

WHILE (@start_id <= @max_id)
BEGIN
     DELETE FROM My_Table WHERE id BETWEEN @start_id AND @end_id AND <your criteria>

     SET @start_id = @end_id + 1
     SET @end_id = @end_id + @interval
END
Run Code Online (Sandbox Code Playgroud)