从包含数万亿条记录的 Oracle 表中删除数十亿条记录

Posted

技术标签:

【中文标题】从包含数万亿条记录的 Oracle 表中删除数十亿条记录【英文标题】:Deleting billions of records from Oracle Table containing trillions of records 【发布时间】:2021-02-26 18:17:58 【问题描述】:

我需要删除大约。来自具有大约 100 + 十亿行的 Oracle 表的 300 亿行。我有我需要在临时表中删除的行的所有 ID。目前我正在使用如下的单个删除语句,也使用 SUBPARTITION 并在 temp_table 上创建索引。然而,这需要 4 个多小时才能在 PRODUCTION 中完成。

DELETE FROM table_name SUBPARTITION(subpartition_name) WHERE id IN (SELECT id FROM temp_table);
COMMIT;

有没有办法可以优化它以使其运行得更快。

仅供参考:

    我所指的 oracle 表对于多个客户端来说是通用的,所以下面的选项在这里不适合。 创建新表并将所需数据移入其中并删除旧表,然后将新表重命名为旧表。 批量删除:循环遍历临时表并删除如下所示的内容,在非生产环境中需要更多时间,并且不确定它在生产环境中的情况。
DECLARE
  vCT NUMBER(38) := 0;

BEGIN
  FOR t IN (SELECT id FROM temp_table) LOOP
    DELETE FROM table_name WHERE id = t.id;
    ......
    ......
      COMMIT;
    END IF;
  END LOOP;
  COMMIT;
END;
    在这里创建单独的 DELETE 语句的选项也不可行,因为记录数以十亿为单位。

我确实检查了,我正在使用它的表上有分区和子分区,并且没有没有子表依赖它。

请提出建议。

【问题讨论】:

您如何确定将哪些id 值放入临时表中?如果这是需要定期发生的事情,通常会设计该表,以便您可以只删除一个或多个分区,而不是删除 300 亿行。 似乎是您的分区键设计不佳。通常,您删除或截断整个(子)分区。 @JustinCave - 我查询到原始表,并根据一些条件确定需要删除哪些记录。因此将所有 id 捕获到临时表中,这样我就不必一次又一次地运行相同的条件。现在 temp_table 具有所有要从原始表中删除的 ID。 @WernfriedDomscheit - 设计确实很差,但必须忍受。 但是这些条件和分区方案有关系吗?还是您真的要从每个分区中删除 30% 的数据? 【参考方案1】:

删除(或更新)大量行是痛苦并且需要很多时间。

管理它最有效的方法是使用updatable join views

请求但应该没问题的是 delta 表上的一个唯一索引,其中包含要删除的 id

在使用这种方法时,请确保大表在id 列上没有唯一索引如果两个表在连接列上都有唯一索引,则会出现一些技术问题 - 见下文。

比使用以下查询(如果您想明智地使用子分区)删除

delete from 
(
select delta.id, big.id big_id 
from delta 
join big subpartition (SYS_SUBP220880)
on delta.id = big.id  
)

Oracle 使用两个表的 hash join,在您的情况下,这是管理您的规模的唯一可能性。您可以部署并行选项,不要忘记启用它。

这是预期的执行计划:

-------------------------------------------------------------------------------------------------------
| Id  | Operation                     | Name  | Rows  | Bytes | Cost (%CPU)| Time     | Pstart| Pstop |
-------------------------------------------------------------------------------------------------------
|   0 | DELETE STATEMENT              |       |   100K|  1757K|   875   (2)| 00:00:01 |       |       |
|   1 |  DELETE                       | BIG   |       |       |            |          |       |       |
|*  2 |   HASH JOIN                   |       |   100K|  1757K|   875   (2)| 00:00:01 |       |       |
|   3 |    TABLE ACCESS FULL          | DELTA |   100K|   488K|    47   (3)| 00:00:01 |       |       |
|   4 |    PARTITION COMBINED ITERATOR|       |   783K|  9947K|   825   (1)| 00:00:01 |   KEY |   KEY |
|   5 |     TABLE ACCESS FULL         | BIG   |   783K|  9947K|   825   (1)| 00:00:01 |    65 |    65 |
-------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
 
   2 - access("DELTA"."ID"="BIG"."ID")

注意 - 如果多个连接表被保留,请参阅文档Note on Updatable Views

对于 DELETE 语句,如果连接导致多个保留键的表,则 Oracle 数据库将从 FROM 子句中命名的第一个表中删除,无论视图是否创建为 WITH CHECK OPTION。

【讨论】:

以上是关于从包含数万亿条记录的 Oracle 表中删除数十亿条记录的主要内容,如果未能解决你的问题,请参考以下文章

我想在oracle数据库中插入十亿条记录

逐页读取Oracle表中的所有数据

将 s3 中跨 CSV 文件的数十亿条记录推送到 MongoDb

如何使用mongo在sinatra的handsontable中轻松加载数十亿条记录?

Firebase 实时数据库能否有效地循环浏览数十亿条帖子并由发布它们的用户检索?

第20篇-不和谐如何索引数十亿条消息