Unlike "regular" Serial Execution queries that undergo only 1 hard parse and multiple soft parses on repeated execution, Parallel Execution queries actually are hard parsed by each PX Server plus the co-ordinator at each execution.  [Correction, as noted by Yasin in his comment : Not hard parsed, but separately parsed by each PX Server]
UPDATE 26-Apr-15: See Oracle Support Note 751588.1 and Bug 6274465 to understand how the PX Servers (PQ Slaves) also parse the SQL statement.
Here's a quick demo.
First, I start with a Serial Execution query.
5 executions with no additional parse overheads.
Next, I run Parallel Execution.
Each of the 5 executions had parse overheads for each PX server.
Note : The 5 "PARSE_CALLS" per execution is a result of 4 PX servers. You might see a different number in your tests.
.
.
.
UPDATE 26-Apr-15: See Oracle Support Note 751588.1 and Bug 6274465 to understand how the PX Servers (PQ Slaves) also parse the SQL statement.
Here's a quick demo.
First, I start with a Serial Execution query.
[oracle@localhost ~]$ sqlplus hemant/hemant
SQL*Plus: Release 11.2.0.2.0 Production on Fri Apr 24 22:53:55 2015
Copyright (c) 1982, 2010, Oracle.  All rights reserved.
Connected to:
Oracle Database 11g Enterprise Edition Release 11.2.0.2.0 - Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options
HEMANT>set serveroutput off
HEMANT>alter table large_table noparallel;
Table altered.
HEMANT>select count(*) from large_table;
  COUNT(*)
----------
   4802944
HEMANT>select * from table(dbms_xplan.display_cursor);
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------
SQL_ID  5ys3vrapmbx6w, child number 0
-------------------------------------
select count(*) from large_table
Plan hash value: 3874713751
--------------------------------------------------------------------------
| Id  | Operation          | Name        | Rows  | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |             |       | 18894 (100)|          |
|   1 |  SORT AGGREGATE    |             |     1 |            |          |
|   2 |   TABLE ACCESS FULL| LARGE_TABLE |  4802K| 18894   (1)| 00:03:47 |
--------------------------------------------------------------------------
14 rows selected.
HEMANT>select
  2  executions, parse_calls, invalidations, sql_fulltext
  3  from v$sqlstats
  4  where sql_id = '5ys3vrapmbx6w';
EXECUTIONS PARSE_CALLS INVALIDATIONS SQL_FULLTEXT
---------- ----------- ------------- --------------------------------------------------------------------------------
         1           1             0 select count(*) from large_table
HEMANT>
HEMANT>select count(*) from large_table;
  COUNT(*)
----------
   4802944
HEMANT>select
  2  executions, parse_calls, invalidations, sql_fulltext
  3  from v$sqlstats
  4  where sql_id = '5ys3vrapmbx6w';
EXECUTIONS PARSE_CALLS INVALIDATIONS SQL_FULLTEXT
---------- ----------- ------------- --------------------------------------------------------------------------------
         2           2             0 select count(*) from large_table
HEMANT>
HEMANT>select count(*) from large_table;
  COUNT(*)
----------
   4802944
HEMANT>select
  2  executions, parse_calls, invalidations, sql_fulltext
  3  from v$sqlstats
  4  where sql_id = '5ys3vrapmbx6w';
EXECUTIONS PARSE_CALLS INVALIDATIONS SQL_FULLTEXT
---------- ----------- ------------- --------------------------------------------------------------------------------
         3           3             0 select count(*) from large_table
HEMANT>
HEMANT>select count(*) from large_table;
  COUNT(*)
----------
   4802944
HEMANT>select
  2  executions, parse_calls, invalidations, sql_fulltext
  3  from v$sqlstats
  4  where sql_id = '5ys3vrapmbx6w';
EXECUTIONS PARSE_CALLS INVALIDATIONS SQL_FULLTEXT
---------- ----------- ------------- --------------------------------------------------------------------------------
         4           4             0 select count(*) from large_table
HEMANT>
HEMANT>select count(*) from large_table;
  COUNT(*)
----------
   4802944
HEMANT>select
  2  executions, parse_calls, invalidations, sql_fulltext
  3  from v$sqlstats
  4  where sql_id = '5ys3vrapmbx6w';
EXECUTIONS PARSE_CALLS INVALIDATIONS SQL_FULLTEXT
---------- ----------- ------------- --------------------------------------------------------------------------------
         5           5             0 select count(*) from large_table
HEMANT>
5 executions with no additional parse overheads.
Next, I run Parallel Execution.
[oracle@localhost ~]$ sqlplus hemant/hemant
SQL*Plus: Release 11.2.0.2.0 Production on Fri Apr 24 23:04:45 2015
Copyright (c) 1982, 2010, Oracle.  All rights reserved.
Connected to:
Oracle Database 11g Enterprise Edition Release 11.2.0.2.0 - Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options
HEMANT>set serveroutput off
HEMANT>alter table large_table parallel 4;
Table altered.
HEMANT>select /*+ PARALLEL */ count(*) from large_table;
  COUNT(*)
----------
   4802944
HEMANT>select * from table(dbms_xplan.display_cursor);
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------
SQL_ID  4wd97vn0ytfmc, child number 0
-------------------------------------
select /*+ PARALLEL */ count(*) from large_table
Plan hash value: 2085386270
-----------------------------------------------------------------------------------------------------------
| Id  | Operation              | Name        | Rows  | Cost (%CPU)| Time     |    TQ  |IN-OUT| PQ Distrib |
-----------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT       |             |       |  1311 (100)|          |        |      |            |
|   1 |  SORT AGGREGATE        |             |     1 |            |          |        |      |            |
|   2 |   PX COORDINATOR       |             |       |            |          |        |      |            |
|   3 |    PX SEND QC (RANDOM) | :TQ10000    |     1 |            |          |  Q1,00 | P->S | QC (RAND)  |
|   4 |     SORT AGGREGATE     |             |     1 |            |          |  Q1,00 | PCWP |            |
|   5 |      PX BLOCK ITERATOR |             |  4802K|  1311   (1)| 00:00:16 |  Q1,00 | PCWC |            |
|*  6 |       TABLE ACCESS FULL| LARGE_TABLE |  4802K|  1311   (1)| 00:00:16 |  Q1,00 | PCWP |            |
-----------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   6 - access(:Z>=:Z AND :Z<=:Z)
Note
-----
   - automatic DOP: skipped because of IO calibrate statistics are missing
27 rows selected.
HEMANT>select
  2  executions, parse_calls, invalidations, sql_fulltext
  3  from v$sqlstats
  4  where sql_id = '4wd97vn0ytfmc';
EXECUTIONS PARSE_CALLS INVALIDATIONS SQL_FULLTEXT
---------- ----------- ------------- --------------------------------------------------------------------------------
         1           5             0 select /*+ PARALLEL */ count(*) from large_table
HEMANT>
HEMANT>select /*+ PARALLEL */ count(*) from large_table;
  COUNT(*)
----------
   4802944
HEMANT>select
  2  executions, parse_calls, invalidations, sql_fulltext
  3  from v$sqlstats
  4  where sql_id = '4wd97vn0ytfmc';
EXECUTIONS PARSE_CALLS INVALIDATIONS SQL_FULLTEXT
---------- ----------- ------------- --------------------------------------------------------------------------------
         2          10             0 select /*+ PARALLEL */ count(*) from large_table
HEMANT>
HEMANT>select /*+ PARALLEL */ count(*) from large_table;
  COUNT(*)
----------
   4802944
HEMANT>select
  2  executions, parse_calls, invalidations, sql_fulltext
  3  from v$sqlstats
  4  where sql_id = '4wd97vn0ytfmc';
EXECUTIONS PARSE_CALLS INVALIDATIONS SQL_FULLTEXT
---------- ----------- ------------- --------------------------------------------------------------------------------
         3          15             0 select /*+ PARALLEL */ count(*) from large_table
HEMANT>
HEMANT>select /*+ PARALLEL */ count(*) from large_table;
  COUNT(*)
----------
   4802944
HEMANT>select
  2  executions, parse_calls, invalidations, sql_fulltext
  3  from v$sqlstats
  4  where sql_id = '4wd97vn0ytfmc';
EXECUTIONS PARSE_CALLS INVALIDATIONS SQL_FULLTEXT
---------- ----------- ------------- --------------------------------------------------------------------------------
         4          20             0 select /*+ PARALLEL */ count(*) from large_table
HEMANT>
HEMANT>select /*+ PARALLEL */ count(*) from large_table;
  COUNT(*)
----------
   4802944
HEMANT>select
  2  executions, parse_calls, invalidations, sql_fulltext
  3  from v$sqlstats
  4  where sql_id = '4wd97vn0ytfmc';
EXECUTIONS PARSE_CALLS INVALIDATIONS SQL_FULLTEXT
---------- ----------- ------------- --------------------------------------------------------------------------------
         5          25             0 select /*+ PARALLEL */ count(*) from large_table
HEMANT>
Each of the 5 executions had parse overheads for each PX server.
Note : The 5 "PARSE_CALLS" per execution is a result of 4 PX servers. You might see a different number in your tests.
.
.
.
4 comments:
Hi Hemant,
Parallel queries are not hard parsed each time. The number of parses you see comes from the query coordinator and the PX servers. Since you are using a DOP of 4 you see 5 parses each time you run the statement, one query coordinator, four PX servers. With a DOP of 2 you would see 3 parses for example. Please see the following example which shows the second execution of a query with DOP=2. There are 6 parses because of 2 executions but no hard parses.
SQL> select n.name,s.VALUE from v$mystat s,v$statname n where s.STATISTIC#=n.STATISTIC# and n.name like 'parse count%' ;
NAME VALUE
------------------------------ -----------
parse count (total) 259
parse count (hard) 102
parse count (failures) 0
parse count (describe) 0
Elapsed: 00:00:00.01
SQL> select /*+ parallel(2) */ count(*) from sales;
COUNT(*)
----------
960
Elapsed: 00:00:00.02
SQL> select n.name,s.VALUE from v$mystat s,v$statname n where s.STATISTIC#=n.STATISTIC# and n.name like 'parse count%' ;
NAME VALUE
------------------------------ -----------
parse count (total) 263
parse count (hard) 102
parse count (failures) 0
parse count (describe) 0
Elapsed: 00:00:00.00
SQL> select parse_Calls,sql_text from v$sql where lower(sql_text) like '%sales%';
PARSE_CALLS SQL_TEXT
----------- --------------------------------------------------------------------------------
6 select /*+ parallel(2) */ count(*) from sales
2 select parse_Calls,sql_text from v$sql where lower(sql_text) like '%sales%'
3 select parse_Calls,sql_text from v$sql where lower(sql_text) like '%sales%'
Yasin Baskan
Product Manager for Parallel Execution
Yasin,
Thank you for the correction.
Thanks Hemant for posts on parallel series, In my case I could only see 5 executions during first run, all subsequent executions have only 4 parse calls per execution. I am using parallel(4) hint instead of modifying object degree.
SQL> select executions, parse_calls, invalidations, sql_fulltext from v$sqlstats where sql_id = 'fg52yv7v85zjy';
EXECUTIONS PARSE_CALLS INVALIDATIONS
---------- ----------- -------------
SQL_FULLTEXT
--------------------------------------------------------------------------------
1 5 0
select /*+ PARALLEL(4) */ count(*) from rakesh_objects
SQL> select /*+ PARALLEL(4) */ count(*) from rakesh_objects;
COUNT(*)
----------
18010
SQL> select executions, parse_calls, invalidations, sql_fulltext from v$sqlstats where sql_id = 'fg52yv7v85zjy';
EXECUTIONS PARSE_CALLS INVALIDATIONS
---------- ----------- -------------
SQL_FULLTEXT
--------------------------------------------------------------------------------
2 9 0
select /*+ PARALLEL(4) */ count(*) from rakesh_objects
SQL> select /*+ PARALLEL(4) */ count(*) from rakesh_objects;
COUNT(*)
----------
18010
SQL> select executions, parse_calls, invalidations, sql_fulltext from v$sqlstats where sql_id = 'fg52yv7v85zjy';
EXECUTIONS PARSE_CALLS INVALIDATIONS
---------- ----------- -------------
SQL_FULLTEXT
--------------------------------------------------------------------------------
3 13 0
select /*+ PARALLEL(4) */ count(*) from rakesh_objects
SQL> select /*+ PARALLEL(4) */ count(*) from rakesh_objects;
COUNT(*)
----------
18010
SQL> select executions, parse_calls, invalidations, sql_fulltext from v$sqlstats where sql_id = 'fg52yv7v85zjy';
EXECUTIONS PARSE_CALLS INVALIDATIONS
---------- ----------- -------------
SQL_FULLTEXT
--------------------------------------------------------------------------------
4 17 0
select /*+ PARALLEL(4) */ count(*) from rakesh_objects
Thanks
Rakesh
Rakesh,
Query V$SQL to see if you had 2 child cursors. V$SQLSTATS aggregates across the child cursors.
Post a Comment