Skip to Main Content
  • Questions
  • How to verify the parallel execution in a custom User-Defined Aggregate Function

Breadcrumb

Question and Answer

Connor McDonald

Thanks for the question, Carlos.

Asked: December 12, 2017 - 12:15 pm UTC

Last updated: December 13, 2017 - 2:56 pm UTC

Version: 11.2

Viewed 1000+ times

You Asked

I want to verify the parallel execution in my User-Defined Aggregate Function. So I put some DBMS_OUTPUT inside the code - but it seems not to work correctly...

You can reproduce the behaviour by simple create the example user-defined aggregate function "secondmax" ( https://docs.oracle.com/cd/B28359_01/appdev.111/b28425/aggr_functions.htm#BEJBFBHH ) and put a dbms_output.put_line in the odciaggregateinitialize ("init") and odciaggregatemerge ("merge") function.

Here are my testdata:

    create table secondmaxtestdata 
    as
      select * from (
      select 1                           as id,
             dbms_random.value(100,2000) as value
        from dual connect by level<=30000
      union
        select 2                         as id,
             dbms_random.value(200,1500) as value
        from dual connect by level<=8000
      );


Now check the following examples...

1)
-- we see only two "init" in dbms_output, because we have only two groups,
-- no parallel, because we don't use it
  select /*+ NO_PARALLEL */
         id,
         secondmax(value)
    from secondmaxtestdata
group by id;


2)
-- if we filter to one id, parallel is working fine, we see many "merge" outputs
select 
  /*+PARALLEL(3) */
  secondmax(value)
from
  secondmaxtestdata
where id=2;


3)
-- but without filter and parallel enabled - we see nothing (no "init" and
-- no "merge") - but why?
select 
  /*+PARALLEL(3) */
  id,
  secondmax(value)
from
  secondmaxtestdata
group by id;


Do you have any idea why my last example did not output anything???

and Chris said...

That's because parallel processes can run in a different session to the caller. And you only see the result of calls to dbms_output.put_line in your session.

In the following example, the parallel call to f shows no dbms_output. But it still logs ten rows: just in session 131 instead of the parent session 119:

create table log (
  x varchar2(100) not null
);

create or replace procedure p as
  pragma autonomous_transaction;
begin
  insert into log values (sys_context('USERENV', 'SID'));
  commit;
end p;
/

create or replace function f ( val int ) 
  return int parallel_enable as
  retval int;
begin
  p();
  dbms_output.put_line(sys_context('USERENV', 'SID'));
  return val;
end f;
/

drop table t purge;
create table t as 
  select level x from dual
  connect by level <= 10;

select /*+ parallel (2) */sum(f(x)), sys_context('USERENV', 'SID') from t;

SUM(F(X))   SYS_CONTEXT('USERENV','SID')   
         55 119   

select x, count(*) from log group by x;

X     COUNT(*)   
131           10 

truncate table log;
select /*+ no_parallel */sum(f(x)), sys_context('USERENV', 'SID') from t;

SUM(F(X))   SYS_CONTEXT('USERENV','SID')   
         55 119                            


119
119
119
119
119
119
119
119
119
119

select x, count(*) from log group by x;

X     COUNT(*)   
119           10 


The same principle applies in your code. If you want to see details of the executions, you need to log to a table.

Rating

  (2 ratings)

Is this answer out of date? If it is, please let us know via a Comment

Comments

Thanks!!!

Carlos, December 13, 2017 - 1:06 pm UTC

Great example! Perfect explanation.
Chris Saxon
December 13, 2017 - 2:56 pm UTC

Thanks :)

from v$sql dictionary

Rajeshwaran Jeyabal, December 14, 2017 - 2:23 pm UTC

The other option would be use v$sql to verify the PX executions.

demo@ORA11G> create or replace function foo(x int)
  2  return number
  3  parallel_enable
  4  as
  5  begin
  6     return x;
  7  end;
  8  /

Function created.

demo@ORA11G>
demo@ORA11G> create table t as select object_id from all_objects;

Table created.

demo@ORA11G> select /*+ parallel(t,4) */ max( foo(object_id) ) from t;

MAX(FOO(OBJECT_ID))
-------------------
              93481

demo@ORA11G>
demo@ORA11G> column sql_text format a30
demo@ORA11G> select sql_id,sql_text,child_number,executions,px_servers_executions
  2  from v$sql
  3  where lower(sql_text) like 'select /*+ parallel(t,4) */ max%'
  4  /

SQL_ID        SQL_TEXT                       CHILD_NUMBER EXECUTIONS PX_SERVERS_EXECUTIONS
------------- ------------------------------ ------------ ---------- ---------------------
gd25g4dwds5mm select /*+ parallel(t,4) */ ma            0          1                     4
              x( foo(object_id) ) from t


demo@ORA11G> select max( foo(object_id) ) from t;

MAX(FOO(OBJECT_ID))
-------------------
              93481

demo@ORA11G> select sql_id,sql_text,child_number,executions,px_servers_executions
  2  from v$sql
  3  where lower(sql_text) like 'select max( foo(object_id) ) from t%';

SQL_ID        SQL_TEXT                       CHILD_NUMBER EXECUTIONS PX_SERVERS_EXECUTIONS
------------- ------------------------------ ------------ ---------- ---------------------
3pcx827ybvgm3 select max( foo(object_id) ) f            0          1                     0
              rom t


demo@ORA11G>
demo@ORA11G> select /*+ parallel(t) */ max( foo(object_id) ) from t;

MAX(FOO(OBJECT_ID))
-------------------
              93481

demo@ORA11G> select sql_id,sql_text,child_number,executions,px_servers_executions
  2  from v$sql
  3  where lower(sql_text) like 'select /*+ parallel(t) */ max( foo(object_id) ) from t%';

SQL_ID        SQL_TEXT                       CHILD_NUMBER EXECUTIONS PX_SERVERS_EXECUTIONS
------------- ------------------------------ ------------ ---------- ---------------------
65t6fcjhqnjtt select /*+ parallel(t) */ max(            0          1                     8
               foo(object_id) ) from t


demo@ORA11G>

More to Explore

Performance

Get all the information about database performance in the Database Performance guide.