oracle - 简单的 Oracle UPDATE 语句性能异常糟糕

标签 oracle performance

每个月我都会对我的 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 中的行数。

高级问题/建议:

  1. 每次都需要更新每一行吗?是否只有某些行的值可能发生更改?如果是这样,您能否以某种方式预测需要更新哪些行并限制对其的更新。
  2. 为什么会有提示?如果性能发生变化,我会尝试删除提示。优化器的工作就是为您找到最佳计划。通过使用提示,您可以告诉优化器如何完成其​​工作。你最好是对的。
  3. 您正在将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/

相关文章:

sql - 新添加的列没有出现在同义词中

c - 使用Pro*C编程时如何知道SQL是否执行成功?

java - 数据库多线程插入(更新)和单线程顺序插入(更新)的性能比较?

performance - WordPress 操作、过滤器和性能

java - 这是一个 "good enough"随机算法吗?如果它更快,为什么不使用它?

sql - Oracle APEX : Error: SyntaxError: Unexpected end of JSON input

java - 从 PaintComponent 调用 repaint 是一个好习惯吗

Android:使用 png 而不是矢量图像时分配的内存太多

ruby-on-rails - 批量运行 Rails 查询

sql - 如何在 Oracle SQL 数据库中查找相关行