我正在尝试从表中删除大量行,但并行性并未完全发挥作用,并且执行计划注释显示“PDML 已禁用,因为使用了数组绑定”。如何才能完全启用这些 SQL 语句的并行性?
--drop table test_table;
create table test_table(a number, b number);
insert into test_table select level, level from dual connect by level <= 100000;
begin
dbms_stats.gather_table_stats(user, 'TEST_TABLE');
end;
/
(这是实际问题的极大简化版本。)
declare
v_numbers sys.odcinumberlist := sys.odcinumberlist();
begin
for i in 1 .. 100 loop
v_numbers.extend;
v_numbers(v_numbers.count) := i;
end loop;
forall i in 1 .. v_numbers.count
delete /*+ enable_parallel_dml parallel(8) */ from test_table where a = v_numbers(i);
end;
/
查找 SQL 语句的 SQL_TEXT 和 SQL_ID:
-- (The SQL_TEXT may look slightly difference since it's created from the forall command.)
select sql_text, sql_id
from gv$sql
where lower(sql_fulltext) like lower('%delete%from%test_table%where%a%')
and sql_fulltext not like '%quine%';
SQL_ID: a748dtrpfqsra
SQL_TEXT: DELETE /*+ enable_parallel_dml parallel(8) */ FROM TEST_TABLE WHERE A = :B1
查找执行计划:
select *
from table(dbms_xplan.display_cursor(sql_id => 'a748dtrpfqsra'));
SQL_ID a748dtrpfqsra, child number 0
-------------------------------------
DELETE /*+ enable_parallel_dml parallel(8) */ FROM TEST_TABLE WHERE A =
:B1
Plan hash value: 880908202
-----------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | TQ |IN-OUT| PQ Distrib |
-----------------------------------------------------------------------------------------------------------------
| 0 | DELETE STATEMENT | | | | 10 (100)| | | | |
| 1 | DELETE | TEST_TABLE | | | | | | | |
| 2 | PX COORDINATOR | | | | | | | | |
| 3 | PX SEND QC (RANDOM)| :TQ10000 | 1 | 5 | 10 (10)| 00:00:01 | Q1,00 | P->S | QC (RAND) |
| 4 | PX BLOCK ITERATOR | | 1 | 5 | 10 (10)| 00:00:01 | Q1,00 | PCWC | |
|* 5 | TABLE ACCESS FULL| TEST_TABLE | 1 | 5 | 10 (10)| 00:00:01 | Q1,00 | PCWP | |
-----------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
5 - access(:Z>=:Z AND :Z<=:Z)
filter("A"=:B1)
Note
-----
- Degree of Parallelism is 8 because of hint
- PDML disabled because array binds are used
虽然上面的代码使用了some并行性,但它仅并行执行读取部分。 “DELETE”操作之上没有“PX”操作,因此写入不是并行发生的。
如何让完全并行的 DML 在上述代码中工作?
Oracle 通过不允许在
FORALL
语句中进行并行 DML 来拯救您。 FORALL
命令的目的是通过在紧密的优化循环中运行许多微小的 DML 语句来减少它们的开销。并行的目的是通过并发地将大量资源应用于该语句来对单个 SQL 语句进行分而治之。这两种方法本质上是相互矛盾的,如果并行 DML 在 FORALL
语句中完全起作用,那么它可能会非常缓慢且浪费。
如果确实需要并行性,最好将 PL/SQL 块重写为并行 SQL 语句,或者通过多个调度程序作业等机制并发执行 PL/SQL 块。不要混合批量绑定和并行 DML。