【问题标题】:Deleting rows in a table a chunk at a time一次删除表中的一个块
【发布时间】:2012-07-03 20:55:35
【问题描述】:

我有一个单列表 Ids,其列 ID 的类型为 uniqueidentifier。我有另一个表MyTable,它有一个 ID 列以及许多其他列。我想一次删除MyTable 1000 中的行,其中MyTable 中的ID 与Ids 中的ID 匹配。

WHILE 1 = 1 BEGIN
    DELETE t FROM (SELECT TOP 1000 ID FROM Ids) d INNER JOIN MyTable t ON d.ID = t.ID;
    IF @@ROWCOUNT < 1 BREAK;
    WAITFOR DELAY @sleeptime; -- some time to be determined later
END

这似乎不起作用。该语句实际上应该是什么?

【问题讨论】:

    标签: sql sql-server database delete-row


    【解决方案1】:

    试试这个:

    DECLARE @BatchSize INT
    SET @BatchSize = 100000
    
    WHILE @BatchSize <> 0
    BEGIN 
       DELETE TOP (@BatchSize) t
        FROM [MyTable] t
        INNER JOIN [Ids] d ON d.ID=t.ID
        WHERE ????
       SET @BatchSize = @@rowcount 
    END
    

    您需要创建的唯一变量是大小,因为它将用于 WHILE 循环检查。当删除低于 100000 时,它会将变量设置为该数字,在下一次传递时将没有任何内容可删除,并且行数将为 0...所以你退出。干净,简单,易于理解。当 WHILE 可以解决问题时,切勿使用 CURSOR!

    【讨论】:

    • 这里通常有一个额外的迭代。如果 @@rowCount
    • 不是最糟糕的建议,但我讨厌做一个无操作的 while 循环,然后是一个 if 来逃避。我想你可以避免大部分时间与WHILE @BatchSize = 100000 的额外交互。如果你有一个精确的 100000 的倍数,你只会有一个额外的迭代。我们主要使用 4500 来避免清除旧数据时的表锁定。当我们做几百次时,一个额外的循环永远不会受到伤害。不错的收获,@crokusek!
    【解决方案2】:

    试试Delete from MyTable WHERE ID in (select top 1000 t.ID from Ids t inner join MyTable d on d.Id = t.Id)

    【讨论】:

    • 这个效果好吗?我正在处理的数据库将非常大。
    • 这不是一个直截了当的问题。我会确保您的 ID 从一开始就被编入索引。但总的来说,这应该有效。
    • 其实这样不会一直重复从Ids中选择同一个前1000个ID,因为我只是从MyTable中删除吗?
    • 好吧,一旦前1000个被删除,下一次迭代将不再被选中。
    • 如果 Id 列被编入索引,它可能没问题,但我会选择 E J Brennan 的安全答案
    【解决方案3】:

    你也可以试试:

    set rowcount 1000
    delete from mytable where id in (select id from ids)
    set rowcount 0  --reset it when you are done.
    

    http://msdn.microsoft.com/en-us/library/ms188774.aspx

    【讨论】:

    • 是的,但它适用于SQL-2012之后的版本,所以可能会工作一段时间。
    • 至少提醒用户清除该设置...如果他们重用终端会话或有一个大脚本,那么从这一步开始,事情就会变得非常糟糕!
    【解决方案4】:
    WHILE EXISTS (SELECT TOP 1 * FROM MyTable mt JOIN IDs i ON mt.ID = t.ID)
    BEGIN
    
    DELETE TOP (1000) FROM MyTable
    FROM MyTable mt JOIN IDS i ON mt.ID = i.ID
    
    --you can wait if you want, but probably not necessary
    END
    

    --对不起,快速发布;很着急:)

    SQL Server 中的 DELETE 语句支持两个 FROM 子句;第一个 FROM 标识删除行的表,第二个 FROM 子句用于 JOINS。

    见:http://msdn.microsoft.com/en-us/library/ms189835.aspx

    【讨论】:

    • 编辑你的答案,我认为不正确,但方法是正确的。为什么?重复FROM MyTable
    • 另外SELECT TOP 1 FROM 缺少一些东西。
    猜你喜欢
    • 2019-10-30
    • 1970-01-01
    • 1970-01-01
    • 2019-06-11
    • 1970-01-01
    • 1970-01-01
    • 2012-05-13
    • 1970-01-01
    • 2020-06-08
    相关资源
    最近更新 更多