This little note on how dbms_xplan.display_cursor() behaves was prompted by a very simple question on OTN which raised a point that I often manage to forget (temporarily): “Why don’t I see all the execution plans for the SQL_ID I’ve supplied?” I’ve chosen to explain it through a little demonstration.
Session 1 – cut-n-paste (with minor cosmetic changes):
SQL> set pagesize 60 SQL> set linesize 180 SQL> set trimspool on SQL> set tab off SQL> set serveroutput off SQL> select max(n2) from t1 where n1 = 15; MAX(N2) ---------- 15 1 row selected. SQL> select * from table(dbms_xplan.display_cursor); PLAN_TABLE_OUTPUT -------------------- SQL_ID b8ud16xgnsgt7, child number 0 ------------------------------------- select max(n2) from t1 where n1 = 15 Plan hash value: 269862921 -------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | -------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | | | 2 (100)| | | 1 | SORT AGGREGATE | | 1 | 8 | | | | 2 | TABLE ACCESS BY INDEX ROWID| T1 | 15 | 120 | 2 (0)| 00:00:01 | |* 3 | INDEX RANGE SCAN | T1_I1 | 15 | | 1 (0)| 00:00:01 | -------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 3 - access("N1"=15) 20 rows selected.
Session 2 – cut-n-paste:
SQL> set pagesize 60 SQL> set linesize 180 SQL> set trimspool on SQL> set tab off SQL> set serveroutput off SQL> alter session set workarea_size_policy = manual; Session altered. SQL> select max(n2) from t1 where n1 = 15; MAX(N2) ---------- 15 1 row selected. SQL> select * from table(dbms_xplan.display_cursor); PLAN_TABLE_OUTPUT -------------------- SQL_ID b8ud16xgnsgt7, child number 1 ------------------------------------- select max(n2) from t1 where n1 = 15 Plan hash value: 269862921 -------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | -------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | | | 2 (100)| | | 1 | SORT AGGREGATE | | 1 | 8 | | | | 2 | TABLE ACCESS BY INDEX ROWID| T1 | 15 | 120 | 2 (0)| 00:00:01 | |* 3 | INDEX RANGE SCAN | T1_I1 | 15 | | 1 (0)| 00:00:01 | -------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 3 - access("N1"=15) 20 rows selected. SQL>
Because I’ve changed the optimizer environment for the second session Oracle has created a second child cursor for query – even though the execution plan turned out to be exactly the same. (The fact that you can get two child cursors with the same plan sometimes surprises people but it’s not a rare occurrence.) You’ll notice that the two sessions report different values for child number.
So let’s use a third session to find the plans for the sql_id that the previous outputs report: b8ud16xgnsgt7. Here’s the complete cut-n-paste (again with minor cosmetic changes):
SQL> set pagesize 60 SQL> set linesize 180 SQL> set trimspool on SQL> set tab off SQL> select * from table(dbms_xplan.display_cursor('b8ud16xgnsgt7')); PLAN_TABLE_OUTPUT -------------------- SQL_ID b8ud16xgnsgt7, child number 0 ------------------------------------- select max(n2) from t1 where n1 = 15 Plan hash value: 269862921 -------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | -------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | | | 2 (100)| | | 1 | SORT AGGREGATE | | 1 | 8 | | | | 2 | TABLE ACCESS BY INDEX ROWID| T1 | 15 | 120 | 2 (0)| 00:00:01 | |* 3 | INDEX RANGE SCAN | T1_I1 | 15 | | 1 (0)| 00:00:01 | -------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 3 - access("N1"=15) 20 rows selected
Question: We’ve got the execution plan for child_number 0, what happened to child_number 1 ?
Answer: We didn’t ask for it.
The default value for the second parameter to display_cursor() is zero. If you want to see all the available execution plans for a given sql_id, you need to supply an explicit null to the call, viz:
SQL> select * from table(dbms_xplan.display_cursor('b8ud16xgnsgt7',null));
(I won’t bother to cut-n-paste the output – it just lists the two plans one after the other in child_number order reporting a total of 40 rows selected.)
If you want to read other notes that make significant points about dbms_xplan, there’s an entry for it in the Categories drop-down list to the top right of the screen.
Footnote:
Take note of the four formatting (set) commands I’ve issued in SQL*Plus. Execution plans tend to be quite long and can have some wide bits of white space . If someone asks you to supply an execution plan on one of the Oracle forums or mailing lists then some suitable format settings will make the output much easier to read – you don’t want to see lines wrapping and page heading every few lines, and columns failing to align, if you’re trying to work out what the plan is saying.
Note also that for SQL*Plus, you need to set serveroutput off if you’re going to call dbms_xplan.display_cursor() without an SQL_ID or the last statement you executed (behind the scenes) will be a call to dbms_output() and you’ll get a surprising error message about being unable to find a cursor.
Update (Aug 2021)
A quick check of dbms_xplan.display_cursor() and the manuals, shows that (a) the behaviour hasn’t changed and (b) the documentation bug described by Randof Geist in comment #1 below (and raised by Greg Rahn in response) has not been fixed.
It’s not only easy to forget, it’s also a documentation bug, see here in the documentation:
Quote from above docu:
But if one checks the actual declaration of the function:
Note to myself: Should have filed a documentation bug for this long time ago…
Randolf
Comment by Randolf Geist — August 16, 2011 @ 1:36 pm BST Aug 16,2011 |
Filed. Bug 12879906
Comment by Greg Rahn — August 16, 2011 @ 8:45 pm BST Aug 16,2011 |
Greg,
thanks – much appreciated.
Randolf
Comment by Randolf Geist — August 17, 2011 @ 10:31 pm BST Aug 17,2011 |
Nice reminder. dbms_xplan has a rich set of parameters we usually skip for convenience.
About the multiple children: I grok why they have to create “child 1” because the session environment difference *might* mean a different plan is better. And if “child 1” were different, of course it would remain separate. What I don’t get is why they don’t merge identical twin plans to save the space.
Also nice use of viz!
Comment by Mark W. Farnham — August 16, 2011 @ 12:51 pm BST Aug 16,2011 |
We should not use
select * from table(dbms_xplan.display_cursor(‘b8ud16xgnsgt7’,null));
at all.
http://download.oracle.com/docs/cd/E11882_01/appdev.112/e17126/subprograms.htm#i4072
recommends us to use named notation “when you invoke a subprogram defined or maintained by someone else.”
(since 11, we can use named notation also for PL/SQL called from SQL)
So, we should use
select * from table(dbms_xplan.display_cursor(sql_id => ‘b8ud16xgnsgt7’, child_number=>null));
( Parameters as documented )
and would receive
ORA-06553: PLS-306: wrong number or types of arguments in call to ‘DISPLAY_CURSOR’
which would show us the documentation bug Randolf is writing about.
Comment by Matthias Rogel — August 16, 2011 @ 3:03 pm BST Aug 16,2011 |
This doesn’t work for me:
Comment by Mladen Gogala — August 16, 2011 @ 4:30 pm BST Aug 16,2011 |
Ah, don’t worry! I figured it out. The problem is in set serveroutput on. When I disable the server output, I get the behavior you describe.
Comment by Mladen Gogala — August 16, 2011 @ 4:33 pm BST Aug 16,2011 |
Factly,when we troubleshooting,we should find the sql_id and child_number,then get exection plan by query:
Comment by leo — August 17, 2011 @ 1:35 am BST Aug 17,2011 |
Jonathan,
a somewhat related question: does dbms_xplan.display_cursor work with RAC? With event 10046 I see an access on v$sql (and not gv$sql) when using dbms_xplan.display_cursor on a non-RAC-DB:
On a RAC DB (without the option to create a sql_trace) I get no result from dbms_xplan.display_cursor for a given sql_id/child_number and no result from v$sql_plan, but when I ask gv$sql_plan I see some lines:
In Morgan’s Library (http://www.morganslibrary.org/reference/pkgs/dbms_xplan.html#dxdc) I find for “display_cursor” the description “Display from GV$SQL_PLAN (or GV$SQL_PLAN_STATISTICS_ALL)” – but the documentation (http://download.oracle.com/docs/cd/B28359_01/appdev.111/b28419/d_xplan.htm#CACFJGHG) says “The table function DISPLAY_CURSOR requires to have select privileges on the following fixed views: V$SQL_PLAN, V$SESSION and V$SQL_PLAN_STATISTICS_ALL”.
Of course if I am lucky and on the appropriate node I get my results – but is this a limitation of dbms_xplan.display_cursor or do I miss an important point?
Regards
Martin
Comment by Martin Preiss — August 17, 2011 @ 9:59 am BST Aug 17,2011 |
With RAC, presumably each node could have a child 1, each with different plans? So the answer should depend on which node you run it.
Comment by Dom Brooks — August 17, 2011 @ 4:35 pm BST Aug 17,2011 |
Dom,
thank you for your comment. I think it would be helpful if there was an additional node parameter for display_cursor.
Regards
Martin
Comment by Martin Preiss — August 18, 2011 @ 6:11 am BST Aug 18,2011 |
I had a similar question, and foundt his, maybe it helps:
http://practical-sql-tuning.blogspot.com/2009/10/dbmsxplandisplaycursor-for-rac-database.html
not beeing able to create, this, I just did it like this manually and it worked on a 2 node cluster (with inst_id, slq_id and childnmber inserted)
select * from table(dbms_xplan.display(‘gv$sql_plan_statistics_all’, null, null,
‘inst_id=2 and sql_id=”…….” and CHILD_NUMBER=0’));
Comment by stefan — August 30, 2011 @ 10:51 am BST Aug 30,2011 |
Stefan,
Cunning solution.
Thanks for the reference.
Comment by Jonathan Lewis — September 1, 2011 @ 4:18 pm BST Sep 1,2011 |
Stefan,
thank you for the link and the information. That’s what I was looking for.
Regards
Martin
Comment by Martin Preiss — August 30, 2011 @ 11:48 am BST Aug 30,2011 |