You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从Oracle执行计划中定位性能瓶颈及优化建议咨询

Oracle SQL执行计划分析与潜在优化点探讨

各位Oracle SQL调优专家,恳请帮忙分析以下执行计划以定位性能瓶颈,提前致谢。该查询响应速度很快,但我希望通过分析执行计划找到代码的潜在优化点。就我目前的认知来看执行计划整体尚可,但仅返回一行数据却有较高的成本,对此我存在疑问。

--------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                                       |                             |    25 | 10000 |  6105   (1)| 00:00:01 |
|   1 |  SORT ORDER BY                                         |                             |    25 | 10000 |  6105   (1)| 00:00:01 |
|*  2 |   VIEW                                                 |                             |    25 | 10000 |  6104   (1)| 00:00:01 |
|   3 |    WINDOW SORT                                         |                             |    25 |  9625 |  6104   (1)| 00:00:01 |
|   4 |     WINDOW SORT                                        |                             |    25 |  9625 |  6104   (1)| 00:00:01 |
|   5 |      WINDOW SORT                                       |                             |    25 |  9625 |  6104   (1)| 00:00:01 |
|   6 |       NESTED LOOPS ANTI                                |                             |    25 |  9625 |  6101   (1)| 00:00:01 |
|   7 |        NESTED LOOPS OUTER                              |                             |    25 |  8800 |  6001   (1)| 00:00:01 |
|   8 |         NESTED LOOPS OUTER                             |                             |    25 |  8125 |  5950   (1)| 00:00:01 |
|   9 |          NESTED LOOPS OUTER                            |                             |    25 |  7675 |  5875   (1)| 00:00:01 |
|  10 |           NESTED LOOPS OUTER                           |                             |     7 |  1862 |  5850   (1)| 00:00:01 |
|  11 |            NESTED LOOPS OUTER                          |                             |     5 |  1200 |  5825   (1)| 00:00:01 |
|  12 |             NESTED LOOPS OUTER                         |                             |     5 |  1165 |  5821   (1)| 00:00:01 |
|  13 |              NESTED LOOPS OUTER                        |                             |     4 |   760 |  5807   (1)| 00:00:01 |
|  14 |               NESTED LOOPS OUTER                       |                             |     4 |   684 |  5797   (1)| 00:00:01 |
|  15 |                NESTED LOOPS OUTER                      |                             |     4 |   568 |  5793   (1)| 00:00:01 |
|  16 |                 NESTED LOOPS OUTER                     |                             |     4 |   540 |  5793   (1)| 00:00:01 |
|  17 |                  NESTED LOOPS OUTER                    |                             |     4 |   424 |  5789   (1)| 00:00:01 |
|  18 |                   NESTED LOOPS                         |                             |     4 |   396 |  5789   (1)| 00:00:01 |
|  19 |                    NESTED LOOPS                        |                             |    57 |  1995 |  5630   (1)| 00:00:01 |
|  20 |                     INLIST ITERATOR                    |                             |       |       |            |          |
|* 21 |                      INDEX RANGE SCAN                  | NU_LOV_ENTRY_1              |     3 |    36 |     3   (0)| 00:00:01 |
|* 22 |                     TABLE ACCESS BY INDEX ROWID BATCHED| PARTY                       |    22 |   506 |  1876   (1)| 00:00:01 |
|* 23 |                      INDEX RANGE SCAN                  | IDX_HOME_STORE_PARTY        | 14838 |       |    41   (0)| 00:00:01 |
|* 24 |                    TABLE ACCESS BY INDEX ROWID         | PERSON                      |     1 |    64 |     3   (0)| 00:00:01 |
|* 25 |                     INDEX UNIQUE SCAN                  | XPKPERSON                   |     1 |       |     2   (0)| 00:00:01 |
|* 26 |                   INDEX UNIQUE SCAN                    | XPKLOV_ENTRY                |     1 |     7 |     0   (0)| 00:00:01 |
|  27 |                  TABLE ACCESS BY INDEX ROWID           | TRANSLATION                 |     1 |    29 |     1   (0)| 00:00:01 |
|* 28 |                   INDEX UNIQUE SCAN                    | XPKTRANSLATION              |     1 |       |     0   (0)| 00:00:01 |
|* 29 |                 INDEX UNIQUE SCAN                      | XPKLOV_ENTRY                |     1 |     7 |     0   (0)| 00:00:01 |
|  30 |                TABLE ACCESS BY INDEX ROWID             | TRANSLATION                 |     1 |    29 |     1   (0)| 00:00:01 |
|* 31 |                 INDEX UNIQUE SCAN                      | XPKTRANSLATION              |     1 |       |     0   (0)| 00:00:01 |
|* 32 |               TABLE ACCESS BY INDEX ROWID BATCHED      | PARTY_LEGAL_HOLD            |     1 |    19 |     4   (0)| 00:00:01 |
|* 33 |                INDEX RANGE SCAN                        | XIF3PARTY_LEGAL_HOLD        |     1 |       |     2   (0)| 00:00:01 |
|* 34 |              TABLE ACCESS BY INDEX ROWID BATCHED       | ADDRESS                     |     1 |    43 |     4   (0)| 00:00:01 |
|* 35 |               INDEX RANGE SCAN                         | IDX$$_036C0004              |     1 |       |     3   (0)| 00:00:01 |
|  36 |             TABLE ACCESS BY INDEX ROWID                | STATE_PROVINCE              |     1 |     7 |     1   (0)| 00:00:01 |
|* 37 |              INDEX UNIQUE SCAN                         | XPKSTATE_PROVINCE           |     1 |       |     0   (0)| 00:00:01 |
|* 38 |            TABLE ACCESS BY INDEX ROWID BATCHED         | PHONE                       |     1 |    26 |     5   (0)| 00:00:01 |
|* 39 |             INDEX RANGE SCAN                           | IDX$$_036C0003_1            |     1 |       |     3   (0)| 00:00:01 |
|  40 |           TABLE ACCESS BY INDEX ROWID BATCHED          | AGREEMENT_PARTY             |     4 |   164 |     7   (0)| 00:00:01 |
|* 41 |            INDEX RANGE SCAN                            | XIF2AGREEMENT_PARTY         |     4 |       |     3   (0)| 00:00:01 |
|  42 |          TABLE ACCESS BY INDEX ROWID                   | AGREEMENT                   |     1 |    18 |     3   (0)| 00:00:01 |
|* 43 |           INDEX UNIQUE SCAN                            | XPKAGREEMENT                |     1 |       |     2   (0)| 00:00:01 |
|  44 |         TABLE ACCESS BY INDEX ROWID BATCHED            | INSTALLMENT_NOTE            |     1 |    27 |     3   (0)| 00:00:01 |
|* 45 |          INDEX RANGE SCAN                              | IDX_INSTALLMENT_NOTE_AGR_ID |     1 |       |     2   (0)| 00:00:01 |
|* 46 |        TABLE ACCESS BY INDEX ROWID BATCHED             | AGREEMENT_PARTY             |     1 |    33 |     4   (0)| 00:00:01 |
|* 47 |         INDEX RANGE SCAN                               | UQ_AGREEMENT_PARTY_1        |     1 |       |     3   (0)| 00:00:01 |

执行计划关键分析点

1. 预估成本与实际返回行数的偏差

执行计划预估返回25行,但实际仅返回1行,整体成本达6105,核心原因是统计信息不准确:

  • PARTY表的IDX_HOME_STORE_PARTY索引预估扫描14838行,最终仅匹配22行数据,说明该索引对应的统计信息过时,CBO对数据分布判断严重偏差,高估了中间结果集规模,推高了整体成本。
  • 多层嵌套外连接的累加效应,每一层外连接都会让CBO默认保留更多结果行,进一步放大了预估偏差。

2. 排序操作的开销占比

执行计划包含3次WINDOW SORT和1次SORT ORDER BY,这部分是成本的主要构成。如果查询中使用了窗口函数(如ROW_NUMBER、RANK),需要注意:

  • 窗口函数的分区/排序字段是否缺少对应索引,导致每次查询都要全量排序。
  • 是否存在不必要的窗口函数嵌套,可通过简化业务逻辑减少排序次数。

3. 多层嵌套连接的潜在风险

当前查询用了10层以上的嵌套外连接,虽然响应快,但数据量增长后可能成为瓶颈:

  • 检查所有外连接是否都是业务必需的,部分非必需的外连接可改为内连接,或通过子查询提前过滤数据,缩小中间结果集。
  • NESTED LOOPS ANTI反连接的效率依赖索引支持,若原查询使用NOT IN,建议替换为NOT EXISTS,并确保关联字段有索引,提升过滤效率。

4. 临时索引的问题

执行计划中出现IDX$$_036C0004和IDX$$_036C0003_1两个临时索引,说明原表缺少匹配查询过滤条件的永久索引。临时索引每次查询都需要重新生成,会增加额外开销,且性能不稳定。

具体优化建议

  • 更新统计信息:对涉及的所有表和索引执行DBMS_STATS.GATHER_TABLE_STATS,确保CBO获取准确的数据分布,缩小预估与实际的行数偏差。
  • 优化窗口函数:为窗口函数的分区/排序字段创建复合索引,避免全量排序,降低排序操作的成本。
  • 精简连接逻辑:梳理业务需求,移除不必要的外连接,或通过子查询提前过滤数据,减少中间结果集的大小。
  • 替换临时索引:根据临时索引的字段组合,创建对应的永久索引,提升查询的稳定性和执行效率。
  • 调整反连接逻辑:将NOT IN替换为NOT EXISTS,并确保关联字段有索引支持,提升反连接的过滤效率。

内容的提问来源于stack exchange,提问作者user1402648

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 14:15:01