【问题标题】:Deleting data from Big Table in Oracle taking longer execution time从 Oracle 中的大表中删除数据需要更长的执行时间
【发布时间】:2020-07-24 07:50:51
【问题描述】:

我有一种情况,我需要从我的 Oracle 数据库中删除日志表中的数据。该表包含大约 3159037 行的 CLOB 内容,现在作为维护活动,我需要通过保留当前日期的最后 6 个月来清除旧数据。我设计了 PL/SQL 程序来实现这一点,但是在测试期间我发现即使删除 1000 条记录,该过程也需要大约 22 秒才能完成执行。现在假设我们有超过 100000 条记录要删除,这将花费大量时间来完成它的执行。

谁能提出更好的方法来解决这个问题。

下面是我当前的脚本,它具有 FORALL 和 BULK COLLECT 功能以获得性能优势。

 CREATE OR replace PROCEDURE Integration_data_purge
authid current_user
AS
  c_limit CONSTANT PLS_INTEGER DEFAULT 100;
  CURSOR int_cur IS
    SELECT a.ROWID AS a_rowid,
           b.ROWID AS b_rowid
    FROM   integration_log a,
           integration_errors b
    WHERE  a.error_log_id = b.error_rec_id(+)
           AND Trunc(a.insert_date) < Trunc(SYSDATE) - 180;
  TYPE int_aat
    IS TABLE OF int_cur%ROWTYPE INDEX BY PLS_INTEGER;
  l_integration_log INT_AAT;
  --l_count     INTEGER := 1;
  start_time        NUMBER;
  end_time          NUMBER;
BEGIN
    start_time := dbms_utility.get_time;

OPEN int_cur;

LOOP
    FETCH int_cur bulk collect INTO l_integration_log limit c_limit;

    --DBMS_OUTPUT.put_line ('Retrieved in RUN '|| l_count ||' = ' ||
    -- l_integration_log.COUNT);
    EXIT WHEN l_integration_log.count = 0;

    --if l_integration_log.count <> 0 then
    forall indx IN 1 .. l_integration_log.count
      DELETE FROM integration_log
      WHERE  ROWID = L_integration_log(indx).a_rowid;

    --DBMS_OUTPUT.put_line ('Total rows deleted from INTEGRATION_LOG = ' ||
    --SQL%ROWCOUNT);
    forall indx IN 1 .. l_integration_log.count
      DELETE FROM integration_errors
      WHERE  ROWID = L_integration_log(indx).b_rowid;
--DBMS_OUTPUT.put_line ('Total rows deleted from INTEGRATION_ERRORS = ' ||
--SQL%ROWCOUNT);
--l_count := l_count + 1;
--end if;
--commit;
END LOOP;

CLOSE int_cur;

end_time := dbms_utility.get_time;

dbms_output.Put_line('Execution Completed : '
                     || To_char(( end_time - start_time ) / 100)
                     || ' Seconds');
END;  

【问题讨论】:

  • 如果表 integration_errors 具有表 integration_log 的外键,并且您在定义外键时添加了 ON DELETE CASCADE,那么从 integration_log 中删除一行也将删除表中的所有相关行表integration_errors.
  • 外键减慢所有操作。我不建议将它们用于简单的日志表。此外,“on delete cascade”对父表中的每一行都运行删除,所以它会是缓慢的设计。

标签: oracle


【解决方案1】:

相当糟糕的设计。试试这个

DELETE FROM integration_errors WHERE err_rec_id in (select error_log_id from integation_log where insert_date < sysdate - 180) ;

DELETE from integation_log where insert_date < sysdate - 180;

除非你有基于函数的索引,否则不要使用trunc(insert_date)。删除数据前禁用外键约束,删除后再次启用。

考虑分区,在较新的 Oracle 中,您还可以通过 ref-key 进行分区

【讨论】:

  • 而“并行”提示可以帮助加快速度。
  • 是的,当表被分区时。否则我不知道 Oracle 可以在哪里并行化它
  • Oracle 甚至可以在非分区表上轻松执行并行 dml。
  • 感谢 Wernfried Domscheit,但如果要删除数百万行,那么简单地执行 DML 语句将无济于事。因此,我采用了 FORALL 和 BULK COLLECT 的方法。如果要从表中删除数百万行,您会建议什么。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-06
  • 2010-09-28
  • 2018-12-07
  • 1970-01-01
  • 2013-05-08
相关资源
最近更新 更多