每个月我都在我的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 |
-----------------------------------------------------------------------------------------------------
有人可以向我描述,这是怎么回事?该计划看起来非常糟糕!非常感谢你。
答案 0 :(得分:1)
你没说多长时间。您正在加入一个800万行表。不确定source_tab中有多少行。
我注意到执行计划表明了destination_tab的全表扫描。 destination_tab表上的city列是否已编入索引?如果没有,请尝试添加索引。如果是,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);
答案 1 :(得分:1)
如果这是一个数据仓库,我不会做更新,尤其不是大表中的每一行。我可能会创建一个materialized view来组合各种基表中的各个部分,并在需要时进行完全刷新(非原子:truncate + insert append)。
编辑: 至于为什么当前的更新方法花费的时间比平时长得多,我的猜测就是在以前的运行中,Oracle在缓冲区缓存中发现了更新所需的大量块,最近Oracle不得不拉首先从磁盘到缓冲区很多。您可以查看一致的获取和db块获取(逻辑io)与物理io(磁盘)。
答案 2 :(得分:1)
尝试以下方法。
merge
into destination_tab d
using source_tab s
on (d.city = d.city)
when matched then
update
set d.state = s.state
where decode(d.state, s.state, 1, 0) = 0;
答案 3 :(得分:0)
我理解有关数据仓库意义的评论等。但是,我必须在这种情况下进行此更新。此更新是ETL工作流程的一部分。我必须每个月复制表“目的地”的完整800万条记录。在这一步之后,我必须进行UPDATE,这会产生问题。
我不明白这个问题,日常表现如此糟糕。通常,更新运行45分钟。现在,它运行大约4个小时。但为什么?没有必要的分类,因此着名的原因是“在光盘上而不是在主存储器上分类”是不可能的。我的问题是什么问题?
正常更新(我是如何做)和合并更新之间的性能是否存在差异?