“PDML 已禁用,因为使用了数组绑定”

问题描述 投票:0回答:1

我正在尝试从表中删除大量行,但并行性并未完全发挥作用,并且执行计划注释显示“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;
/

FORALL 删除语句

(这是实际问题的极大简化版本。)

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 plsql
1个回答
0
投票

Oracle 通过不允许在

FORALL
语句中进行并行 DML 来拯救您。
FORALL
命令的目的是通过在紧密的优化循环中运行许多微小的 DML 语句来减少它们的开销。并行的目的是通过并发地将大量资源应用于该语句来对单个 SQL 语句进行分而治之。这两种方法本质上是相互矛盾的,如果并行 DML 在
FORALL
语句中完全起作用,那么它可能会非常缓慢且浪费。

如果确实需要并行性,最好将 PL/SQL 块重写为并行 SQL 语句,或者通过多个调度程序作业等机制并发执行 PL/SQL 块。不要混合批量绑定和并行 DML。

© www.soinside.com 2019 - 2024. All rights reserved.