Oracle上的大规模更新与合并性能
我试图使用一个庞大的Oracle上的大规模更新与合并性能,oracle,sql-update,query-optimization,oracle12c,sql-merge,Oracle,Sql Update,Query Optimization,Oracle12c,Sql Merge,我试图使用一个庞大的update语句从源表更新目标表,但执行时间比应该的要长得多 查询 UPDATE MY_DEST SET (DEST_B, DEST_C) = ( SELECT SRC_A + SRC_B, SRC_B FROM MY_SRC WHERE SRC_KEY = DEST_KEY AND SRC_DATE = DEST_DATE ); 这两个表都包含大约1000万到1300万行,它们有匹配的主键,我们可以安全地假设目标表中的每一行在源表中都有对应的行 表格定义 CR
update
语句从源表更新目标表,但执行时间比应该的要长得多
查询
UPDATE MY_DEST
SET (DEST_B, DEST_C) = (
SELECT SRC_A + SRC_B, SRC_B
FROM MY_SRC
WHERE SRC_KEY = DEST_KEY AND SRC_DATE = DEST_DATE
);
这两个表都包含大约1000万到1300万行,它们有匹配的主键,我们可以安全地假设目标表中的每一行在源表中都有对应的行
表格定义
CREATE TABLE MY_SRC (
SRC_KEY VARCHAR2(50),
SRC_DATE DATE,
SRC_A NUMBER(15,2),
SRC_B NUMBER(15,2),
CONSTRAINT MY_SRC_PK PRIMARY KEY (SRC_KEY, SRC_DATE)
);
CREATE TABLE MY_DEST (
DEST_KEY VARCHAR2(50),
DEST_DATE DATE,
DEST_B NUMBER(15,2),
DEST_C NUMBER(15,2),
CONSTRAINT MY_DEST_PK PRIMARY KEY (DEST_KEY, DEST_DATE)
);
执行计划
Plan hash value: 3904754293
------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------------------
| 0 | UPDATE STATEMENT | | 12M| 675M| 128M (20)| 01:23:55 |
| 1 | UPDATE | MY_DEST | | | | |
| 2 | TABLE ACCESS FULL | MY_DEST | 12M| 675M| 69756 (1)| 00:00:03 |
| 3 | TABLE ACCESS BY INDEX ROWID| MY_SRC | 1 | 46 | 4 (0)| 00:00:01 |
|* 4 | INDEX UNIQUE SCAN | MY_SRC_PK | 1 | | 3 (0)| 00:00:01 |
------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
4 - access("SRC_KEY"=:B1 AND "SRC_DATE"=:B2)
问题
CREATE TABLE MY_SRC (
SRC_KEY VARCHAR2(50),
SRC_DATE DATE,
SRC_A NUMBER(15,2),
SRC_B NUMBER(15,2),
CONSTRAINT MY_SRC_PK PRIMARY KEY (SRC_KEY, SRC_DATE)
);
CREATE TABLE MY_DEST (
DEST_KEY VARCHAR2(50),
DEST_DATE DATE,
DEST_B NUMBER(15,2),
DEST_C NUMBER(15,2),
CONSTRAINT MY_DEST_PK PRIMARY KEY (DEST_KEY, DEST_DATE)
);
UPDATE
查询是否无望地被迫使用缓慢的逐行执行计划
MERGE
语句来优化它,例如下面的语句
- 替代查询,重写为
合并
MERGE INTO MY_DEST USING (SELECT SRC_KEY, SRC_DATE, SRC_B, SRC_A + SRC_B AS SRC_C FROM MY_SRC) ON (DEST_KEY = SRC_KEY AND DEST_DATE = SRC_DATE) WHEN MATCHED THEN UPDATE SET DEST_B = SRC_B, DEST_C = SRC_C;
- 替代执行计划
Plan hash value: 2444580570 ---------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time | ---------------------------------------------------------------------------------------- | 0 | MERGE STATEMENT | | 12M| 638M| | 359K (1)| 00:00:15 | | 1 | MERGE | MY_DEST | | | | | | | 2 | VIEW | | | | | | | |* 3 | HASH JOIN | | 12M| 2260M| 716M| 359K (1)| 00:00:15 | | 4 | TABLE ACCESS FULL| MY_SRC | 12M| 568M| | 162K (1)| 00:00:07 | | 5 | TABLE ACCESS FULL| MY_DEST | 12M| 1695M| | 69756 (1)| 00:00:03 | ---------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 3 - access("DEST_KEY"="SRC_KEY" AND "DEST_DATE"="SRC_DATE")
--------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time | --------------------------------------------------------------------------------------- | 0 | UPDATE STATEMENT | | 1000K| 57M| | 6682 (1)| 00:00:01 | | 1 | UPDATE | MY_DEST | | | | | | |* 2 | HASH JOIN OUTER | | 1000K| 57M| 40M| 6682 (1)| 00:00:01 | | 3 | TABLE ACCESS FULL| MY_DEST | 1000K| 28M| | 1341 (2)| 00:00:01 | | 4 | TABLE ACCESS FULL| MY_SRC | 1000K| 28M| | 1341 (2)| 00:00:01 | --------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 2 - access("D"."DEST_DATE"="S"."SRC_DATE"(+) AND "D"."DEST_KEY"="S"."SRC_KEY"(+))
更新
时,我能否获得与备用合并
语句相同的良好性能
UPDATE
语句,在设置中不会出现问题。您将使用
质疑
执行计划
Plan hash value: 2444580570
----------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |
----------------------------------------------------------------------------------------
| 0 | MERGE STATEMENT | | 12M| 638M| | 359K (1)| 00:00:15 |
| 1 | MERGE | MY_DEST | | | | | |
| 2 | VIEW | | | | | | |
|* 3 | HASH JOIN | | 12M| 2260M| 716M| 359K (1)| 00:00:15 |
| 4 | TABLE ACCESS FULL| MY_SRC | 12M| 568M| | 162K (1)| 00:00:07 |
| 5 | TABLE ACCESS FULL| MY_DEST | 12M| 1695M| | 69756 (1)| 00:00:03 |
----------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - access("DEST_KEY"="SRC_KEY" AND "DEST_DATE"="SRC_DATE")
---------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |
---------------------------------------------------------------------------------------
| 0 | UPDATE STATEMENT | | 1000K| 57M| | 6682 (1)| 00:00:01 |
| 1 | UPDATE | MY_DEST | | | | | |
|* 2 | HASH JOIN OUTER | | 1000K| 57M| 40M| 6682 (1)| 00:00:01 |
| 3 | TABLE ACCESS FULL| MY_DEST | 1000K| 28M| | 1341 (2)| 00:00:01 |
| 4 | TABLE ACCESS FULL| MY_SRC | 1000K| 28M| | 1341 (2)| 00:00:01 |
---------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("D"."DEST_DATE"="S"."SRC_DATE"(+) AND
"D"."DEST_KEY"="S"."SRC_KEY"(+))
您可以看到,为合并创建了类似的执行计划,因此您也将看到类似的性能
最终注释
CREATE TABLE MY_SRC (
SRC_KEY VARCHAR2(50),
SRC_DATE DATE,
SRC_A NUMBER(15,2),
SRC_B NUMBER(15,2),
CONSTRAINT MY_SRC_PK PRIMARY KEY (SRC_KEY, SRC_DATE)
);
CREATE TABLE MY_DEST (
DEST_KEY VARCHAR2(50),
DEST_DATE DATE,
DEST_B NUMBER(15,2),
DEST_C NUMBER(15,2),
CONSTRAINT MY_DEST_PK PRIMARY KEY (DEST_KEY, DEST_DATE)
);
您还可以使用并行提示来加速
不要忘记您必须在会话中启用
ALTER SESSION ENABLE PARALLEL DML;
您的MERGE
语句与第一个UPDATE
语句不相等。
当目标表中存在主键而源表中不存在主键时,会出现差异
UPDATE
将目标列重置为NULL
,而MERGE
将其保持不变
我的UPDATE
语句使用外部联接,因此它的行为与您的UPDATE
相同-切换到内部联接以获得MERGE
行为。您的MERGE语句是否比UPDATE语句运行得更快?如果是的话,我会用它来代替。通过在when matched
子句中添加谓词以仅在必要时更新,例如where dest_b!=src_b或dest_c!=src_c
。如果所有或大多数行匹配,性能将不会有太大的改善,但如果这是一个频繁运行的过程(例如,每天),您可能会看到一些好处。@ Boeistor这是一个很好的点,与预处理有关,但你不应该伪造列是代码> null <代码>,并考虑它在你的谓词。例如'nvl(dest_b,'x')!=nvl(src_b,'x'),以获得原始语句的确切行为。@MarmiteBomber精彩的一点!