每个月我都会对我的 Oracle 数据库执行一个简单的更新语句。但是,从周一开始,这需要很长时间。该表每月增长 5%。目前已存储800万条记录。
声明:
update /*+ parallel(destination_tab, 4) */ destination_tab dest
set (full_name, state) =
(select /*+ parallel(source_tab, 4) */ dest.name, src.state
from source_tab src
where src.city = dest.city);
实际上有 20 个字段需要更新,而不仅仅是两个......但这样看起来更容易描述问题。
解释计划:
-----------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------------------------------
| 0 | update statement | | 8517K| 3167M| 579M (50)|999:59:59 |
| 1 | update | destination_tab | | | | |
| 2 | PX COORDINATOR | | | | | |
| 3 | PX SEND QC (RANDOM) | :TQ10000 | 8517K| 3167M| 6198 (1)| 00:01:27 |
| 4 | px block iterator | | 8517K| 3167M| 6198 (1)| 00:01:27 |
| 5 | table access full | DESTINATION_TAB | 8517K| 3167M| 6198 (1)| 00:01:27 |
| 6 | table access by index rowid| SOURCE_TAB | 1 | 56 | 1 (0)| 00:00:01 |
|* 7 | index unique scan | CITY_PK | 1 | | 1 (0)| 00:00:01 |
-----------------------------------------------------------------------------------------------------
有人可以向我描述一下这是怎么回事吗?这个计划看起来很糟糕!非常非常感谢。
最佳答案
你没有说多长时间才算太长。您正在加入一个 800 万行的表。不确定 source_tab 中有多少行。
我注意到执行计划表明对destination_tab进行全表扫描。 destination_tab 表中的城市列是否已建立索引?如果没有,请尝试添加索引。如果是,Oracle 可能会忽略它,因为它知道无论如何都需要返回每个值,而 destination_tab 是驱动表。
无论您如何优化它,随着表的增长,性能总是会下降,因为您通过从连接到另一个表的同一个表中获取值来更新每一行。也就是说,您始终执行 N 个操作,其中 N 是destination_tab 中的行数。
高级问题/建议:
- 每次都需要更新每一行吗?是否只有某些行的值可能发生更改?如果是这样,您能否以某种方式预测需要更新哪些行并限制对其的更新。
- 为什么会有提示?如果性能发生变化,我会尝试删除提示。优化器的工作就是为您找到最佳计划。通过使用提示,您可以告诉优化器如何完成其工作。你最好是对的。
您正在将destination_tab 上的full_name 列更新为同一行的name 列。但是您是通过连接到表来获取名称列的。从您的选择中删除它并使用如下所示的内容可能会更快。这是一个猜测。这可能并不重要。
update destination_tab dest set full_name = name, state = (select src.state from source_tab src where src.city = dest.city);
关于oracle - 简单的 Oracle UPDATE 语句性能异常糟糕,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15463266/