确保您的更新语句同时使用并行读取和并行写入 - 将 append 提示替换为 enable_parallel_dml。
示例表和数据:
--drop table my_table;
create table my_table(my_row_num number, my_date date);
insert into my_table select 1, date '2019-11-11' from dual connect by level <= 100000;
begin
dbms_stats.gather_table_stats(user, 'my_table');
end;
/
commit;
append 提示仅用于插入。虽然parallel 提示适用于整个语句,但不一定适用于 DML 部分。除非您已经运行 alter session enable parallel dml;,否则您的更新将不会完全并行化。在下面的执行计划中,并不是说第一个 PX 操作直到两个 UPDATE 操作之后才会发生。
explain plan for
update /*+ append parallel */ my_table
set my_row_num = rownum
WHERE my_date = DATE'2019-11-11';
select * from table(dbms_xplan.display);
Plan hash value: 1791278450
----------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | TQ |IN-OUT| PQ Distrib |
----------------------------------------------------------------------------------------------------------------
| 0 | UPDATE STATEMENT | | 100K| 1074K| 39 (3)| 00:00:01 | | | |
| 1 | UPDATE | MY_TABLE | | | | | | | |
| 2 | COUNT | | | | | | | | |
| 3 | PX COORDINATOR | | | | | | | | |
| 4 | PX SEND QC (RANDOM)| :TQ10000 | 100K| 1074K| 39 (3)| 00:00:01 | Q1,00 | P->S | QC (RAND) |
| 5 | PX BLOCK ITERATOR | | 100K| 1074K| 39 (3)| 00:00:01 | Q1,00 | PCWC | |
|* 6 | TABLE ACCESS FULL| MY_TABLE | 100K| 1074K| 39 (3)| 00:00:01 | Q1,00 | PCWP | |
----------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
6 - filter("MY_DATE"=TO_DATE(' 2019-11-11 00:00:00', 'syyyy-mm-dd hh24:mi:ss'))
Hint Report (identified by operation id / Query Block Name / Object Alias):
Total hints for statement: 1 (U - Unused (1))
---------------------------------------------------------------------------
0 - STATEMENT
U - parallel
Note
-----
- automatic DOP: Computed Degree of Parallelism is 2
- PDML is disabled in current session
但是对于新的 12c 提示 enable_parallel_dml,第二个 UPDATE 是 PX 操作的子代。这意味着现在写入也将并行完成。
explain plan for
update /*+ enable_parallel_dml parallel */ my_table
set my_row_num = rownum
WHERE my_date = DATE'2019-11-11';
select * from table(dbms_xplan.display);
Plan hash value: 3185872929
--------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | TQ |IN-OUT| PQ Distrib |
--------------------------------------------------------------------------------------------------------------------------
| 0 | UPDATE STATEMENT | | 100K| 1074K| 39 (3)| 00:00:01 | | | |
| 1 | PX COORDINATOR | | | | | | | | |
| 2 | PX SEND QC (RANDOM) | :TQ10002 | 100K| 1074K| 39 (3)| 00:00:01 | Q1,02 | P->S | QC (RAND) |
| 3 | UPDATE | MY_TABLE | | | | | Q1,02 | PCWP | |
| 4 | PX RECEIVE | | 100K| 1074K| 39 (3)| 00:00:01 | Q1,02 | PCWP | |
| 5 | PX SEND HASH (BLOCK ADDRESS)| :TQ10001 | 100K| 1074K| 39 (3)| 00:00:01 | Q1,01 | S->P | HASH (BLOCK|
| 6 | BUFFER SORT | | 100K| 1074K| | | Q1,01 | SCWP | |
| 7 | COUNT | | | | | | Q1,01 | SCWP | |
| 8 | PX RECEIVE | | 100K| 1074K| 39 (3)| 00:00:01 | Q1,01 | SCWP | |
| 9 | PX SEND 1 SLAVE | :TQ10000 | 100K| 1074K| 39 (3)| 00:00:01 | Q1,00 | P->S | 1 SLAVE |
| 10 | PX BLOCK ITERATOR | | 100K| 1074K| 39 (3)| 00:00:01 | Q1,00 | PCWC | |
|* 11 | TABLE ACCESS FULL | MY_TABLE | 100K| 1074K| 39 (3)| 00:00:01 | Q1,00 | PCWP | |
--------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
11 - filter("MY_DATE"=TO_DATE(' 2019-11-11 00:00:00', 'syyyy-mm-dd hh24:mi:ss'))
Hint Report (identified by operation id / Query Block Name / Object Alias):
Total hints for statement: 1 (U - Unused (1))
---------------------------------------------------------------------------
0 - STATEMENT
U - parallel
Note
-----
- automatic DOP: Computed Degree of Parallelism is 2
但是完全调优并行语句很困难。您可能希望使用select dbms_sqltune.report_sql_monitor(sql_id => 'your SQL_ID') from dual 来确保您的语句请求足够的并行会话(并行提示和配置是否足够好?),系统为其提供了足够的并行会话(是否有足够的并行会话可用?),并且该语句能够使用并行会话(是否存在序列化点,可能使用rownum 函数会阻止该语句完全使用并行性?)。