Monday, April 22, 2019

Table Elimination - Part II


In the previous blog post we discussed how table elimination – a new optimization introduced in Oracle10g Release 2 with the ability to transparently eliminate the table during the sql execution – that supported only equi/inner joins.

With Oracle 10g Release 2 the optimizer doesn’t support table elimination for outer joins, semi joins and anti joins. However, with Oracle 11g Release 1, the optimizer support table elimination for all these joins


Table elimination for outer joins:


demo@PDB1> alter session set optimizer_features_enable='11.1.0.6';

Session altered.

demo@PDB1> set autotrace traceonly explain
demo@PDB1> select e.first_name, e.last_name,e.email
  2  from hr.employees e,
  3     hr.departments d
  4  where e.department_id = d.department_id (+);

Execution Plan
----------------------------------------------------------
Plan hash value: 1445457117

-------------------------------------------------------------------------------
| Id  | Operation         | Name      | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |           |   107 |  2461 |     3   (0)| 00:00:01 |
|   1 |  TABLE ACCESS FULL| EMPLOYEES |   107 |  2461 |     3   (0)| 00:00:01 |
-------------------------------------------------------------------------------


Table elimination for Semi joins:


demo@PDB1> select e.first_name, e.last_name,e.email
  2  from hr.employees e
  3  where exists( select null
  4  from hr.departments d
  5  where e.department_id = d.department_id ) ;

Execution Plan
----------------------------------------------------------
Plan hash value: 1445457117

-------------------------------------------------------------------------------
| Id  | Operation         | Name      | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |           |   106 |  2756 |     3   (0)| 00:00:01 |
|*  1 |  TABLE ACCESS FULL| EMPLOYEES |   106 |  2756 |     3   (0)| 00:00:01 |
-------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter("E"."DEPARTMENT_ID" IS NOT NULL)



Table elimination for Anti joins:


demo@PDB1> select e.first_name, e.last_name,e.email
  2  from hr.employees e
  3  where not exists( select null
  4  from hr.departments d
  5  where e.department_id = d.department_id ) ;

Execution Plan
----------------------------------------------------------
Plan hash value: 1445457117

-------------------------------------------------------------------------------
| Id  | Operation         | Name      | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |           |     1 |    26 |     3   (0)| 00:00:01 |
|*  1 |  TABLE ACCESS FULL| EMPLOYEES |     1 |    26 |     3   (0)| 00:00:01 |
-------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter("E"."DEPARTMENT_ID" IS NULL)

demo@PDB1>


However with Oracle 11g Release 1 (prior to 11.1.0.7) – if the join key is referred elsewhere in the query other than the join condition in the where clause, table elimination cannot occur.


demo@PDB1> show parameter optimizer_features_enable

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
optimizer_features_enable            string      11.1.0.6
demo@PDB1> set autotrace traceonly explain
demo@PDB1> select e.first_name, e.last_name,e.email,d.department_id
  2  from hr.employees e,
  3     hr.departments d
  4  where e.department_id = d.department_id;

Execution Plan
----------------------------------------------------------
Plan hash value: 169719308

---------------------------------------------------------------------------------
| Id  | Operation          | Name       | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |            |   106 |  3180 |     3   (0)| 00:00:01 |
|   1 |  NESTED LOOPS      |            |   106 |  3180 |     3   (0)| 00:00:01 |
|   2 |   TABLE ACCESS FULL| EMPLOYEES  |   107 |  2782 |     3   (0)| 00:00:01 |
|*  3 |   INDEX UNIQUE SCAN| DEPT_ID_PK |     1 |     4 |     0   (0)| 00:00:01 |
---------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   3 - access("E"."DEPARTMENT_ID"="D"."DEPARTMENT_ID")

demo@PDB1> set autotrace off
demo@PDB1>
demo@PDB1>

the join key in this example is d.department_id – that is available in both the join clause and select list.  Since this join key is available in the select list, table elimination doesn’t kick in with 11.1.0.6 optimizer, however that got addressed in 11.1.0.7 optimizer.

Running the same query again the 11.1.0.7 optimizer produced the plan like this

demo@PDB1>
demo@PDB1> alter session set optimizer_features_enable='11.1.0.7';

Session altered.

demo@PDB1> set autotrace traceonly explain
demo@PDB1> select e.first_name, e.last_name,e.email,d.department_id
  2  from hr.employees e,
  3     hr.departments d
  4  where e.department_id = d.department_id;

Execution Plan
----------------------------------------------------------
Plan hash value: 1445457117

-------------------------------------------------------------------------------
| Id  | Operation         | Name      | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |           |   106 |  2756 |     3   (0)| 00:00:01 |
|*  1 |  TABLE ACCESS FULL| EMPLOYEES |   106 |  2756 |     3   (0)| 00:00:01 |
-------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter("E"."DEPARTMENT_ID" IS NOT NULL)

demo@PDB1> set autotrace off

Thursday, April 18, 2019

Table Elimination - Part I


Table elimination a new optimization technique that got introduced in Oracle 10g to remove redundant table from a query. A table is redundant if its columns are only referenced in join predicates, and its guarantee that those joins neither filter or expand the resulting rows. There are several cases where oracle will eliminate the redundant table and that got improved over the versions of Oracle database.

The optimizer eliminates tables that are redundant due to PK-FK constraints in place. Consider these data model (from HR schema) for this blog series.


And the query:

select e.first_name, e.last_name,e.email
from employees e,
     departments d
where e.department_id = d.department_id;

In this query, the join to departments is redundant. The only column d.department_id referenced in the query appears in the join predicate, and the PK-FK constraint guarantees that there is at most one match in department for each row in employees.

In 10g R1 (10.1.0.5) – no table elimination will be there.

demo@PDB1> alter session set optimizer_features_enable='10.1.0.5';

Session altered.

demo@PDB1> set autotrace traceonly explain
demo@PDB1> select e.first_name, e.last_name,e.email
  2  from hr.employees e,
  3  hr.departments d
  4  where e.department_id = d.department_id;

Execution Plan
----------------------------------------------------------
Plan hash value: 169719308

---------------------------------------------------------------------------------
| Id  | Operation          | Name       | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |            |   106 |  3180 |     3   (0)| 00:00:01 |
|   1 |  NESTED LOOPS      |            |   106 |  3180 |     3   (0)| 00:00:01 |
|   2 |   TABLE ACCESS FULL| EMPLOYEES  |   107 |  2782 |     3   (0)| 00:00:01 |
|*  3 |   INDEX UNIQUE SCAN| DEPT_ID_PK |     1 |     4 |     0   (0)| 00:00:01 |
---------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   3 - access("E"."DEPARTMENT_ID"="D"."DEPARTMENT_ID")

In 10g R2 (10.2.0.5), the table elimination will be like this.

demo@PDB1> alter session set optimizer_features_enable='10.2.0.5';

Session altered.

demo@PDB1> set autotrace traceonly explain
demo@PDB1> select e.first_name, e.last_name,e.email
  2  from hr.employees e,
  3  hr.departments d
  4  where e.department_id = d.department_id;

Execution Plan
----------------------------------------------------------
Plan hash value: 1445457117

-------------------------------------------------------------------------------
| Id  | Operation         | Name      | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |           |   106 |  2756 |     3   (0)| 00:00:01 |
|*  1 |  TABLE ACCESS FULL| EMPLOYEES |   106 |  2756 |     3   (0)| 00:00:01 |
-------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter("E"."DEPARTMENT_ID" IS NOT NULL)

demo@PDB1>

However, Oracle 10gR2 doesn’t support join elimination for queries involving Outer, Semi and Anti joins.

demo@PDB1> select e.first_name, e.last_name,e.email
  2  from hr.employees e,
  3  hr.departments d
  4  where e.department_id = d.department_id (+)
  5  /

Execution Plan
----------------------------------------------------------
Plan hash value: 3172634026

---------------------------------------------------------------------------------
| Id  | Operation          | Name       | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |            |   107 |  3210 |     3   (0)| 00:00:01 |
|   1 |  NESTED LOOPS OUTER|            |   107 |  3210 |     3   (0)| 00:00:01 |
|   2 |   TABLE ACCESS FULL| EMPLOYEES  |   107 |  2782 |     3   (0)| 00:00:01 |
|*  3 |   INDEX UNIQUE SCAN| DEPT_ID_PK |     1 |     4 |     0   (0)| 00:00:01 |
---------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   3 - access("E"."DEPARTMENT_ID"="D"."DEPARTMENT_ID"(+))


demo@PDB1> select e.first_name, e.last_name,e.email
  2  from hr.employees e
  3  where exists( select null
  4  from hr.departments d
  5  where e.department_id = d.department_id ) ;

Execution Plan
----------------------------------------------------------
Plan hash value: 1768210675

---------------------------------------------------------------------------------
| Id  | Operation          | Name       | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |            |   106 |  3180 |     3   (0)| 00:00:01 |
|   1 |  NESTED LOOPS SEMI |            |   106 |  3180 |     3   (0)| 00:00:01 |
|   2 |   TABLE ACCESS FULL| EMPLOYEES  |   107 |  2782 |     3   (0)| 00:00:01 |
|*  3 |   INDEX UNIQUE SCAN| DEPT_ID_PK |    27 |   108 |     0   (0)| 00:00:01 |
---------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   3 - access("E"."DEPARTMENT_ID"="D"."DEPARTMENT_ID")


demo@PDB1> select e.first_name, e.last_name,e.email
  2  from hr.employees e
  3  where not exists( select null
  4  from hr.departments d
  5  where e.department_id = d.department_id ) ;

Execution Plan
----------------------------------------------------------
Plan hash value: 1538847337

---------------------------------------------------------------------------------
| Id  | Operation          | Name       | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |            |     1 |    30 |     3   (0)| 00:00:01 |
|   1 |  NESTED LOOPS ANTI |            |     1 |    30 |     3   (0)| 00:00:01 |
|   2 |   TABLE ACCESS FULL| EMPLOYEES  |   107 |  2782 |     3   (0)| 00:00:01 |
|*  3 |   INDEX UNIQUE SCAN| DEPT_ID_PK |    27 |   108 |     0   (0)| 00:00:01 |
---------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   3 - access("E"."DEPARTMENT_ID"="D"."DEPARTMENT_ID")

So with Oracle 10gR2 the only supported table elimination type is Equi/Inner join.

Wednesday, April 10, 2019

In-memory cursor duration temp tables

 
Cursor duration temp tables – feature that has been around for some time – used to materialize the intermediate results of a query into temporary tables to improve performance for queries that make multiple passes over a dataset.
 
With 12.2 database introduced new In-memory cursor duration temp tables. The switch to in-memory means the queries should see reduction in IO since each pass over the data set and does not occur addition IO operations to disk. Incase if insufficient memory to load all data then Oracle would use local temp segments will be allocated to store the excess data and when an In-memory cursor duration temp table is queried, it will query both memory and private temp segments to return the data.
 
In general the memory used by the In-memory cursor duration temp table come from PGA pool.
 
Here is the query we need to run:
 
select owner,object_type,trunc(created,'Y'),count(*)
from big_table
group by grouping sets(
      (owner),
      (owner,object_type),
      (object_type,trunc(created,'Y')),
      (trunc(created,'Y')),(object_type)  ) ;
 
 
Pre 12.2 – cursor duration temp tables
 
PLAN_TABLE_OUTPUT
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------
SQL_ID  71yfn2zkk91pc, child number 0
-------------------------------------
select owner,object_type,trunc(created,'Y'),count(*) from big_table
group by grouping sets(     (owner),     (owner,object_type),
(object_type,trunc(created,'Y')),     (trunc(created,'Y')),
(object_type)  )
 
Plan hash value: 3370705251
 
----------------------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                  | Name                        | Starts | E-Rows | A-Rows | Buffers | Reads  | Writes |  OMem |  1Mem | Used-Mem |
----------------------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT           |                             |      1 |        |    448 |   29127 |  25151 |   3845 |       |       |          |
|   1 |  TEMP TABLE TRANSFORMATION |                             |      1 |        |    448 |   29127 |  25151 |   3845 |       |       |          |
|   2 |   LOAD AS SELECT           |                             |      1 |        |      0 |   21378 |  17464 |   3840 |  2068K|  2068K|          |
|   3 |    TABLE ACCESS FULL       | BIG_TABLE                   |      1 |   1000K|   1000K|   17475 |  17464 |      0 |       |       |          |
|   4 |   LOAD AS SELECT           |                             |      1 |        |      0 |    3851 |   3841 |      2 |  1040K|  1040K|          |
|   5 |    SORT GROUP BY ROLLUP    |                             |      1 |   1048 |    342 |    3846 |   3841 |      0 | 27648 | 27648 |24576  (0)|
|   6 |     TABLE ACCESS FULL      | SYS_TEMP_0FD9D6E0C_3ADC9D7D |      1 |   1000K|   1000K|    3846 |   3841 |      0 |       |       |          |
|   7 |   MULTI-TABLE INSERT       |                             |      1 |        |      0 |    3851 |   3841 |      2 |       |       |          |
|   8 |    SORT GROUP BY ROLLUP    |                             |      1 |     27 |    103 |    3843 |   3841 |      0 |  6144 |  6144 | 6144  (0)|
|   9 |     TABLE ACCESS FULL      | SYS_TEMP_0FD9D6E0C_3ADC9D7D |      1 |   1000K|   1000K|    3843 |   3841 |      0 |       |       |          |
|  10 |    DIRECT LOAD INTO        | SYS_TEMP_0FD9D6E0E_3ADC9D7D |      0 |        |      0 |       0 |      0 |      0 |       |       |          |
|  11 |    DIRECT LOAD INTO        | SYS_TEMP_0FD9D6E0D_3ADC9D7D |      0 |        |      0 |       0 |      0 |      0 |       |       |          |
|  12 |   LOAD AS SELECT           |                             |      1 |        |      0 |      11 |      1 |      1 |  1040K|  1040K|          |
|  13 |    HASH GROUP BY           |                             |      1 |      1 |      3 |       6 |      1 |      0 |  1149K|  1149K|  759K (0)|
|  14 |     TABLE ACCESS FULL      | SYS_TEMP_0FD9D6E0E_3ADC9D7D |      1 |     27 |     65 |       6 |      1 |      0 |       |       |          |
|  15 |   VIEW                     |                             |      1 |   1075 |    448 |      15 |      4 |      0 |       |       |          |
|  16 |    VIEW                    |                             |      1 |   1075 |    448 |      15 |      4 |      0 |       |       |          |
|  17 |     UNION-ALL              |                             |      1 |        |    448 |      15 |      4 |      0 |       |       |          |
|  18 |      TABLE ACCESS FULL     | SYS_TEMP_0FD9D6E0D_3ADC9D7D |      1 |   1048 |    383 |      12 |      4 |      0 |       |       |          |
|  19 |      TABLE ACCESS FULL     | SYS_TEMP_0FD9D6E0E_3ADC9D7D |      1 |     27 |     65 |       3 |      0 |      0 |       |       |          |
----------------------------------------------------------------------------------------------------------------------------------------------------
 
 
As we see at the top of the plan, we see TEMP TABLE TRANSFORMATION followed by LOAD AS SELECT, about half the way down the report we can see the additional LOAD AS SELECT statement against the temp tables containing the base level information that we need to create the various total combinations using grouping sets clause.
 
Moving to 12.2 database – the plan changes like this:
 
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------
SQL_ID  71yfn2zkk91pc, child number 0
-------------------------------------
select owner,object_type,trunc(created,'Y'),count(*) from big_table
group by grouping sets(     (owner),     (owner,object_type),
(object_type,trunc(created,'Y')),     (trunc(created,'Y')),
(object_type)  )
 
Plan hash value: 3370705251
 
---------------------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                                   | Name                        | Starts | E-Rows | A-Rows | Buffers |  OMem |  1Mem | Used-Mem |
---------------------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                            |                             |      1 |        |    448 |   17513 |       |       |          |
|   1 |  TEMP TABLE TRANSFORMATION                  |                             |      1 |        |    448 |   17513 |       |       |          |
|   2 |   LOAD AS SELECT (CURSOR DURATION MEMORY)   | SYS_TEMP_0FD9D6746_1D8EED58 |      1 |        |      0 |   17512 |  1024 |  1024 |          |
|   3 |    TABLE ACCESS FULL                        | BIG_TABLE                   |      1 |   1000K|   1000K|   17511 |       |       |          |
|   4 |   LOAD AS SELECT (CURSOR DURATION MEMORY)   | SYS_TEMP_0FD9D6747_1D8EED58 |      1 |        |      0 |       0 |  1024 |  1024 |          |
|   5 |    SORT GROUP BY ROLLUP                     |                             |      1 |   1048 |    342 |       0 | 27648 | 27648 |24576  (0)|
|   6 |     TABLE ACCESS FULL                       | SYS_TEMP_0FD9D6746_1D8EED58 |      1 |   1000K|   1000K|       0 |       |       |          |
|   7 |   MULTI-TABLE INSERT                        |                             |      1 |        |      0 |       0 |       |       |          |
|   8 |    SORT GROUP BY ROLLUP                     |                             |      1 |     27 |    103 |       0 |  6144 |  6144 | 6144  (0)|
|   9 |     TABLE ACCESS FULL                       | SYS_TEMP_0FD9D6746_1D8EED58 |      1 |   1000K|   1000K|       0 |       |       |          |
|  10 |    DIRECT LOAD INTO (CURSOR DURATION MEMORY)| SYS_TEMP_0FD9D6748_1D8EED58 |      0 |        |      0 |       0 |       |       |          |
|  11 |    DIRECT LOAD INTO (CURSOR DURATION MEMORY)| SYS_TEMP_0FD9D6747_1D8EED58 |      0 |        |      0 |       0 |       |       |          |
|  12 |   LOAD AS SELECT (CURSOR DURATION MEMORY)   | SYS_TEMP_0FD9D6747_1D8EED58 |      1 |        |      0 |       0 |  1024 |  1024 |          |
|  13 |    HASH GROUP BY                            |                             |      1 |      1 |      3 |       0 |  1149K|  1149K|  730K (0)|
|  14 |     TABLE ACCESS FULL                       | SYS_TEMP_0FD9D6748_1D8EED58 |      1 |     27 |     65 |       0 |       |       |          |
|  15 |   VIEW                                      |                             |      1 |   1075 |    448 |       0 |       |       |          |
|  16 |    VIEW                                     |                             |      1 |   1075 |    448 |       0 |       |       |          |
|  17 |     UNION-ALL                               |                             |      1 |        |    448 |       0 |       |       |          |
|  18 |      TABLE ACCESS FULL                      | SYS_TEMP_0FD9D6747_1D8EED58 |      1 |   1048 |    383 |       0 |       |       |          |
|  19 |      TABLE ACCESS FULL                      | SYS_TEMP_0FD9D6748_1D8EED58 |      1 |     27 |     65 |       0 |       |       |          |
---------------------------------------------------------------------------------------------------------------------------------------------------
 
The global stats from SQL Monitor report from 12.1 database shows this.
 
Global Stats
==============================================================================================
| Elapsed |   Cpu   |    IO    | Application | Fetch | Buffer | Read | Read  | Write | Write |
| Time(s) | Time(s) | Waits(s) |  Waits(s)   | Calls |  Gets  | Reqs | Bytes | Reqs  | Bytes |
==============================================================================================
|    1.76 |    0.96 |     0.80 |        0.00 |     4 |  29126 |  886 | 196MB |    65 |  30MB |
==============================================================================================
 
And 12.2 database shows this.
 
Global Stats
===========================================================================
| Elapsed |   Cpu   |    IO    |  Other   | Fetch | Buffer | Read | Read  |
| Time(s) | Time(s) | Waits(s) | Waits(s) | Calls |  Gets  | Reqs | Bytes |
===========================================================================
|    2.89 |    1.28 |     0.56 |     1.05 |     4 |  17513 |  250 |   2MB |
===========================================================================
 
 
In summary, with this grouping set example we have reduced the amount of IO and number of IO requests through the use of in-memory cursor duration temp tables. As with the previous report, you will see continual references to “LOAD AS SELECT”, however in 12.2 the additional set of keywords which identify the use of new in-memory cursor duration temp tables.
 
In the closing note, in-memory cursor duration temp tables are only support for serial queries and not for parallel executions. For parallel executions, Oracle switch over to cursor duration temp table(pre 12.2 approach)
 
demo@PDB1> set autotrace traceonly explain
demo@PDB1> select deptno,job,count(*)
  2  from emp
  3  group by grouping sets(
  4    (job),
  5    (deptno,job),
  6    (deptno) ) ;
 
Execution Plan
----------------------------------------------------------
Plan hash value: 2624106695
 
--------------------------------------------------------------------------------------------------------------
| Id  | Operation                                   | Name                      | Rows  | Bytes | Cost (%CPU)|
--------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                            |                           |    11 |   352 |    11  (19)|
|   1 |  TEMP TABLE TRANSFORMATION                  |                           |       |       |         |  
|   2 |   MULTI-TABLE INSERT                        |                           |       |       |         |  
|   3 |    SORT GROUP BY ROLLUP                     |                           |    11 |   121 |     4  (25)|
|   4 |     TABLE ACCESS FULL                       | EMP                       |    14 |   154 |     3   (0)|
|   5 |    DIRECT LOAD INTO (CURSOR DURATION MEMORY)| SYS_TEMP_0FD9D6A5B_3E3A37 |       |       |         |  
|   6 |    DIRECT LOAD INTO (CURSOR DURATION MEMORY)| SYS_TEMP_0FD9D6A5C_3E3A37 |       |       |         |  
|   7 |   LOAD AS SELECT (CURSOR DURATION MEMORY)   | SYS_TEMP_0FD9D6A5C_3E3A37 |       |       |         |  
|   8 |    HASH GROUP BY                            |                           |     3 |    33 |     3  (34)|
|   9 |     TABLE ACCESS FULL                       | SYS_TEMP_0FD9D6A5B_3E3A37 |    11 |   121 |     2   (0)|
|  10 |   VIEW                                      |                           |    22 |   704 |     4   (0)|
|  11 |    VIEW                                     |                           |    22 |   704 |     4   (0)|
|  12 |     UNION-ALL                               |                           |       |       |         |  
|  13 |      TABLE ACCESS FULL                      | SYS_TEMP_0FD9D6A5B_3E3A37 |    11 |   121 |     2   (0)|
|  14 |      TABLE ACCESS FULL                      | SYS_TEMP_0FD9D6A5C_3E3A37 |    11 |   121 |     2   (0)|
--------------------------------------------------------------------------------------------------------------
 
demo@PDB1>
demo@PDB1>
demo@PDB1> select /*+ parallel(e,2) */ deptno,job,count(*)
  2  from emp e
  3  group by grouping sets(
  4    (job),
  5    (deptno,job),
  6    (deptno) )  ;
 
Execution Plan
----------------------------------------------------------
Plan hash value: 1046219261
 
------------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                                  | Name                      | Rows  | Bytes | Cost (%CPU)|    TQ  |IN-OUT| PQ Distrib |
------------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                           |                           |    11 |   352 |    10  (20)|        |      |            |
|   1 |  TEMP TABLE TRANSFORMATION                 |                           |       |       |            |        |      |            |
|   2 |   PX COORDINATOR                           |                           |       |       |            |        |      |            |
|   3 |    PX SEND QC (RANDOM)                     | :TQ10002                  |       |       |            |  Q1,02 | P->S | QC (RAND)  |
|   4 |     MULTI-TABLE INSERT                     |                           |       |       |            |  Q1,02 | PCWP |            |
|   5 |      PX RECEIVE                            |                           |       |       |            |  Q1,02 | PCWP |            |
|   6 |       PX SEND ROUND-ROBIN                  | :TQ10001                  |       |       |            |  Q1,01 | P->P | RND-ROBIN  |
|   7 |        VIEW                                |                           |       |       |            |  Q1,01 | PCWP |            |
|   8 |         SORT GROUP BY ROLLUP COLLECTOR     |                           |    11 |   121 |     3  (34)|  Q1,01 | PCWP |            |
|   9 |          PX RECEIVE                        |                           |    11 |   121 |     3  (34)|  Q1,01 | PCWP |            |
|  10 |           PX SEND HYBRID HASH              | :TQ10000                  |    11 |   121 |     3  (34)|  Q1,00 | P->P | HYBRID HASH|
|  11 |            SORT GROUP BY ROLLUP DISTRIBUTOR|                           |    11 |   121 |     3  (34)|  Q1,00 | PCWP |            |
|  12 |             HASH GROUP BY                  |                           |    11 |   121 |     3  (34)|  Q1,00 | PCWP |            |
|  13 |              PX BLOCK ITERATOR             |                           |    14 |   154 |     2   (0)|  Q1,00 | PCWC |            |
|  14 |               TABLE ACCESS FULL            | EMP                       |    14 |   154 |     2   (0)|  Q1,00 | PCWP |            |
|  15 |      DIRECT LOAD INTO (TEMP SEGMENT MERGE) | SYS_TEMP_0FD9D6A5F_3E3A37 |       |       |                |  Q1,02 | PCWP |            |
|  16 |      DIRECT LOAD INTO (TEMP SEGMENT MERGE) | SYS_TEMP_0FD9D6A60_3E3A37 |       |       |                |  Q1,02 | PCWP |            |
|  17 |   PX COORDINATOR                           |                           |       |       |                |        |      |            |
|  18 |    PX SEND QC (RANDOM)                     | :TQ20001                  |     3 |    33 |     3  (34)|  Q2,01 | P->S | QC (RAND)  |
|  19 |     LOAD AS SELECT (TEMP SEGMENT MERGE)    | SYS_TEMP_0FD9D6A60_3E3A37 |       |       |                |  Q2,01 | PCWP |            |
|  20 |      HASH GROUP BY                         |                           |     3 |    33 |     3  (34)|  Q2,01 | PCWP |            |
|  21 |       PX RECEIVE                           |                           |     3 |    33 |     3  (34)|  Q2,01 | PCWP |            |
|  22 |        PX SEND HASH                        | :TQ20000                  |     3 |    33 |     3  (34)|  Q2,00 | P->P | HASH       |
|  23 |         HASH GROUP BY                      |                           |     3 |    33 |     3  (34)|  Q2,00 | PCWP |            |
|  24 |          PX BLOCK ITERATOR                 |                           |    11 |   121 |     2   (0)|  Q2,00 | PCWC |            |
|  25 |           TABLE ACCESS FULL                | SYS_TEMP_0FD9D6A5F_3E3A37 |    11 |   121 |     2   (0)|  Q2,00 | PCWP |            |
|  26 |   PX COORDINATOR                           |                           |       |       |                |           |      |            |
|  27 |    PX SEND QC (RANDOM)                     | :TQ30000                  |    22 |   704 |     4   (0)|  Q3,00 | P->S | QC (RAND)  |
|  28 |     VIEW                                   |                           |    22 |   704 |     4   (0)|  Q3,00 | PCWP |            |
|  29 |      VIEW                                  |                           |    22 |   704 |     4   (0)|  Q3,00 | PCWP |            |
|  30 |       UNION-ALL                            |                           |       |       |         |     Q3,00 | PCWP |            |
|  31 |        PX BLOCK ITERATOR                   |                           |    11 |   121 |     2   (0)|  Q3,00 | PCWC |            |
|  32 |         TABLE ACCESS FULL                  | SYS_TEMP_0FD9D6A5F_3E3A37 |    11 |   121 |     2   (0)|  Q3,00 | PCWP |            |
|  33 |        PX BLOCK ITERATOR                   |                           |    11 |   121 |     2   (0)|  Q3,00 | PCWC |            |
|  34 |         TABLE ACCESS FULL                  | SYS_TEMP_0FD9D6A60_3E3A37 |    11 |   121 |     2   (0)|  Q3,00 | PCWP |            |
------------------------------------------------------------------------------------------------------------------------------------------
 
Note
-----
   - Degree of Parallelism is 2 because of table property
 
demo@PDB1>