【问题标题】:Techniques for removing old data on Oracle databases删除 Oracle 数据库上旧数据的技术
【发布时间】:2010-11-02 04:16:34
【问题描述】:

我们有一个成熟的 Oracle 数据库应用程序(已投入生产超过 10 年),在此期间,我们一直在使用我们自己设计的脚本来删除不再需要的旧数据。它们通过在频繁提交的循环中针对适当的表发出删除语句来工作,以避免系统因 i/o 过载或使用过多的撤消空间。

在大多数情况下,它们工作正常。它们每天运行,大约需要一个小时才能从系统中删除最旧日期的数据。我主要担心的是所有这些删除可能对表和索引产生的影响,以及即使它们不会过度加载系统,在短时间内删除一天的数据确实会产生影响由于缓存逐渐恢复,导致后续查询在接下来的几个小时内运行速度稍慢。

多年来,我们一直在考虑更好的方法。过去,我听说人们使用分区表来管理旧数据的回收——例如,每个分区一个月,然后每月删除最旧的分区。这种方法的主要缺点是我们的收获规则超出了“删除 X 月”的范围。允许用户根据键值指定数据必须在系统中保留多长时间(例如,在发票表中,帐户 foo 可以在 3 个月后删除,但帐户栏可能需要保留 2 年)。

还有参照完整性的问题; Oracle 文档主要在数据仓库的上下文中讨论使用分区来清除数据,其中表往往是超立方体。我们的更接近于 OLTP,X 月的数据与 Y 月的数据有关联是很常见的。为这些表创建正确的分区键充其量是很麻烦的。

关于缓存井喷,我已经阅读了一些关于设置专用缓冲区缓存的内容,但似乎更多的是基于每个表,而不是基于每个用户或每个事务。为了保留缓存,我真的很希望收割作业在任何时候只将一个事务的数据保留在缓存中,因为一旦删除就不需要保留数据。

在可预见的未来,我们是否会坚持使用删除,还是有其他更聪明的方法来处理收获?

【问题讨论】:

  • +1 好问题,希望我有一个聪明的解决方案,因为我可以自己使用它;-)
  • 保留数据不是一种选择吗?即您可以过滤查询中的旧记录(例如,使用 VPD 谓词)而不返回旧记录。只是说如果删除行会导致性能问题,我至少会考虑保留它们不一定是更糟糕的情况的可能性。

标签: oracle partitioning purge


【解决方案1】:

在大多数情况下,我认为您在执行删除操作时遇到了困难。

您的 cmets 在您的情况下使用分区的难度可能确实会阻止它们被有效使用(根据记录类型使用不同的删除日期),但您可以创建一个“删除日期”列您可以分区的记录?这样做的缺点是使更新变得非常昂贵,因为删除日期的更改可能会导致行迁移,因此您的更新将真正实现为删除和插入。

即使那样,由于参照完整性问题,您也可能无法使用 DDL 分区操作来删除旧数据,但分区仍然可能用于物理集群要删除的行,以便在为了删除它们,减轻对缓冲区缓存的影响。

【讨论】:

    【解决方案2】:

    删除并没有那么糟糕,只要你重建你的索引。 Oracle 将恢复不再包含数据的页面。

    但是,从 8i 开始(很可能仍然如此),它无法正确恢复不再包含有效引用的索引页面。更糟糕的是,由于索引叶子是链式的,您可能会遇到一种情况,它会开始遍历叶子节点以查找行。这将导致性能显着下降:通常需要几秒钟的查询可能需要几分钟。下降也很突然:前一天还可以,第二天就不行了。

    我在一个使用递增键和定期删除数据的应用程序中发现了这种行为(有一个 Oracle 错误,所以其他人也有)。我们的解决方案是反转部分密钥,但这对日期没有帮助。

    【讨论】:

    • 如果所有条目都从叶块中删除,则整理得很好。如果你留下一两个,它可能会很笨重。反向键索引对日期与任何其他数据类型一样有效,但它们具有使范围扫描不切实际的效果。大量删除可能值得重建一些索引,但要进行测量和测试以确保它是值得的。
    • 我假设您是 Oracle 员工,并且指的是 8i 之后的版本;正如我所说,从 8i 开始,这是一个已知的错误,没有修复的计划。重新反转键,我想我应该更清楚为什么它对你没有帮助。
    【解决方案3】:

    如果您暂时停用索引,执行删除然后重建它们怎么办?它会提高删除的性能吗?当然,在这种情况下,您必须确保脚本正确,并确保正确的删除顺序和引用完整性。

    【讨论】:

      【解决方案4】:

      我们有同样的问题,使用同样的策略。 如果情况变得非常糟糕(索引、表等非常分散的分配),我们会尝试应用空间回收操作。

      表格必须允许行移动(例如闪回): alter table TTT 启用行移动; alter table TTT 收缩空间; 然后重建所有索引。

      我不知道您的维护窗口如何,如果应用程序必须一直可用,那就更难了,如果不是,您可以在离线时进行一些“重新打包”。 “alter table TTT move tablespace SSSS”在表被重写时做了很多清理混乱的工作。您还可以指定新的存储参数,例如范围管理、大小……查看文档。

      我使用这样的脚本为整个数据库创建脚本:

      SET SQLPROMPT "-- "
      SET ECHO OFF
      SET NEWPAGE 0
      SET SPACE 0
      SET PAGESIZE 0
      SET FEEDBACK OFF
      SET HEADING OFF
      SET TRIMSPOOL ON
      SET TERMOUT OFF
      SET VERIFY OFF
      SET TAB OFF
      spool doit.sql
      select 'prompt Enabling row movement in '||table_name||'...'||CHR (10)||'alter table '||table_name||' enable row movement;' from user_tables where table_name not like '%$%' and table_name not like '%QTAB' and table_name not like 'SYS_%';
      select 'prompt Setting initial ext for '||table_name||'...'||CHR (10)||'alter table '||table_name||' move storage (initial 1m);' from user_tables where table_name not like '%$%' and table_name not like '%QTAB' and table_name not like 'SYS_%';
      select 'prompt Shrinking space for '||table_name||'...'||CHR (10)||'alter table '||table_name||' shrink space;' from user_tables where table_name not like '%$%' and table_name not like '%QTAB' and table_name not like 'SYS_%';
      select 'prompt Rebuilding index '||index_name||'...'||CHR (10)||'alter index '||index_name||' rebuild;' from user_indexes where status = 'UNUSABLE';
      spool off
      prompt now check and then run @doit.sql
      exit
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-01-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-02-06
        • 1970-01-01
        相关资源
        最近更新 更多