我有一个包含 1 亿行的子表,需要使用父表中的值更新一列的 5000 万行。我已经阅读了假设如果我们有足够的空间,“创建表作为选择”将是最快的,但我想知道是否有人不同意或者是否需要其他因素才能做出更好的猜测?与使用 pl/sql 的 BULK COLLECT FORALL UPDATE 功能相比,这条路线会更好吗?
问问题
1251 次
2 回答
1
如果你有很多数据,那么 CREATE TABLE AS SELECT 肯定会更快,因为它不需要 UNDO 表空间。但是,由于名称冲突,要在新表上重新创建所有索引可能会很麻烦。
好消息是:50 分钟的行并不是很多数据。如果你有一个现代的中端服务器,它应该不会引起问题,所以不值得额外的工作。找出答案的最好方法是复制原始表(包括所有索引)并在那里尝试更新。然后你就会大致了解需要多长时间。
于 2017-07-12T23:22:34.123 回答
0
并行更新可能是对子表进行较大更改的最佳选择。(如果您有企业版、足够的资源、合理的配置等)
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
,我建议您避免这项工作并接受稍微非最佳的解决方案。
于 2017-07-13T07:16:13.827 回答