【问题标题】:Bulk DELETE on SQL Server 2008 (Is there anything like Bulk Copy (bcp) for delete data?)SQL Server 2008 上的 Bulk DELETE(是否有类似 Bulk Copy (bcp) 的删除数据?)
【发布时间】:2011-01-08 17:53:41
【问题描述】:

SQL Server 中是否有批量删除的解决方案?

我不能使用 TRUNCATE,因为我想使用 WHERE 来限制行数。

有没有像批量复制(bcp)这样的删除数据?

【问题讨论】:

    标签: sql sql-server tsql sql-server-2008


    【解决方案1】:

    您可以使用循环逐块删除:

    这是我每次删除 100 条记录的解决方案:

    DECLARE @Rows INT
    SET @Rows = 1
    
    WHILE (@Rows > 0)
    BEGIN
       
         with ToDelete(EMailNotificationID)
             as
             (
             select top 100 q.EMailNotificationID from email
             )
    
             delete from ToDelete
    
    
        SET @Rows = @@ROWCOUNT
    END
    

    【讨论】:

      【解决方案2】:

      【讨论】:

        【解决方案3】:

        在处理数百万行时,我更喜欢使用 WHERE 语句并使用 SELECT INTO 复制表,删除原始表并重命名副本(恢复为原始名称)。

        不过,您应该牢记 (FK) 键、约束等内容。但是使用这种方法可以避免日志的badazz-size,并且可以避免大量删除块的时间消耗。

        /斯内德克

        【讨论】:

          【解决方案4】:

          刚刚在处理临时表时遇到了类似的问题,该表在使用适当的锁进行扩展时遇到了问题。

          由于我们只在一个位置引用了相关表,因此我们只是用动态表名的查询替换了该引用,动态表名是使用类似于 gbn 建议的“选择进入”创建的。

          这是可维护的,因为临时表仅在代码中的一个位置引用,并且在仓库上下文中,额外的数据库调用以及表创建的费用是合理的。如果您只有几百条记录或在代码中多次引用该表,那么这种方法可能行不通。

          【讨论】:

            【解决方案5】:

            没有。

            您想要一个带有 WHERE 子句的 DELETE:这是标准 SQL。

            你可以像这样批量删除:

            SELECT 'Starting' --sets @@ROWCOUNT
            WHILE @@ROWCOUNT <> 0
                DELETE TOP (xxx) MyTable WHERE ...
            

            或者如果你想删除很高比例的行...

            SELECT col1, col2, ... INTO #Holdingtable
                       FROM MyTable WHERE ..opposite condition..
            TRUNCATE TABLE MyTable
            INSERT MyTable (col1, col2, ...)
                       SELECT col1, col2, ... FROM #Holdingtable
            

            【讨论】:

            • 如果事务量很大,根据你的备份模型和日志大小,做更多的日志备份以释放日志空间...
            • 在临时表中保存数据会让你付出更多的内存使用。
            • @Allan Chua:你能证明临时表只保存在内存中吗?
            • 哎哟...学到了艰难的方法...当我可以应用这种方法时,2小时批量删除
            • 您还应该确保恢复模式为BULK_LOGGEDSIMPLE 并使用WITH TABLOCK 锁定表以进行第二次INSERT,否则事务日志仍然会很大。见social.technet.microsoft.com/wiki/contents/articles/…
            【解决方案6】:

            如果您想删除表的一部分而不是TRUNCATE,您可以做几件事。

            你可以选择表格的一部分到一个新表格中,然后将两者切换,如下所示:

            SELECT *
            INTO tmp_MyTable
            FROM MyTable
            WHERE Key='Value'
            
            IF @@ROWCOUNT > 0
            BEGIN
                EXEC sp_rename MyTable, old_MyTable, NULL
                EXEC sp_rename tmp_MyTable, MyTable, NULL
                TRUNCATE old_MyTable 
            END
            

            其次,如果您使用分区,您可以在相同的分区方案上创建一个相同的(空)表。如果该表是根据您的归档/清除逻辑分区的,您可以从您的主表到新表然后截断新表。例如:

            ALTER TABLE MyTable
            SWITCH PARTITION 15 TO purge_MyTable PARTITION 2 
            GO; 
            
            TRUNCATE TABLE purge_MyTable 
            

            附言。 SQL 2005/08 Ent 中提供了分区。

            希望这会有所帮助!

            【讨论】:

            • 好答案。仅供参考,您也可以使用 ALTER TABLE..SWITCH 而不进行分区,但是您需要 2 个离散表。
            • +1 在删除大量行时,使用临时表可能会获得最快的结果。如果目标是回收空间,我还将在操作结束时为所有 db 文件运行DBCC SHRINKFILE
            【解决方案7】:

            Sychare Jedko,

            TRUNCATE 的优点是避免在日志文件中记录每一次删除。 TRUNCATE 语句将为整个批次创建一个条目(在日志中)。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2017-12-11
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2023-03-24
              相关资源
              最近更新 更多