Oracle 最佳实践使用父表中的值更新表中的 5000 万个子行

Posted

技术标签:

【中文标题】Oracle 最佳实践使用父表中的值更新表中的 5000 万个子行【英文标题】:Oracle BEST PRACTICE to update 50 million child rows in a table using value from parent table 【发布时间】:2017-07-12 21:23:10 【问题描述】:

我有一个包含 1 亿行的子表,需要使用父表中的值更新一列的 5000 万行。我已经阅读了假设如果我们有足够的空间,“创建表作为选择”将是最快的,但我想知道是否有人不同意或者是否需要其他因素才能做出更好的猜测?与使用 pl/sql 的 BULK COLLECT FORALL UPDATE 功能相比,这条路线会更好吗?

【问题讨论】:

为什么不使用update - 这就是你正在做的事情 在此之前请发布解释计划 过程代码会比SQL语句慢。 如果这是一个必须经常发生的过程,那么在使用扩展 SQL 跟踪进行跟踪的同时尝试两种方式,这样您就不必猜测哪个更好。如果事情只需要发生一次,那么你走哪条路可能并不重要。但你必须展示更多的作品,我们才能高度自信地说“没关系”。 如果子表上的字段是一个或多个索引的一部分,我建议您在执行更新之前删除索引,然后重新创建它/它们。 【参考方案1】:

如果您有大量数据,那么 CREATE TABLE AS SELECT 肯定会更快,因为它不需要 UNDO 表空间。但是,由于名称冲突,在新表上重新创建所有索引可能会很麻烦。

好消息是:50 分钟的行并不是很多数据。如果你有一台现代的中端服务器,它应该不会引起问题,所以不值得额外的工作。找出答案的最好方法是复制原始表(包括所有索引)并在那里尝试更新。然后你就会大致了解需要多长时间。

【讨论】:

【参考方案2】:

并行更新可能是对子表进行较大更改的最佳选择。 (如果您有企业版、足够的资源、合理的配置等)

alter session enable parallel dml;
update /*+ parallel */ ...;

(您可能想使用不同的并行数,例如parallel(8)。默认的并行度通常足够好。但是像 SPARC 这样的一些平台会夸大它们的“CPU_COUNT”,导致并行度荒谬。)

并行更新可能不是最佳解决方案。重新创建对象可以更快,因为它几乎可以完全避免生成 REDO 和 UNDO。但是重新创建对象通常是有问题的,并且要获得最佳性能是很棘手的。

在您决定简单地删除并重新创建表之前,需要考虑以下事项:

    授权。在重新创建对象后保存并重新应用对象授权。 依赖对象。该过程需要以完全相同的方式重新创建所有对象和依赖对象。这可能会非常困难,具体取决于您的架构有多复杂。 DBMS_METADATA 可能很棘手,并且在某些情况下仍然不会以相同的方式完全相同制作对象。如果您决定对 DDL 进行硬编码,则必须记住在对象更改时更新流程。 无效的对象。大多数对象会在必要时自动重新编译。但是您可能不想等待,因为拥有无效对象总是很糟糕。即使编译正确,某些程序仍可能出现那些讨厌的ORA-04068: existing state of packages has been discarded 错误。 (因为大多数 PL/SQL 程序员不知道会话状态,并且默认将每个包变量公开。) 统计数据。 在重新创建表后简单地重新收集它们并不总是足够的。直方图取决于列是否在谓词中使用。如果重新创建表,所有列都是新的,并且最初不会创建直方图。 直接路径写入是难以捉摸的。父子表意味着一个外键,这通常会阻止直接路径写入。该过程需要禁用或删除外键。并且还将表和索引设置为NOLOGGING,然后记得在最后将它们设置回LOGGING。当您重新创建外键时,如果您想并行执行,您必须首先将其创建为NOVALIDATE,将表设置为并行,启用验证约束,然后将表设置回NOPARALLEL

在大型数据仓库中,值得通过所有这些步骤并构建代码来处理所有问题。如果这是您唯一的大表UPDATE,我建议您避免这项工作并接受稍微不理想的解决方案。

【讨论】:

以上是关于Oracle 最佳实践使用父表中的值更新表中的 5000 万个子行的主要内容,如果未能解决你的问题,请参考以下文章

Oracle 删除表中的重复行并使用另一个表中的值更新行

Oracle:使用其他表中的值进行更新

如何根据oracle中另一个表中的值更新一个表中的字段[重复]

Oracle:使用来自同一表的聚合值更新表中的值

编写 SQL 语句通过 join id 查找行,并将连接行中的值插入到父表中

oracle查询包含在子表中的主表数据