【问题标题】:Deleting massive number of duplicate records without using a new table在不使用新表的情况下删除大量重复记录
【发布时间】:2021-10-05 15:59:41
【问题描述】:

现在我有一张表,其中有大量重复项需要删除(大约 5 亿)。

我有一个查询将删除所有重复项,但由于事务日志已填满,它无法完成整个查询。

将非重复项移动到新表,然后重命名它会起作用,但在这种情况下,我无法这样做。这将在生产环境中执行,因此我无法删除该 d1 表。

与涉及更改某种备份事务日志设置的其他解决方案相同。

这是我的查询:

;WITH CTE AS 
(
    SELECT 
        d_id, d_record, d_d2id, 
        ROW_NUMBER() OVER (PARTITION BY d_record, d_d2id ORDER BY d_id) RowNumber
    FROM 
        d1
    WHERE 
        d_d2id >= 25 AND d_d2id <= 28
)
DELETE FROM CTE 
WHERE RowNumber > 1

显然这会起作用,但是由于必须执行的删除量,它会炸毁事务日志。

有没有办法创建这个特定的 CTE,然后分批检查 1000 条记录并以这种方式删除它们,从而留下一大堆事务而不是 1 个?还是有另一种方法可以做到这一点?我唯一的解决方案是遍历这些重复项并删除它们,而不会破坏事务日志。

谢谢!

【问题讨论】:

  • 有没有办法在 SQL Server 中关闭事务日志?您当前的查询(至少)看起来已经非常理想了。
  • 您可以添加另一个 CTE 术语,它只过滤掉 RowNumber > 1,然后在所有剩余的行上添加另一个 row_number,然后只删除每个批次/提交的前 N ​​个。冲洗,重复直到完成。一些数据库支持某种形式的 FETCH FIRST N ROWS,可以用来代替第二个 row_number 表达式。
  • 用您正在使用的数据库标记您的问题。据我所知,鉴于您的非标准代码仅适用于一个数据库,您的“显然这将起作用”是完全不正确的。

标签: sql duplicates sql-delete


【解决方案1】:

在 SQL Server 中,您可以批量删除。虽然这不是最有效的代码,但它说明了批量删除的想法:

DECLARE @go_on INT
SELECT @go_on = 1;

WHILE (@go_on = 1)
BEGIN
    WITH TODELETE AS (
          SELECT TOP (10000) d1.*
          FROM (SELECT d1.*,
                       ROW_NUMBER() OVER (PARTITION BY d_record, d_d2id ORDER BY d_id) as seqnum
                FROM d1
                WHERE d_d2id >= 25 AND d_d2id <= 28
               ) d1
          WHERE seqnum > 1
         )
    DELETE FROM TODELETE; 

    SET @go_on = (CASE WHEN @@ROWCOUNT > 0 THEN 1 ELSE 0 END);
END;

将要删除的行存储在临时表或表变量中会更有效,因此不需要每次都重新计算。

【讨论】:

    【解决方案2】:

    您可以使用光标进行批量删除。这些通常被认为是不好的做法,但它可以满足您在此处尝试做的事情。

    https://www.mysqltutorial.org/mysql-cursor/

    https://docs.microsoft.com/en-us/sql/t-sql/language-elements/declare-cursor-transact-sql

    【讨论】:

      【解决方案3】:

      有两种选择

      1st,让系统记忆1个出现记录位置并删除其余具有相同值的条目

      第二次看到您可以扫描和删除具有 2 个或更多条件的条目,但它必须将您的数据存储在某个地方, 制作具有唯一/主约束的临时表要快得多,否则系统可能会在运行时崩溃或变慢,例如在第一个发现的记录 RD002,但系统必须记住第一个条目的位置并扫描表的其余部分 > 与其他重复项相同和唯一的条目(删除其他条目也会发生同样的情况)

      【讨论】:

        【解决方案4】:

        您可以批量删除 1000 行并在每次删除后提交。您可以在 pl/sql 循环中执行此操作:

        begin
            loop
        
                delete from d1
                where d1.rowid in (
                    select t.rowid
                    from (
                        select 
                            d1.rowid, 
                            row_number() over (partition by d_record, d_d2id order by d_id) rn
                        from d1
                        where 
                            d_d2id >= 25 and d_d2id <= 28
                    ) t
                    where t.rn > 1 and rownum <= 1000
                );
        
                commit;
            exit when sql%rowcount = 0;
            end loop;
        end;
        

        【讨论】:

          猜你喜欢
          • 2014-08-26
          • 1970-01-01
          • 2017-01-17
          • 2012-09-18
          • 2013-11-01
          • 2015-06-14
          • 2021-08-16
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多