0

I have both DML and DDL as part of my procedure and enabled the parallel on both DML and DDL. I want to run them in Parallel mode using parallel hint but neither of them execute in parallel. Is this a limitation of using the Dynamic SQL?

For example

DECLARE
v_parallel_degree NUMBER := 8;
BEGIN
    EXECUTE IMMEDIATE 'ALTER SESSION FORCE PARALLEL DML PARALLEL ' || v_parallel_degree;
    EXECUTE IMMEDIATE 'ALTER SESSION FORCE PARALLEL QUERY PARALLEL ' || v_parallel_degree;
    EXECUTE IMMEDIATE 'ALTER SESSION FORCE PARALLEL DDL PARALLEL ' || v_parallel_degree;

    EXECUTE IMMEDIATE 'INSERT /*+PARALLEL(DEFAULT)*/ INTO '|| p_target_tabname || ' NOLOGGING
                SELECT /*+PARALLEL(dmf,DEFAULT)*/*
                FROM ' || p_source_tabname ||' PARTITION('|| p_part_name ||');
    
    EXECUTE IMMEDIATE 'CREATE UNIQUE INDEX idx_pk ON TAB_HIST
                 (COL1,COL2,COL3)
                 LOCAL
                 NOLOGGING PARALLEL ' || v_parallel_degree;
END;

I even tried the below block but not working.

v_sql := 'BEGIN
                EXECUTE IMMEDIATE ''ALTER SESSION FORCE PARALLEL DML PARALLEL ' || v_parallel_degree ||''';
                EXECUTE IMMEDIATE ''ALTER SESSION FORCE PARALLEL QUERY PARALLEL ' || v_parallel_degree ||''';
                INSERT /*+PARALLEL(DEFAULT)*/ INTO '|| p_target_tabname || ' NOLOGGING
                SELECT /*+PARALLEL(dmf,DEFAULT)*/*
                FROM ' || p_source_tabname ||' PARTITION('|| p_part_name ||') dmf;
    DBMS_OUTPUT.PUT_LINE(''Inserted '' || SQL%ROWCOUNT || '' Rows into Table- '' || p_target_tabname || '' Partition - '' || p_part_name );
                COMMIT;
              END;';
    EXECUTE IMMEDIATE v_sql;
Oracle Version -
Oracle Database 12c Enterprise Edition Release 12.1.0.2.0 - 64bit Production
PL/SQL Release 12.1.0.2.0 - Production
CORE    12.1.0.2.0  Production

Soon will be upgraded to 19c.

Any suggestions are appreciated..

TIA Venkat

Venkat
  • 107
  • 12
  • How did you identify that they do not run in parallel mode? – astentx Jul 13 '21 at 19:32
  • @astentx, I have not verified this with any query but I found the difference in execution times compared to a simple insert in the same procedure, where it was taking just 10 seconds to insert 14M rows and taking 2 mins using Dynamic SQL. Also observed the number of sessions in my Session browser. I am looking into the other answers provided here. Thank you all for the answers and will get back to you ASAP. – Venkat Jul 14 '21 at 11:46

3 Answers3

2

Is this a limitation of using the Dynamic SQL?

No.

may be helpful:

  1. parallel DML : https://docs.oracle.com/database/121/VLDBG/GUID-1D5C8D6C-0A0E-4CDB-8B32-16EC3C856ACC.htm#VLDBG1431
  2. restriction PDML: https://docs.oracle.com/database/121/VLDBG/GUID-6626C70C-876C-47A4-8C01-9B66574062D8.htm
  3. parallel DDL: https://docs.oracle.com/database/121/VLDBG/GUID-41774038-773B-40A5-BDCD-AB16A189C035.htm#VLDBG1411
2

You can start with it: https://stackoverflow.com/a/67377464/429100

Then you can check a real execution plan (Note section) and RTSM (Real-time SQL Monitor) report (select/*+ no_monitor */ dbms_sqltune.report_sql_monitor(sql_id => '&1',report_level => 'ALL',type => 'TEXT') sqlmon from dual;). They should show more information about the used DOP.

And, finally, you can trace parallel execution using the following command:

alter session set "_px_trace"="compilation","execution","messaging";

More info: "Tracing Parallel Execution with _px_trace (Doc ID 444164.1)"

Sayan Malakshinov
  • 8,492
  • 1
  • 19
  • 27
  • Thank you for your time, too much information for me.. Being a Developer, I don't seem to have access to trace. Appreciate your time – Venkat Jul 14 '21 at 16:56
2

TLDR

Most probably you forgot to enable parallel DML.

ALTER SESSION ENABLE PARALLEL DML;

Additionaly if you force parallel execution you typically do not use parallel hints and vice versa.

Sample Setup (11.2)

create table TAB_HIST (
col1 int,
col2 int,
col3 varchar2(4000))
PARTITION BY RANGE (col1) 
interval(1000000)
(
  partition p_init values less than (1000000) 
); 


create table TAB_SRC (
col1 int,
col2 int,
col3 varchar2(4000)
)
PARTITION BY RANGE (col1) 
interval(1000000)
(
  partition p_init values less than (1000000) 
);

insert into tab_src
select rownum, rownum,  rpad('x',1000,'y') from dual connect by level <= 100000;
commit;

Insert

You must enable parallel DML in the first step

ALTER SESSION ENABLE PARALLEL DML;

Note that alternatively a hint can be used

INSERT /*+ ENABLE_PARALLEL_DML */ …

Additionally if you force parallel DML and QUERY, you typically do not use parallel hints. I'm hinting a direct insert with APPEND that is often used in this situation.

DECLARE
v_parallel_degree NUMBER := 2;
BEGIN
    EXECUTE IMMEDIATE 'ALTER SESSION FORCE PARALLEL DML PARALLEL ' || v_parallel_degree;
    EXECUTE IMMEDIATE 'ALTER SESSION FORCE PARALLEL QUERY PARALLEL ' || v_parallel_degree;

    EXECUTE IMMEDIATE 'INSERT /*+ APPEND */ INTO TAB_HIST  
                SELECT  *
                FROM  TAB_SRC PARTITION(P_INIT)';
END;
/

How to check if the table was inserted in parallel? The simplest way is to query the table (before making a commit) - if you get the bellow error, it way a parallel direct insert.

select count(*) from TAB_HIST;
ORA-12838: cannot read/modify an object after modifying it in parallel

Index

If you specify a parallel degree in the create index statement you need not enable or force anything.

DECLARE
v_parallel_degree NUMBER := 2;
BEGIN
    
    EXECUTE IMMEDIATE 'CREATE UNIQUE INDEX idx_pk ON TAB_HIST
                 (COL1,COL2,COL3)
                 LOCAL
                 NOLOGGING PARALLEL ' || v_parallel_degree;
END;
/

The check is as simple as to look on the degree in data dictionary

select DEGREE from user_indexes where table_name = 'TAB_HIST';

DEGREE 
--------- 
2

Note that after creating index in parallel mode you often want to reset the DOP to one. Otherwise some simple nested loop queries may be confused and will open a parallel query...

Marmite Bomber
  • 19,886
  • 4
  • 26
  • 53
  • 1
    You are correct, Instead of FORCE PARALLEL, I should do ENABLE PARALLEL. And yes, after creating the index in Parallel mode, I have another alter index to noparallel. Thanks a lot for helping me out. This had got my effort back on track. Now both Simple insert and the dynamic SQL are done in <5mins for 480M rows and creating the UQ index is taking around 15 mins with DOP of 16. We are good with this. Thanks a lot! All the Best – Venkat Jul 14 '21 at 16:53
  • I am sorry to bug you again, now even ENABLE PARALLEL DML also not working for me, I can monitor the session is executing sequentially. The same code worked pretty well till yesterday. Do you think of any DB parameters that forcing my session to run in single thread? – Venkat Jul 24 '21 at 13:20
  • Dozens of possible causes @Venkat . Check V$PX_PROCESS_SYSSTAT` if you see `Servers Available`. Look in `v$PX_SESSTAT` for occurences of `Parallel operations downgraded to serial` – Marmite Bomber Jul 26 '21 at 08:11
  • Servers are available when I checked in V$PX_PROCESS_SYSSTAT and the number is changing for each query. I didn't quiet get the second part. I am the only developer using this DB server at this moment. I don't understand the inconsistency in picking up the parallel threads, When I am using 8, sometimes runs on 8 and other times like 6 or 4 or 1. I even added the below statements into my code after some research on this issue ``` EXECUTE IMMEDIATE 'ALTER SESSION SET parallel_degree_policy = ''AUTO'''; EXECUTE IMMEDIATE 'ALTER SESSION SET parallel_min_time_threshold = 2'; ``` – Venkat Jul 26 '21 at 09:29