oracleplsql

"PDML disabled because array binds are used"


I'm trying to delete a large number of rows from a table, but parallelism isn't fully working and the execution plan Note says "PDML disabled because array binds are used". How can I fully enable parallelism for these SQL statements?

Simplified schema

--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 delete statement

(This is a vastly simplified version of the real problem.)

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;
/

Execution plan

Find the SQL_TEXT and SQL_ID for the SQL statement:

-- (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 

Find the execution plan:

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

Missing parallelism

While the above code is using some parallelism, it's only performing the read part in parallel. There is no "PX" operation above the "DELETE" operation, so the writing is not happening in parallel.

How can I get fully parallel DML to work in the above code?


Solution

  • Oracle is saving you from yourself by not allowing parallel DML in FORALL statements. The purpose of the FORALL command is to reduce the amount of overhead for many tiny DML statement by running them in a tight, optimized loop. The purpose of parallelism is to divide-and-conquer a single SQL statement by concurrently applying a large amount of resources to the statement. The two approaches are inherently at odds with each other, and if parallel DML did fully work inside a FORALL statement, it would likely be catastrophically slow and wasteful.

    If parallelism is really needed, it's better to either re-write the PL/SQL block into a parallel SQL statement, or concurrently execute the PL/SQL block through a mechanism like multiple scheduler jobs. Don't mix bulk binding and parallel DML.