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

Oracle 19c Merge语句执行超时问题及调优方案分享

Oracle 19c MERGE语句性能优化案例

问题背景

在Oracle Database 19c环境中,执行一条仅包含UPDATE操作的MERGE语句时,语句始终无法执行完成,单独执行其SRC子查询也无响应。本次操作涉及两张表:

  • TEST_TAB1:约17369608行
  • TEST_TAB2:约300711行

通过会话监控捕获到以下等待事件:gc cr multi block mixed、library cache pin、pga memory operation。

原表结构、MERGE语句及执行计划

表结构

CREATE TABLE TEST_TAB1 
(    
    EFFECTIVE_DT DATE NOT NULL ENABLE, 
    CMPNY_CD VARCHAR2(3 BYTE) NOT NULL ENABLE, 
    CURRENCY VARCHAR2(3 BYTE) NOT NULL ENABLE, 
    EXCHNG_RT NUMBER(28,13) NOT NULL ENABLE, 
    LAST_CHNG TIMESTAMP (6) NOT NULL ENABLE
) 
TABLESPACE APP_TS ;

CREATE UNIQUE INDEX TEST_TAB1_IDX1 ON TEST_TAB1 (EFFECTIVE_DT, CMPNY_CD, CURRENCY)
TABLESPACE APP_TS ;

ALTER TABLE TEST_TAB1 ADD CONSTRAINT TEST_TAB1_PK PRIMARY KEY (EFFECTIVE_DT, CMPNY_CD, CURRENCY)
USING INDEX TEST_TAB1_IDX1  ENABLE;

CREATE INDEX TEST_TAB1_IDX2 ON TEST_TAB1 (LAST_CHNG)
TABLESPACE APP_TS ;

-- TEST_TAB1 行数:17369608

CREATE TABLE TEST_TAB2 
(    
    BUSINESS_DT DATE NOT NULL ENABLE,           
    ORG_CRCY VARCHAR2(3 BYTE) NOT NULL ENABLE,  
    ORG_CRCY_A NUMBER(23,3) NOT NULL ENABLE,     
    CMPNY_CD VARCHAR2(3 BYTE) NOT NULL ENABLE, 
    FUNC_CRCY NUMBER(23,3) NOT NULL ENABLE
) 
TABLESPACE APP_TS ;

-- TEST_TAB2 行数:300711

原MERGE语句

MERGE INTO TEST_TAB2 wk
USING (
    With temp_tab2 as (select distinct CMPNY_CD,ORG_CRCY ,BUSINESS_DT from TEST_TAB2 )
    ,temp_tab1 as (select max(EFFECTIVE_DT) as EFFECTIVE_DT, g1.CMPNY_CD,g1.ORG_CRCY,g1.BUSINESS_DT, 0.0  EXCHNG_RT
                   from temp_tab2 g1 inner join  TEST_TAB1 flx on g1.CMPNY_CD=flx.CMPNY_CD and g1.ORG_CRCY=flx.CURRENCY
                   and flx.EFFECTIVE_DT < g1.BUSINESS_DT group by g1.CMPNY_CD,g1.ORG_CRCY,g1.BUSINESS_DT)
    ,temp_tab1Final as ( select t1.EFFECTIVE_DT, t1.CMPNY_CD,t1.ORG_CRCY,t1.BUSINESS_DT,
       case when flx.CURRENCY  is not null then flx.EXCHNG_RT else t1.EXCHNG_RT end rate
       from temp_tab1 t1 left join TEST_TAB1 flx
       on  t1.CMPNY_CD=flx.CMPNY_CD and t1.ORG_CRCY=flx.CURRENCY and t1.EFFECTIVE_DT=flx.EFFECTIVE_DT
       )select * from temp_tab1Final
)src ON ( wk.CMPNY_CD=src.CMPNY_CD and src.ORG_CRCY =wk.ORG_CRCY )
WHEN MATCHED  THEN
UPDATE  SET FUNC_CRCY = src.rate * wk.ORG_CRCY_A;               

执行计划

--------------------------------------------------------------------------------------------------------------------
| Id  | Operation                      | Name                              | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------------------------------------------
|   0 | MERGE STATEMENT                |                                   |     1 |    39 |  2132   (1)| 00:00:01 |
|   1 |  MERGE                         | TEST_TAB2                         |       |       |            |          |
|   2 |   VIEW                         |                                   |       |       |            |          |
|   3 |    NESTED LOOPS OUTER          |                                   |     1 |   266 |  2132   (1)| 00:00:01 |
|*  4 |     HASH JOIN                  |                                   |     1 |   242 |  2130   (1)| 00:00:01 |
|   5 |      TABLE ACCESS FULL         | TEST_TAB2                         |     1 |   216 |   307   (0)| 00:00:01 |
|   6 |      VIEW                      |                                   |     1 |    26 |  1823   (1)| 00:00:01 |
|   7 |       SORT GROUP BY            |                                   |     1 |    31 |  1823   (1)| 00:00:01 |
|   8 |        NESTED LOOPS            |                                   |     1 |    31 |  1822   (1)| 00:00:01 |
|   9 |         TABLE ACCESS FULL      | TEST_TAB2                         |     1 |    15 |   307   (0)| 00:00:01 |
|* 10 |         INDEX RANGE SCAN       | TEST_TAB1_IDX1                    |    48 |   768 |  1515   (1)| 00:00:01 |
|  11 |     TABLE ACCESS BY INDEX ROWID| TEST_TAB1                         |     1 |    24 |     2   (0)| 00:00:01 |
|* 12 |      INDEX UNIQUE SCAN         | TEST_TAB1_IDX1                    |     1 |       |     1   (0)| 00:00:01 |
--------------------------------------------------------------------------------------------------------------------
 
Predicate Information (identified by operation id):
---------------------------------------------------
 
   4 - access("WK"."CMPNY_CD"="T1"."CMPNY_CD" AND "T1"."ORG_CRCY"="WK"."ORG_CRCY")
  10 - access("CMPNY_CD"="FLX"."CMPNY_CD" AND "ORG_CRCY"="FLX"."CURRENCY" AND "FLX"."EFFECTIVE_DT"<"BUSINESS_DT")
       filter("ORG_CRCY"="FLX"."CURRENCY" AND "CMPNY_CD"="FLX"."CMPNY_CD")
  12 - access("T1"."EFFECTIVE_DT"="FLX"."EFFECTIVE_DT"(+) AND "T1"."CMPNY_CD"="FLX"."CMPNY_CD"(+) AND 
              "T1"."ORG_CRCY"="FLX"."CURRENCY"(+))            

Oracle version -- Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production

示例数据

Insert into TEST_TAB1 (EFFECTIVE_DT,CMPNY_CD,CURRENCY,EXCHNG_RT,LAST_CHNG) values (to_date('15-AUG-22','DD-MON-RR'),'XYZ','USD',1.328991959599,to_timestamp('22-JAN-15 01.19.38.000000000 PM','DD-MON-RR HH.MI.SSXFF AM'));
Insert into TEST_TAB1 (EFFECTIVE_DT,CMPNY_CD,CURRENCY,EXCHNG_RT,LAST_CHNG) values (to_date('25-FEB-22','DD-MON-RR'),'XYZ','USD',1.331292018904,to_timestamp('22-JAN-15 01.19.38.000000000 PM','DD-MON-RR HH.MI.SSXFF AM'));
Insert into TEST_TAB1 (EFFECTIVE_DT,CMPNY_CD,CURRENCY,EXCHNG_RT,LAST_CHNG) values (to_date('21-JUL-05','DD-MON-RR'),'XYZ','USD',1.31743626902,to_timestamp('22-JAN-15 01.19.38.000000000 PM','DD-MON-RR HH.MI.SSXFF AM'));
Insert into TEST_TAB1 (EFFECTIVE_DT,CMPNY_CD,CURRENCY,EXCHNG_RT,LAST_CHNG) values (to_date('22-JUL-05','DD-MON-RR'),'XYZ','USD',1.306421059507,to_timestamp('22-JAN-15 01.19.38.000000000 PM','DD-MON-RR HH.MI.SSXFF AM'));
              
Insert into TEST_TAB2 (BUSINESS_DT,ORG_CRCY,ORG_CRCY_A,CMPNY_CD,FUNC_CRCY) values (to_date('28-FEB-22','DD-MON-RR'),'USD',50979531.06,'XYZ',0);
Insert into TEST_TAB2 (BUSINESS_DT,ORG_CRCY,ORG_CRCY_A,CMPNY_CD,FUNC_CRCY) values (to_date('28-FEB-22','DD-MON-RR'),'USD',1663875,'XYZ',0);
Insert into TEST_TAB2 (BUSINESS_DT,ORG_CRCY,ORG_CRCY_A,CMPNY_CD,FUNC_CRCY) values (to_date('28-FEB-22','DD-MON-RR'),'USD',-17354778.41,'XYZ',0);
Insert into TEST_TAB2 (BUSINESS_DT,ORG_CRCY,ORG_CRCY_A,CMPNY_CD,FUNC_CRCY) values (to_date('28-FEB-22','DD-MON-RR'),'USD',17216450,'XYZ',0);

优化方案

改写后的MERGE语句

优化后处理1700万+30万条数据耗时60秒:

MERGE INTO TEST_TAB2 wk USING (
select t2.CMPNY_CD,t2.org_crcy,t2.business_dt
,max(EXCHNG_RT) keep (dense_rank last order by effective_dt) rate
from TEST_TAB1 t1
join test_tab2 t2 on t1.cmpny_cd = t2.cmpny_cd and t1.currency = t2.org_crcy and t2.business_dt > t1.effective_dt
group by t2.CMPNY_CD,t2.org_crcy,t2.business_dt
) src ON ( wk.CMPNY_CD=src.CMPNY_CD and wk.org_crcy = src.org_crcy and wk.business_dt = src.business_dt)
WHEN MATCHED THEN UPDATE SET FUNC_CRCY = src.rate * wk.ORG_CRCY_A;

新增TEST_TAB2索引

CREATE INDEX TEST_TAB2_IDX1 ON TEST_TAB2 (CMPNY_CD, ORG_CRCY, BUSINESS_DT)
TABLESPACE APP_TS ; 

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 07:07:14