【问题标题】:Best way to delete millions of rows in Oracle在 Oracle 中删除数百万行的最佳方法
【发布时间】:2019-02-15 13:48:16
【问题描述】:

我有一个包含 1 万亿行和 8 个索引、2 个外键的表,并由一个包含年份的列进行分区。对于每个人,我计算年份(单独的包),少于该年份的数据应该被删除。目前最后一个分区有 6.51 亿行,我需要从这个分区中删除大约 600 万行。以下是我尝试过的事情

  1. 原版删除 - 花费大量时间

  2. 批量 FORALL 和 DELETE - 花费大量时间

  3. 交换分区 - 这是最快的,但所有 8 个索引都进入不可用状态,我需要重建所有索引,这又需要时间。目前 Exchange 分区也无法正常工作,因为父表有隐藏列并且分区会抛出错误提示

    ORA-12996: 无法删除系统生成的虚拟列

这张表有 300 000 人,我计算了每个人的年份,现在遍历每个人并删除他们,但在删除每个人后提交。

【问题讨论】:

  • 大概要保留多少记录?您可以考虑复制这些,截断表格并重新插入。
  • 在一个分区中的 6.5 亿个中,我想删除大约 5 亿个。尝试使用 CTAS 然后重新插入,但由于表有 8 个索引,这又需要时间。
  • 删除每一行后绝对不提交。
  • @DavidAldridge 如果我不这样做,撤消保留表将被填充并引发异常。我在删除每个人后提交。
  • 保证删除尽可能慢。解决帽子问题的方法是使用没有太多撤消的操作,或者增加可用的撤消空间。

标签: sql oracle plsql


【解决方案1】:

你可以这样做:

create table tablewithrelevantdata unrecoverable as select * from tabletobedeleted where ....;
drop table tabletobedeleted;
rename tablewithrelevantdata to tabletobedeleted;
create index tabletobedeleted_idx1 on tabletobedeleted(c1,c2) unrecoverable parallel 5;

既然你有索引,我会仔细检查复合表上是否有索引,比如

  1. 学生
  2. 老师

这里Class 以学生和教师的身份作为主键。 StudentIdTeacheridClass 中的索引很重要。

另外,你可以使用 delete 像:

SET TRANSACTION USE ROLLBACK SEGMENT <test_segment>;
DELETE FROM tabletobedeleted WHERE <some_condition>
COMMIT;

【讨论】:

  • 我可以使用 CTAS 和我想要保留的数据的副本,但它有 2 个问题。首先,该表有 1 万亿行,我只想删除 6 亿行。其次,它有 8 个索引,创建或重建它们需要时间。将尝试设置交易删除虽然
  • CTAS 不适合您的情况(我仍然提到过)。也可以尝试批量删除。
  • 否则您可以简单地将需要的行复制到新表中,删除旧表,将新表重命名为旧表,然后有一个回滚段。 (这类似于 CTAS)
【解决方案2】:

你可以试试:

  1. 创建新的非分区表
  2. 在其上创建索引
  3. 使用直接路径 (APPEND) nologging insert 添加要保留的行。
  4. 执行分区交换
  5. 截断非分区表
  6. 从 (3) 重复其他分区
  7. 删除非分区表
  8. 备份

请注意,索引是在插入过程中构建的,通过将所需数据记录到临时段中,然后对其进行扫描以构建索引,而不是完全扫描表本身。

【讨论】:

    猜你喜欢
    • 2012-01-07
    • 1970-01-01
    • 2010-09-22
    • 2020-08-10
    • 1970-01-01
    • 1970-01-01
    • 2023-03-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多