[More in dbms_xplan.display_cursor()]
If you’re using 9i and haven’t learned about the dbms_xplan package, then you should take a good look at it right away. It’s (usually) a much better way of getting execution plans from your system than writing your own queries against the plan_table.
If you’ve been using dbms_xplan, and upgraded from 9i to 10g, make sure that you look at the new features – there are some things which are really useful, and this note is about just one of them.
dbms_xplan.display_cursor()
In 10g, Oracle instroduced a new function in dbms_xplan that can read the in-memory execution plan (v$sql_plan and associated structures). The call is the display_cursor call, and takes three optional parameters, the sql_id and child_number of the sql statement you want to see the plan for, and a formatting string.
The best bit of this function shows up when you look at the script that generates it($ORACLE_HOME/rdbms/admin/dbmsxpln.sql) when you decide to find out how to use the format parameter. Here’s a “live” demo:
set serveroutput off
select
/*+
gather_plan_statistics
ordered use_nl(t1) index(t1)
*/
count(t1.n2), count(t2.n2)
from
t2, t1
where
t2.n2 = 45
and t1.n1 = t2.n1
;
COUNT(T1.N2) COUNT(T2.N2)
------------ ------------
225 225
select * from table(dbms_xplan.display_cursor(null,null,'ALLSTATS LAST'));
PLAN_TABLE_OUTPUT
-------------------------------------
SQL_ID 98cw5a9c0pw33, child number 0
-------------------------------------
select /*+ gather_plan_statistics ordered use_nl(t1) index(t1) */ count(t1.n2),
count(t2.n2) from t2, t1 where t2.n2 = 45 and t1.n1 = t2.n1
Plan hash value: 3795562434
-----------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
-----------------------------------------------------------------------------------------------
| 1 | SORT AGGREGATE | | 1 | 1 | 1 |00:00:00.01 | 146 |
| 2 | TABLE ACCESS BY INDEX ROWID| T1 | 1 | 15 | 225 |00:00:00.01 | 146 |
| 3 | NESTED LOOPS | | 1 | 225 | 241 |00:00:00.02 | 116 |
|* 4 | TABLE ACCESS FULL | T2 | 1 | 15 | 15 |00:00:00.01 | 99 |
|* 5 | INDEX RANGE SCAN | T_I1 | 15 | 15 | 225 |00:00:00.01 | 17 |
-----------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
4 - filter("T2"."N2"=45)
5 - access("T1"."N1"="T2"."N1")
If you want to call this function, you need access to several of the dynamic performance views -v$session, v$sql, v$sql_plan and v$sql_plan_statistics_all seem to cover all the options between them; and v$sql_plan_statistics_all is the most useful one.
As you can see in the query above, I’ve not supplied an sql_id or child_number, and I’ve used the format ‘ALLSTATS LAST’. By default display_cursor reports the last statement I executed, and the effect of ‘ALLSTATS LAST’ is to report the actual execution stats alongside the predicted row counts.
If you’ve ever got into Wolfgang Breitling’s ”Tuning by Cardinality Feedback” – you’ve now got a tool that can make it a lot easier.
A couple of odd notes – you’ll see that I set serveroutput off. If serveroutput is on when you call this function, the last statement you will have run will be the (hidden) call to dbms_output that follows your execution of any other statement – so you won’t get the plan and statistics.
The hint /*+ gather_plan_statistics */ enables collection of rowsource execution statistics for the statement. It’s a “nearly undocumented” hint, in that the documentation seems only to exist in odd places like the script that generates the package, and as part of the output of the function call if the statistics weren’t enabled when you try to report statistics.
You have to be a little careful comparing the actual and estimated row counts. They are not supposed to be the same in all cases. The estimated values are estimates for each execution of a rowsource, the actual values are the cumulative counts. So, for example, it is perfectly reasonable in line 5 to see E-rows = 15 and A-rows = 225, because line 5 starts 15 times: so 225 Actual rows = 15 starts * 15 estimated rows per start.
Jonathan,
I’ve been using dbms_xplan.display for a while now, but could never seem to get dbms_xplan.display_cursor to work, I can’t thank you enough for pointing out the ‘gather_plan_statistics’ hint, which was the key to getting it to work.
Keep up the blogging please!
Comment by John Scott — November 9, 2006 @ 11:50 pm UTC Nov 9,2006 |
I have been using 10g for a while but didn’t know about this. Thank you!!!
Comment by Kirtan Desai — November 10, 2006 @ 4:25 am UTC Nov 10,2006 |
well i knew about dbms_xplan but didn’t know about display_cursor.
Comment by Kirtan Desai — November 10, 2006 @ 4:26 am UTC Nov 10,2006 |
Hi Jaffar,
This is Hitesh from India. I work as Oracle DBA Developer. Yes,It is a Great Blog for oracle professionals,But only thing ,It lacks AD potential,especially Google ADs,which i thought could provide more info about Oracle related stuffs.
Anyway,If you intend to insert google ADs,do mail me at hitesh222002@yahoo.co.in, and you can take the link from my blogsite.
Comment by Hitesh Shetty — November 10, 2006 @ 6:00 am UTC Nov 10,2006 |
John, There are alternatives to the hint. Setting statistics_level = all, or _rowsource_execution_statistics = true, will enable the collection (and on some versions, just sql_trace = true does so as well). But the hint is the neatest.
Hitesh, I did consider Google Ads briefly last night; but there’s an awful lot of garbage about Oracle advertised on the internet, and it occurred to me that I wouldn’t want advertisements for garbage on my blog.
Comment by Jonathan Lewis — November 10, 2006 @ 7:21 am UTC Nov 10,2006 |
This works particularly nicely in tools such as PL/SQL Developer where you can add your own tabs to the Session Browser window, and so you can define one named “Current Plan”, with the query as:
SELECT plan_table_output
FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR( :sql_id, :sql_child_number))
Now you can easily see the execution plan for any active session.
Comment by William Robertson — November 10, 2006 @ 4:37 pm UTC Nov 10,2006 |
In Oracle 10g, dbms_xplan.display_awr can be used to get the historical information with respect to execution plans.
Jaffar
Comment by Jaffar Hussain — November 11, 2006 @ 7:19 am UTC Nov 11,2006 |
[...] A comment on my previous posting about dbms_xplan pointed out that in 10g you also get the function dbms_xplan.display_awr that allows you to report historical execution plans from the AWR (automatic workload repository). [...]
Pingback by dbms_xplan pt.2 « Oracle Scratchpad — November 15, 2006 @ 8:23 am UTC Nov 15,2006 |
I found that 10gR1 (at least on AIX) does not have the ALLSTATS LAST parameter, but includes RUNSTATS_LAST and RUNSTATS_TOT instead of ALLSTATS. The script documentation for 10gR2 says that these are included for backwards compatibility and are replaced by IOSTATS.
Comment by Daniel Fink — December 13, 2006 @ 11:20 pm UTC Dec 13,2006 |
[...] Plans in Memory Filed under: Infrastructure, Performance, Execution plans — Jonathan Lewis @ 8:42 pm UTC Dec 12,2006 In an earlier article I described how dbms_xplan.display_cursor() could be used to query memory to find the execution plans (and row source statistics) of recently executed SQL. [...]
Pingback by Plans in Memory « Oracle Scratchpad — December 30, 2006 @ 8:26 pm UTC Dec 30,2006 |
[...] — Jonathan Lewis @ 12:03 pm UTC Dec 22,2006 I’ve discussed the capabilities of the dbms_xplan package in a couple of posts already; and shown how useful it can be in two examples: understanding a [...]
Pingback by dbms_xplan - again « Oracle Scratchpad — February 1, 2007 @ 1:07 pm UTC Feb 1,2007 |
[...] blogged before about the improved features in 10g of the dbms_xplan package, in particular the display_cursor() procedure, with its option for displaying rowsource execution [...]
Pingback by Heisenberg « Oracle Scratchpad — April 26, 2007 @ 9:15 pm UTC Apr 26,2007 |
[...] Since this was a 10g machine, I hunted down the query (v$sql.sql_text like …) and called the dbms_xplan.display_cursor() procedure to show me the full plan. It looked a bit like [...]
Pingback by NLS « Oracle Scratchpad — July 26, 2007 @ 9:51 pm UTC Jul 26,2007 |
[...] dbms_xplan in 10g « Oracle Scratchpad Oracle Scratchpad November 9, 2006 dbms_xplan in 10g Filed under: Execution plans, Tuning, Hints — Jonathan Lewis @ 9:17 pm UTC Nov 9,2006 If you’re using 9i and haven’t learned about the dbms_xplan package, then you should take a good l [...]
Pingback by 10g Application Oracle Server — September 13, 2007 @ 3:34 pm UTC Sep 13,2007 |
[...] dbms_xplan(3) Filed under: Execution plans — Jonathan Lewis @ 8:01 am UTC Mar 6,2008 Some time ago, I wrote a note about using the packaged function dbms_xplan.display_cursor(). [...]
Pingback by dbms_xplan(3) « Oracle Scratchpad — March 6, 2008 @ 8:02 am UTC Mar 6,2008 |
[...] and “after” execution plans in 10.2.0.3 (pulled out of memory using the dbms_xplan.display_cursor() procedure) for an example of this type of [...]
Pingback by Cursor_sharing « Oracle Scratchpad — March 9, 2008 @ 9:14 pm UTC Mar 9,2008 |
[...] >= 11 — Last M rows, typically a bind variable order by v2.rn ; Execution Plan (10.2.0.3 – dbms_xplan.display_cursor() edited to remove columns) [...]
Pingback by Manual Optimisation - 2 « Oracle Scratchpad — May 9, 2008 @ 3:44 pm UTC May 9,2008 |
[...] dbms_xplan in 10g [...]
Pingback by Page hits « Oracle Scratchpad — September 7, 2008 @ 11:30 am UTC Sep 7,2008 |
[...] in the documentation here, so for more detailed explanation reading Mr.Jonathan Lewis’s post here may be good starting [...]
Pingback by On Formating Treasures of Execution Plan Interpretation « H.Tonguç Yılmaz - Oracle Blog — September 30, 2008 @ 4:37 pm UTC Sep 30,2008 |
[...] dbms_xplan 10g versijā – Jonathan Lewis raksts par dbms_xplan. [...]
Pingback by SQL teikuma izpildes plāna iegūšana - Oracle, MySQL, SQL Server « Datubāzu resurss latviski — April 7, 2009 @ 6:24 am UTC Apr 7,2009 |
Hi Jonathan,
I have one question related to the density in the CBO.
Why we have a different density between the varchar2 and number data type?
For exmple:
SQL> select * from emp;
1 aaa
1 aaa
1 aaa
1 aaa
1 aaa
1 aaa
1 aaa
3 ccc
5 eee
1 aaa
SQL> l
1 select NUM_DISTINCT, DENSITY, NUM_BUCKETS, HISTOGRAM from user_tab_col_statistics
2* where table_name = ‘EMP’
SQL> /
NUM_DISTINCT DENSITY NUM_BUCKETS HISTOGRAM
———— ———- ———– —————
3 .05 3 FREQUENCY
3 .333333333 1 NONE
Comment by Kwanyoung — April 16, 2009 @ 8:09 pm UTC Apr 16,2009 |
Kwanyoung,
In the absence of a histogram, the density is 1/num_distinct.
In the presence of a frequency histogram the density is 1/(2 * num_rows).
Comment by Jonathan Lewis — April 16, 2009 @ 9:58 pm UTC Apr 16,2009 |
Hi Jonathan,
Thanks a lot for the good answer to my question.
But I have some strange thing related to the parallel excution plan which is very fun and interesting.
SQL> select * from emp;
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
———- ———- ——— ———- ——— ———- ———- ———-
7369 SMITH CLERK 7902 17-DEC-80 800 20
7499 ALLEN SALESMAN 7698 20-FEB-81 1600 300 30
7521 WARD SALESMAN 7698 22-FEB-81 1250 500 30
7566 JONES MANAGER 7839 02-APR-81 2975 20
7654 MARTIN SALESMAN 7698 28-SEP-81 1250 1400 30
7698 BLAKE MANAGER 7839 01-MAY-81 2850 30
7782 CLARK MANAGER 7839 09-JUN-81 2450 10
7788 SCOTT ANALYST 7566 19-APR-87 3000 20
7839 KING PRESIDENT 17-NOV-81 5000 10
7844 TURNER SALESMAN 7698 08-SEP-81 1500 0 30
7876 ADAMS CLERK 7788 23-MAY-87 1100 20
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
———- ———- ——— ———- ——— ———- ———- ———-
7900 JAMES CLERK 7698 03-DEC-81 950 30
7902 FORD ANALYST 7566 03-DEC-81 3000 20
7934 MILLER CLERK 7782 23-JAN-82 1300 10
14 rows selected.
SQL> select * from dept;
DEPTNO DNAME LOC
———- ————– ————-
10 ACCOUNTING NEW YORK
20 RESEARCH DALLAS
30 SALES CHICAGO
40 OPERATIONS BOSTON
50 OPER1 Seoul
60 OPER2 Tokyo
70 OPER3 Hongkong
80 OPER3 Sanghi
90 OPER4 Sinjang
9 rows selected.
SQL>set autotrace on
SQL>SQL> select /*+ parallel(e) parallel(d) USE_NL(d e) */ e.ename, d.dname from emp e, dept d
2 where e.deptno = d.deptno
3 and d.deptno in (10, 20,30,40,11,12,13,14,15,16,17,18)
4 /
Execution Plan
———————————————————-
Plan hash value: 2994253754
————————————————————————————————————————-
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | TQ |IN-OUT| PQ Distrib |
————————————————————————————————————————-
| 0 | SELECT STATEMENT | | 14 | 224 | 2 (0)| 00:00:01 | | | |
| 1 | PX COORDINATOR | | | | | | | | |
| 2 | PX SEND QC (RANDOM) | :TQ10000 | 2 | 14 | 1 (0)| 00:00:01 | Q1,00 | P->S | QC (RAND) |
| 3 | TABLE ACCESS BY INDEX ROWID| EMP | 2 | 14 | 1 (0)| 00:00:01 | Q1,00 | PCWP | |
| 4 | NESTED LOOPS | | 14 | 224 | 2 (0)| 00:00:01 | Q1,00 | PCWP | |
| 5 | PX BLOCK ITERATOR | | | | | | Q1,00 | PCWC | |
|* 6 | TABLE ACCESS FULL | DEPT | 9 | 81 | 2 (0)| 00:00:01 | Q1,00 | PCWP | |
|* 7 | INDEX RANGE SCAN | IDX_DEPTNO | 5 | | 0 (0)| 00:00:01 | Q1,00 | PCWP | |
————————————————————————————————————————-
Predicate Information (identified by operation id):
—————————————————
6 – filter(”D”.”DEPTNO”=10 OR “D”.”DEPTNO”=11 OR “D”.”DEPTNO”=12 OR “D”.”DEPTNO”=13 OR “D”.”DEPTNO”=14 OR
“D”.”DEPTNO”=15 OR “D”.”DEPTNO”=16 OR “D”.”DEPTNO”=17 OR “D”.”DEPTNO”=18 OR “D”.”DEPTNO”=20 OR “D”.”DEPTNO”=30
OR “D”.”DEPTNO”=40)
7 – access(”E”.”DEPTNO”=”D”.”DEPTNO”)
filter(”E”.”DEPTNO”=10 OR “E”.”DEPTNO”=11 OR “E”.”DEPTNO”=12 OR “E”.”DEPTNO”=13 OR “E”.”DEPTNO”=14 OR
“E”.”DEPTNO”=15 OR “E”.”DEPTNO”=16 OR “E”.”DEPTNO”=17 OR “E”.”DEPTNO”=18 OR “E”.”DEPTNO”=20 OR “E”.”DEPTNO”=30
OR “E”.”DEPTNO”=40)
How do we get the rows 5 in the ID 7 and 2 rows in the ID 2?
I think it is 14 rows in the ID7.
Thanks a lot in advance
Comment by Kwanyoung — April 21, 2009 @ 4:11 pm UTC Apr 21,2009 |
[...] then the optimizer would calcualte a cardinality of one for this predicate (having recorded a density of 1/(2 * num_rows) in the data dictionary (see comments 21 and 22 of this note on dbms_xplan). [...]
Pingback by Histogram change « Oracle Scratchpad — April 23, 2009 @ 9:25 pm UTC Apr 23,2009 |
[...] dbms_xplan in 10g [...]
Pingback by Summary Stats « Oracle Scratchpad — April 27, 2009 @ 7:04 pm UTC Apr 27,2009 |
[...] dbms_xplan in 10g [...]
Pingback by Summary Stats « Oracle Scratchpad — April 27, 2009 @ 7:04 pm UTC Apr 27,2009 |
[...] Lewis @ 6:09 pm UTC May 5,2009 I’ve written several posts about dbms_xplan, and the display_cursor function in 10g. One of the nice feature of this function is that it is a “pipelined” [...]
Pingback by Dependent Plans « Oracle Scratchpad — May 5, 2009 @ 6:11 pm UTC May 5,2009 |