Professional Documents
Culture Documents
1 of 15
http://www.akadia.com/services/ora_interpreting_explain_plan.html
Steps [1]-[6] are handled by the parser. Step [7] is the execution of the
statement.
The explain plan is produced by the parser. Once the access path has been decided
upon it is stored in the library cache together with the statement itself. We store
queries in the library cache based upon a hashed representation of that query.
When looking for a statement in the library cache, we first apply a hashing
algorithm to the statement and then we look for this hash value in the library
cache. This access path will be used until the query is reparsed.
Terminology
Row Source
Predicate
Tuples
Driving Table
Probed Table
1/28/2013 12:07 PM
2 of 15
http://www.akadia.com/services/ora_interpreting_explain_plan.html
[CHOOSE] Cost=1234
However the explain plan below indicates the use of the RBO because the cost field
is blank:
SELECT STATEMENT
[CHOOSE] Cost=
The cost field is a comparative cost that is used internally to determine the best
cost for particular plans. The costs of different statements are not really directly
comparable.
[:Q65001] indicates that this particular part of the query is being executed in
parallel. This number indicates that the operation will be processed by a parallel
query slave as opposed to being executed serially.
[ANALYZED] indicates that the object in question has been analyzed and there are
currently statistics available for the CBO to use. There is no indication of the 'level'
of analysis done.
1/28/2013 12:07 PM
3 of 15
http://www.akadia.com/services/ora_interpreting_explain_plan.html
1/28/2013 12:07 PM
4 of 15
http://www.akadia.com/services/ora_interpreting_explain_plan.html
1/28/2013 12:07 PM
5 of 15
http://www.akadia.com/services/ora_interpreting_explain_plan.html
Query plan
-------------------SELECT STATEMENT [CHOOSE] Cost=1
INDEX RANGE SCAN EMP_I2 [ANALYZED]
Index Full Scan
In certain circumstances it is possible for the whole index to be scanned as
opposed to a range scan (i.e. where no constraining predicates are provided for a
table). Full index scans are only available in the CBO as otherwise we are unable
to determine whether a full scan would be a good idea or not. We choose an index
Full Scan when we have statistics that indicate that it is going to be more efficient
than a Full table scan and a sort.
For example we may do a Full index scan when we do an unbounded scan of an
index and want the data to be ordered in the index order. The optimizer may
decide that selecting all the information from the index and not sorting is more
efficient than doing a FTS or a Fast Full Index Scan and then sorting.
An Index full scan will perform single block i/o's and so it may prove to be
inefficient. Index BE_IX is a concatenated index on big_emp (empno,ename)
SQL> explain plan for select empno,ename
from big_emp order by empno,ename;
Query Plan
-----------------------------------------------------------SELECT STATEMENT
[CHOOSE] Cost=26
INDEX FULL SCAN BE_IX [ANALYZED]
Index Fast Full Scan
Scans all the block in the index Rows are not returned in sorted order Introduced
in 7.3 and requires V733_PLANS_ENABLED=TRUE and CBO may be hinted using
INDEX_FFS hint uses multiblock i/o can be executed in parallel can be used to
access second column of concatenated indexes. This is because we are selecting all
of the index.
Note that INDEX FAST FULL SCAN is the mechinism behind fast index create and
recreate. Index BE_IX is a concatenated index on big_emp (empno,ename)
SQL> explain plan for select empno,ename from big_emp;
Query Plan
-----------------------------------------SELECT STATEMENT
[CHOOSE] Cost=1
INDEX FAST FULL SCAN BE_IX [ANALYZED]
Selecting the 2nd column of concatenated index:
SQL> explain plan for select ename from big_emp;
Query Plan
-----------------------------------------SELECT STATEMENT
[CHOOSE] Cost=1
INDEX FAST FULL SCAN BE_IX [ANALYZED]
Rowid
This is the quickest access method available Oracle simply retrieves the block
specified and extracts the rows it is interested in. Most frequently seen in explain
1/28/2013 12:07 PM
6 of 15
http://www.akadia.com/services/ora_interpreting_explain_plan.html
A.col4
A,B,C
B.col3
A.col1
A.col2
C.col3
=
=
=
=
10
B.col1
C.col2
5
We could represent the joins present in the query using the following schematic:
B
<---> A <--->
col3=10
C
col3=5
There are really only 2 ways we can drive the query: via B.col3 or C.col3. We
would have to do a Full scan of A to be able to drive off it. This is unlikely to be
efficient with large tables;
If we drive off table B, using predicate B.col3=10 (as a filter or lookup key) then
we will retrieve the value for B.col1 and join to A.col1. Because we have now filled
the leading column of the concatenated index on table A we can use this index to
give us values for A.col2 and join to A.
However if we drive of table c, then we only get a value for a.col2 and since this is
a trailing column of a concatenated index and the leading column has not been
supplied at this point, we cannot use the index on a to lookup the data.
So it is likely that the best join order will be B A C. The CBO will obviously use
costs to establish whether the individual access paths are a good idea or not.
1/28/2013 12:07 PM
7 of 15
http://www.akadia.com/services/ora_interpreting_explain_plan.html
If the CBO does not choose this join order then we can hint it by changing the
from
clause to read:
from B,A,C
and using the /*+ ordered */ hint. The resultant query would be:
select
from
where
and
and
and
Join Types
Sort Merge Join (SMJ)
Nested Loops (NL)
Hash Join
Sort Merge Join
Rows are produced by Row Source 1 and are then sorted Rows from Row Source 2
are then produced and sorted by the same sort key as Row Source 1. Row Source
1 and 2 are NOT accessed concurrently Sorted rows from both sides are then
merged together (joined)
MERGE
/
SORT
|
Row Source 1
\
SORT
|
Row Source 2
If the row sources are already (known to be) sorted then the sort operation is
unecessary as long as both 'sides' are sorted using the same key. Presorted row
sources include indexed columns and row sources that have already been sorted in
earlier steps. Although the merge of the 2 row sources is handled serially, the row
sources could be accessed in parallel.
SQL> explain plan for
select /*+ ordered */ e.deptno,d.deptno
from emp e,dept d
where e.deptno = d.deptno
order by e.deptno,d.deptno;
Query Plan
------------------------------------SELECT STATEMENT [CHOOSE] Cost=17
MERGE JOIN
SORT JOIN
TABLE ACCESS FULL EMP [ANALYZED]
SORT JOIN
TABLE ACCESS FULL DEPT [ANALYZED]
Sorting is an expensive operation, especially with large tables. Because of this,
SMJ is often not a particularly efficient join method.
Nested Loops
1/28/2013 12:07 PM
8 of 15
http://www.akadia.com/services/ora_interpreting_explain_plan.html
First we return all the rows from row source 1 Then we probe row source 2 once
for each row returned from row source 1
Row source 1
~~~~~~~~~~~~
Row 1 -------------Row 2 -------------Row 3 --------------
-- Probe ->
-- Probe ->
-- Probe ->
Row source 2
Row source 2
Row source 2
1/28/2013 12:07 PM
9 of 15
http://www.akadia.com/services/ora_interpreting_explain_plan.html
Operations
Operations that show up in explain plans
sort
filter
view
Sorts
There are a number of different operations that promote sorts
order by clauses
group by
sort merge join
Note that if the row source is already appropriately sorted then no sorting is
required. This is now indicated in 7.3:
SORT GROUP BY NOSORT
INDEX FULL SCAN .....
In this case the group by operation simply groups the rows it does not do the sort
operation as this has already been completed.
Sorts are expensive operations especially on large tables where the rows do not fit
in memory and spill to disk. By default sort blocks are placed into the buffer cache.
This may result in aging out of other blocks that may be reread by other
processes. To avoid this you can use the parameter
<Parameter:SORT_DIRECT_WRITES> which does not place sort blocks into the
buffer cache.
Filter
Has a number of different meanings used to indicate partition elimination may also
indicate an actual filter step where one row source is filtering another functions
such as min may introduce filter steps into query plans
In this example there are 2 filter steps. The first is effectively like a NL except that
it stops when it gets something that it doesn't like (i.e. a bounded NL). This is
there because of the not in. The second is filtering out the min value:
1/28/2013 12:07 PM
10 of 15
http://www.akadia.com/services/ora_interpreting_explain_plan.html
sum(prc_pd)
Query Plan
----------------------------------------SELECT STATEMENT
[FIRST_ROWS] Cost=1780
1/28/2013 12:07 PM
11 of 15
http://www.akadia.com/services/ora_interpreting_explain_plan.html
SORT AGGREGATE
NESTED LOOPS
[:Q65001] Ct=1780 Cd=40 Bt=3120
TABLE ACCESS FULL PARENT1 [:Q65000] [AN] Ct=20 Cd=40 Bt=1040
VIEW KBWYV1 [:Q65001]
UNION-ALL PARTITION [:Q65001]
FILTER
[:Q64000]
TABLE ACCESS FULL KBWYT1 [AN] Ct=11 Cd=2000 Bt=104000
TABLE ACCESS FULL KBWYT2 [AN] Ct=11 Cd=2000 Bt=104000
TABLE ACCESS FULL KBWYT3 [AN] Ct=11 Cd=2000 Bt=104000
FILTER
[:Q61000]
TABLE ACCESS FULL KBWYT4 [AN] Ct=11 Cd=2000 Bt=104000
KBWYV1 is a view on 4 tables KBWYT1-4. KBWYT1-4 contain rows for week 31-34
respectively and are maintained by check constraints. This query should only
return rows from partions 2 & 3. The filter operation indicates this. Partitions 1 &
4 are eliminated at execution time. The view line indicates that the view is not
merged. The union-all partion information indicates that we have recognised this
as a partition view. Note that the tables can be accessed in parallel.
Remote Queries
Only shows remote in the OPERATION column OTHER column shows query
executed on remote node OTHER_NODE shows where it is executed Different
operational characteristics for RBO & CBO
RBO - Drags everything across the link and joins locally
CBO - Uses cost estimates to determine whether to execute remotely or locally
SQL> explain plan for
select *
from dept@loop_link;
Query Plan
------------------------------------------------------SELECT STATEMENT REMOTE [CHOOSE] Cost=1
TABLE ACCESS FULL DEPT [SJD.WORLD] [ANALYZED]
In this case the whole query has been sent to the remote site. The other column
shows nothing.
SQL> explain plan for
select a.dname,avg(b.sal),max(b.sal)
from dept@loop_link a, emp b
where a.deptno=b.deptno
group by a.dname
order by max(b.sal),avg(b.sal) desc;
Query Plan
----------------------------------------------------SELECT STATEMENT
[CHOOSE] Cost=20
SORT ORDER BY [:Q137003] [PARALLEL_TO_SERIAL]
SORT GROUP BY [:Q137002] [PARALLEL_TO_PARALLEL]
NESTED LOOPS
[:Q137001] [PARALLEL_TO_PARALLEL]
REMOTE
[:Q137000] [PARALLEL_FROM_SERIAL]
TABLE ACCESS FULL EMP [:Q137001] [ANALYZED]
[PARALLEL_COMBINED_WITH_PARENT]
Bind Variables
Bind variables are recommended in most cases because they promote sharing of
sql code
At parse time the parser has NO IDEA what the bind variable contains. With RBO
1/28/2013 12:07 PM
12 of 15
http://www.akadia.com/services/ora_interpreting_explain_plan.html
this makes no difference but with CBO, which relies on accurate statistics to
produce plans, this can be a problem.
Defining bind variables in sqlplus:
variable x varchar2(18);
assigning values:
begin
:x := 'hello';
end;
/
SQL> explain plan for
select *
from dept
where rowid = ':x';
Query Plan
-----------------------------------SELECT STATEMENT [CHOOSE] Cost=1
TABLE ACCESS BY ROWID DEPT [ANALYZED]
Parallel Query
Main indicators that a query is using PQO:
[:Q1000004] entries in the explain plan
Checkout the other column for details of what the slaves are executing
v$pq_slave will show any parallel activity
Columns to look in for information
other - contains the query passed to the slaves
other_tag - describes the contents of other
object_node - indicates order of pqo slaves
Parallel Query operates on a producer/consumer basis. When you specify parallel
degree 4 oracle tries to allocate 4 producer slaves and 4 consumer slaves. The
producers can feed any of the consumers. If there are only 2 slaves available then
we use these. If there is only 1 slave available then we go serial If there are none
available then we use serial. If parallel_min_percent is set then we error ora
12827 instead of using a lower number of slaves or going serial
Consumer processes typically perform a sorting function. If there is no
requirement for the data to be sorted then the consumer slaves are not produced
and we end up with the number of slaves used matching the degree of parallelism
as opposed to being 2x the degree.
Parallel Terms
PARALLEL_FROM_SERIAL
PARALLEL_TO_PARALLEL
1/28/2013 12:07 PM
13 of 15
PARALLEL_COMBINED_WITH_PARENT
PARALELL_TO_SERIAL
http://www.akadia.com/services/ora_interpreting_explain_plan.html
OBJECT_NODE OTHER
----------- -------
OBJECT_NODE OTHER
1/28/2013 12:07 PM
14 of 15
http://www.akadia.com/services/ora_interpreting_explain_plan.html
------------------------------SELECT STATEMENT
Cost = ??
SORT ORDER BY
SORT GROUP BY
MERGE JOIN
SORT JOIN
TABLE ACCESS FULL emp
SORT JOIN
TABLE ACCESS FULL dept
Execution Plan #2
**[1]**
----------- ------:Q55004
:Q55003
:Q55002
:Q55002
:Q55001
:Q55002
:Q55000
**[7]**
**[6]**
**[5]**
**[4]**
**[2]**
**[3]**
**[1]**
-- OTHER column
(:Q55000) "PARALLEL_FROM_SERIAL"
(:Q55001) "PARALLEL_TO_PARALLEL"
SELECT /*+ ROWID(A1)*/
A1."DEPTNO" C0, A1."SAL" C1
FROM "EMP" A1
WHERE ROWID BETWEEN :1 AND :2
**[3]**
**[4]**
**[5]**
(:Q55002) "PARALLEL_COMBINED_WITH_PARENT"
(:Q55002) "PARALLEL_COMBINED_WITH_PARENT"
(:Q55002) "PARALLEL_TO_PARALLEL"
SELECT /*+ ORDERED USE_MERGE(A2)*/
A2.C1 C0, A1.C1 C1
FROM :Q55001 A1,:Q55000 A2
WHERE A1.C0=A2.C0
**[6]**
(:Q55003) "PARALLEL_TO_PARALLEL"
SELECT MAX(A1.C1) C0, AVG(A1.C1) C1, A1.C0 C2
FROM :Q55002 A1
GROUP BY A1.C0
**[7]**
(:Q55004) "PARALLEL_FROM_SERIAL"
SELECT A1.C0 C0, A1.C1 C1, A1.C2 C2
FROM :Q55003 A1
ORDER BY A1.CO, A1.C1 DESC
OBJECT_NODE OTHER
----------- ------:Q58002
:Q58001
:Q58000
:Q58000
:Q58000
:Q58000
**[6]**
**[5]**
**[4]**
**[3]**
**[2]**
**[1]**
-- OTHER column
1/28/2013 12:07 PM
15 of 15
**[1]**
**[2]**
**[3]**
**[4]**
http://www.akadia.com/services/ora_interpreting_explain_plan.html
(:Q58000)
(:Q58000)
(:Q58000)
(:Q58000)
"PARALLEL_COMBINED_WITH_PARENT"
"PARALLEL_COMBINED_WITH_PARENT"
"PARALLEL_COMBINED_WITH_PARENT"
"PARALLEL_TO_PARALLEL"
(:Q58001) "PARALLEL_TO_PARALLEL"
SELECT MAX(A1.C1) C0, AVG(A1.C1) C1, A1.C0 C2
FROM :Q58000 A1
GROUP BY A1.C0
**[6]**
(:Q58002) "PARALLEL_TO_SERIAL"
SELECT A1.C0 C0, A1.C1 C1, A1.C2 C2
FROM :Q58001 A1
ORDER BY A1.C0, A1.C1 DESC
1/28/2013 12:07 PM