Вы находитесь на странице: 1из 77

| Print | Contents | Close |

Gathering Execution Plans


Learning Objectives

After completing this topic, you should be able to

recognize how to gather execution plans

recognize how to display execution plans

1. Understanding execution plans


An execution plan is the output of the optimizer and is presented to the execution engine
for implementation. It instructs the execution engine about the operations it must perform
for retrieving the data required by a query most efficiently.

Supplement
Selecting the link title opens the resource in a new browser window.

Learning Aid
Use the learning aid Style considerations for more information on the style
considerations for Oracle 11g Database used in this course.
The execution plan of a SQL statement is composed of small building blocks called row
sources for serial execution plans. The combination of row sources for a statement is also
called the execution plan. By using parent-child relationships, the execution plan can be
displayed in a tree-like structure (text or graphical).
The EXPLAIN PLAN statement gathers execution plans chosen by the Oracle optimizer
for the SELECT, UPDATE, INSERT, and DELETE statements. The steps of the execution
plan are not performed in the order in which they are numbered. There is a parent-child
relationship between steps.
The row source tree is the core of the execution plan. It shows the following information:

an ordering of the tables referenced by the statement

an access method for each table mentioned in the statement

a join method for tables affected by join operations in the statement, and

data operations, such as filter, sort, or aggregation


In addition to the row source tree (or data flow tree for parallel operations), the plan table
contains information about the following:

optimization, such as the cost and cardinality of each operation

partitioning, such as the set of accessed partitions, and

parallel execution, such as the distribution method of join inputs


The EXPLAIN PLAN results help you determine whether the optimizer selects a particular
execution plan, such as nested loops join.
There are many ways to retrieve execution plans inside the database. The following are
the most well-known ones:
EXPLAIN PLAN
The EXPLAIN PLAN command enables you to view the execution plan that the optimizer
might use to execute a SQL statement. This command is very useful because it outlines
the plan that the optimizer may use and inserts it in a table called PLAN_TABLE without
executing the SQL statement.
V$SQL_PLAN
V$SQL_PLAN provides a way to examine the execution plan for cursors that were recently
executed. Information in V$SQL_PLAN is very similar to the output of an EXPLAIN PLAN
statement. However, while EXPLAIN PLAN shows a theoretical plan that can be used if this
statement was executed, V$SQL_PLAN contains the actual plan used.
V$SQL_PLAN_MONITOR, and
V$SQL_PLAN_MONITOR displays plan-level monitoring statistics for each SQL statement
found in V$SQL_MONITOR. Each row in V$SQL_PLAN_MONITOR corresponds to an
operation of the execution plan that is monitored.
DBA_HIST_SQL_PLAN and STATS$SQL_PLAN
The Automatic Workload Repository, or AWR, infrastructure and statspack reports store
plans from top SQLs. Plans are recorded into DBA_HIST_SQL_PLAN and
STATS$SQL_PLAN.
Other ways to retrieve execution plans inside the database include the following:

Plan and row source operations are dumped in trace files generated by DBMS_MONITOR.

In the SQL Management Base or SMB, which is a part of the data dictionary that resides in the
SYSAUX tablespace. It stores statement log, plan histories, and SQL plan baselines, as profiles.

The event 10053 trace file, which is used to dump Cost-Based Optimizer, or CBO computations,
may include a plan.

Starting with Oracle Database 10g Release 2, when you dump process state (or errorstack from a
process), execution plans are included in the trace file that is generated.

Question
Which method of retrieving execution plans from the database enables you to
review the execution plan that the optimizer might use to execute a SQL
statement?
Options:
1.

AWR

2.

EXPLAIN PLAN command

3.

SMB

4.

V$SQL_PLAN_MONITOR

Answer
Option 1: Incorrect. The Automatic Workload Repository, or AWR, infrastructure
and statspack reports store plans from top SQLs. Plans are recorded into
DBA_HIST_SQL_PLAN and STATS$SQL_PLAN.
Option 2: Correct. The EXPLAIN PLAN command enables you to view the
execution plan that the optimizer might use to execute a SQL statement. This
command is very useful because it outlines the plan that the optimizer may use
and inserts it in a table called PLAN_TABLE without executing the SQL statement.
Option 3: Incorrect. The SQL Management Base, or SMB, is a part of the data
dictionary that resides in the SYSAUX tablespace. It stores statement log, plan
histories, and SQL plan baselines, as well as SQL profiles.
Option 4: Incorrect. V$SQL_PLAN_MONITOR displays plan-level monitoring
statistics for each SQL statement found in V$SQL_MONITOR. Each row in
V$SQL_PLAN_MONITOR corresponds to an operation of the execution plan that is
monitored.
Correct answer(s):

2. EXPLAIN PLAN command

2. Gathering execution plans


You can view execution plans by using the EXPLAIN PLAN command and then using
either the SELECT...FROM PLAN_TABLE statement or the
DBMS_XPLAN.DISPLAY()PL/SQL package.
You can also use the SQL*Plus AutoTrace feature to view execution plans. To do this, you
use the SET AUTOTRACE ON command.
The DBMS_XPLAN package supplies five table functions for viewing execution plans:
DISPLAY
DISPLAY is used to format and to display the contents of a plan table.
DISPLAY_AWR
You use DISPLAY_AWR to format and display the contents of the execution plan of a
stored SQL statement in the AWR.
DISPLAY_CURSOR
DISPLAY_CURSOR can be used to format and display the contents of the execution plan of
any loaded cursor.
DISPLAY_SQL_PLAN_BASELINE, and
DISPLAY_SQL_PLAN_BASELINE is used to display one or more execution plans for the
SQL statement identified by SQL handle.
DISPLAY_SQLSET
You can use DISPLAY_SQLSET to format and display the contents of the execution plan of
statements stored in a SQL tuning set.
The EXPLAIN PLAN command is used to generate the execution plan that the optimizer
uses to execute a SQL statement. It does not execute the statement, but simply produces
the plan that may be used, and inserts this plan into a table. If you examine the plan, you
can see how the Oracle Server executes the statement.
Use the EXPLAIN PLAN command first to explain a SQL statement and then retrieve the
plan steps by querying PLAN_TABLE.
PLAN_TABLE is automatically created as a global temporary table to hold the output of an
EXPLAIN PLAN statement for all users. PLAN_TABLE is the default sample output table
into which the EXPLAIN PLAN statement inserts rows describing execution plans.

Note

You can create your own PLAN_TABLE using the


$ORACLE_HOME/rdbms/admin/utlxplan.sql script if you want to keep the
execution plan information for a long term.
The EXPLAIN PLAN command inserts a row in the plan table for each step of the
execution plan. The fields in the syntax have the following meanings:
text
You can specify an optional identifier for the statement in 'text'. You should enter a value to
identify each statement so that you can later specify the statement that you want
explained. This is especially important when you share the plan table with others or when
you keep multiple execution plans in the same plan table.
your plan table
The default name for the output table is PLAN_TABLE. The optional name is
schema.table.
statement
The text of the SQL statement is identified in statement.
In the code example, the EXPLAIN PLAN command inserts the execution plan for the
SQL statement in the plan table and adds the optional demo01 name tag for future
reference.

Code
SQL> EXPLAIN PLAN
2 SET STATEMENT_ID = 'demo01' FOR
3 SELECT e.last_name, d.department_name
4 FROM hr.employees e, hr.departments d
5 WHERE e.department_id = d.department_id;
Explained.
SQL>
You can also use this code to use the EXPLAIN PLAN command.

Code
EXPLAIN PLAN
FOR
SELECT e.last_name, d.department_name
FROM hr.employees e, hr.departments d
WHERE e.department_id =d.department_id;

There are various methods available to gather execution plans. You are introduced only
to the EXPLAIN PLAN statement. This SQL statement gathers the execution plan of a
SQL statement without executing it, and outputs its result in the PLAN_TABLE table.
Whatever the method to gather and display the explain plan, the basic format and goal
are the same.
However, PLAN_TABLE just shows you a plan that might not be the one chosen by the
optimizer. PLAN_TABLE is automatically created as a global temporary table and is visible
to all users. PLAN_TABLE is the default sample output table into which the EXPLAIN
PLAN statement inserts rows describing execution plans.
PLAN_TABLE is organized in a tree-like structure and you can retrieve that structure by
using both the ID and PARENT_ID columns with a CONNECT BY clause in a SELECT
statement. While a PLAN_TABLE table is automatically set up for each user, you can use
the utlxplan.sql SQL script to manually create a local PLAN_TABLE in your schema and
use it to store the results of EXPLAIN PLAN.
The exact name and location of the utlxplan.sql script depends on your operating system.
On UNIX, it is located in the admin directory. It is recommended that you drop and
rebuild your local PLAN_TABLE table after upgrading the version of the database because
the columns might change. This can cause scripts to fail or cause TKPROF to fail, if you
are specifying the table.

Graphic
The admin directory is located at the path $ORACLE_HOME/rdbms/admin.

Note
If you want an output table with a different name, first create PLAN_TABLE
manually with the utlxplan.sql script, and then rename the table with the RENAME
SQL statement.

3. Displaying execution plans


In this example, the EXPLAIN PLAN command inserts the execution plan of the SQL
statement in PLAN_TABLE and adds the optional demo01 name tag for future reference.
It is important to note that the SELECT statement itself is not executed, but is simply
optimized to determine the best execution plan in that context. The DISPLAY function of
the DBMS_XPLAN package can be used to format and display the last statement stored in
PLAN_TABLE.

Code

SQL> EXPLAIN PLAN SET STATEMENT_ID = 'demo01' FOR SELECT *


FROM emp
2 WHERE ename = 'KING';
Explained.
SQL> SET LINESIZE 130
SQL> SET PAGESIZE 0
SQL> SELECT * FROM table(DBMS_XPLAN.DISPLAY());
Plan hash value: 3956160932
----------------------------------------------------------|Id|Operation
|Name|Rows|Bytes|Cost (%CPU)|Time
|
----------------------------------------------------------| 0|SELECT STATEMENT |
|
1|
37|
3
(0)|00:00:01|
|*1|TABLE ACCESS FULL|EMP |
1|
37|
3
(0)|00:00:01|
----------------------------------------------------------Predicate Information (identified by operation id):
--------------------------------------------------1 - filter("ENAME"='KING')
You can also use this code to retrieve the same results from the PLAN_TABLE.

Code
SQL> EXPLAIN PLAN SET STATEMENT_ID = 'demo01' FOR SELECT *
FROM emp
2 WHERE ename = 'KING';
Explained.
SQL> SET LINESIZE 130
SQL> SET PAGESIZE 0
SQL> SELECT * FROM table(DBMS_XPLAN.DISPLAY('plan_table',
'demo01', 'typical', null));
Plan hash value: 3956160932
----------------------------------------------------------|Id|Operation
|Name|Rows|Bytes|Cost (%CPU)|Time
|
----------------------------------------------------------| 0|SELECT STATEMENT |
|
1|
37|
3
(0)|00:00:01|
|*1|TABLE ACCESS FULL|EMP |
1|
37|
3
(0)|00:00:01|
----------------------------------------------------------Predicate Information (identified by operation id):

--------------------------------------------------1 - filter("ENAME"='KING')
In the example, you can substitute the name of another plan table instead of
PLAN_TABLE and demo01 represents the statement ID. TYPICAL displays the most
relevant information in the plan: operation ID, name and option, number of rows, bytes,
and optimizer cost.
The last parameter for the DISPLAY function is the one corresponding to
filter_preds. This parameter represents a filter predicate or predicates to restrict the
set of rows selected from the table where the plan is stored. When value is null (the
default), the plan displayed corresponds to the last executed explain plan. This parameter
can reference any column of the table where the plan is stored and can contain any SQL
construct, for example, subquery or function calls.

Code
SQL> EXPLAIN PLAN SET STATEMENT_ID = 'demo01' FOR SELECT *
FROM emp
2 WHERE ename = 'KING';
Explained.
SQL> SET LINESIZE 130
SQL> SET PAGESIZE 0
SQL> SELECT * FROM table(DBMS_XPLAN.DISPLAY('plan_table',
'demo01', 'typical', null));
Plan hash value: 3956160932
----------------------------------------------------------|Id|Operation
|Name|Rows|Bytes|Cost (%CPU)|Time
|
----------------------------------------------------------| 0|SELECT STATEMENT |
|
1|
37|
3
(0)|00:00:01|
|*1|TABLE ACCESS FULL|EMP |
1|
37|
3
(0)|00:00:01|
----------------------------------------------------------Predicate Information (identified by operation id):
--------------------------------------------------1 - filter("ENAME"='KING')

Note
Alternatively, you can run the utlxpls.sql (or utlxplp.sql for parallel queries) script,
located in the admin directory to display the execution plan stored in

PLAN_TABLE. This script uses the DISPLAY table function from the DBMS_XPLAN
package.
The ALL option used with the DISPLAY function in this example allows you to output the
maximum user level information. It includes information displayed with the TYPICAL
level, with additional information such as PROJECTION, ALIAS, and information about
REMOTE SQL, if the operation is distributed.

Code
SQL> SELECT * FROM
table(DBMS_XPLAN.DISPLAY(null,null,'ALL'));
Plan hash value: 3956160932
-----------------------------------------------------------|Id|Operation
|Name|Rows|Bytes|Cost (%CPU)|Time
|
-----------------------------------------------------------| 0|SELECT STATEMENT |
|
1|
37|
3 (0)|00:00:01|
|*1| TABLE ACCESS FULL|EMP |
1|
37|
3 (0)|00:00:01|
-----------------------------------------------------------Query Block Name / Object Alias (identified by operation
id):
-----------------------------------------------------------1 - SEL$1 / EMP@SEL$1
Predicate Information (identified by operation id):
--------------------------------------------------1 - filter("ENAME"='KING')
Column Projection Information (identified by operation id):
----------------------------------------------------------1 - "EMP"."EMPNO"[NUMBER,22], "ENAME"[VARCHAR2,10],
"EMP"."JOB"[VARCHAR2,9], "EMP"."MGR"[NUMBER,22],
"EMP"."HIREDATE"[DATE,7], "EMP"."SAL"[NUMBER,22],
"EMP"."COMM"[NUMBER,22], "EMP"."DEPTNO"[NUMBER,22]
For finer control on the display output, keywords can be added to the format parameter to
customize its default behavior. Each keyword either represents a logical group of plan
table columns (such as PARTITION) or logical additions to the base plan table output
(such as PREDICATE). Format keywords must be separated by either a comma or a
space.
The keywords include

Code

SQL> SELECT * FROM


table(DBMS_XPLAN.DISPLAY(null,null,'ALL'));
Plan hash value: 3956160932
-----------------------------------------------------------|Id|Operation
|Name|Rows|Bytes|Cost (%CPU)|Time
|
-----------------------------------------------------------| 0|SELECT STATEMENT |
|
1|
37|
3 (0)|00:00:01|
|*1| TABLE ACCESS FULL|EMP |
1|
37|
3 (0)|00:00:01|
-----------------------------------------------------------Query Block Name / Object Alias (identified by operation
id):
-----------------------------------------------------------1 - SEL$1 / EMP@SEL$1
Predicate Information (identified by operation id):
--------------------------------------------------1 - filter("ENAME"='KING')
Column Projection Information (identified by operation id):
----------------------------------------------------------1 - "EMP"."EMPNO"[NUMBER,22], "ENAME"[VARCHAR2,10],
"EMP"."JOB"[VARCHAR2,9], "EMP"."MGR"[NUMBER,22],
"EMP"."HIREDATE"[DATE,7], "EMP"."SAL"[NUMBER,22],
"EMP"."COMM"[NUMBER,22], "EMP"."DEPTNO"[NUMBER,22]
ROWS
If relevant, the ROWS keyword shows the number of rows estimated by the optimizer.
BYTES
The BYTES keyword shows the number of bytes estimated by the optimizer, if relevant.
COST
The COST keyword shows optimizer cost information, if relevant.
PARTITION, and
If relevant, the PARTITION keyword shows partition pruning information.
PARALLEL
The PARALLEL keyword shows PX information (distribution method and table queue
information), if relevant.
Other format keywords include the following:

Code
SQL> SELECT * FROM
table(DBMS_XPLAN.DISPLAY(null,null,'ALL'));
Plan hash value: 3956160932

-----------------------------------------------------------|Id|Operation
|Name|Rows|Bytes|Cost (%CPU)|Time
|
-----------------------------------------------------------| 0|SELECT STATEMENT |
|
1|
37|
3 (0)|00:00:01|
|*1| TABLE ACCESS FULL|EMP |
1|
37|
3 (0)|00:00:01|
-----------------------------------------------------------Query Block Name / Object Alias (identified by operation
id):
-----------------------------------------------------------1 - SEL$1 / EMP@SEL$1
Predicate Information (identified by operation id):
--------------------------------------------------1 - filter("ENAME"='KING')
Column Projection Information (identified by operation id):
----------------------------------------------------------1 - "EMP"."EMPNO"[NUMBER,22], "ENAME"[VARCHAR2,10],
"EMP"."JOB"[VARCHAR2,9], "EMP"."MGR"[NUMBER,22],
"EMP"."HIREDATE"[DATE,7], "EMP"."SAL"[NUMBER,22],
"EMP"."COMM"[NUMBER,22], "EMP"."DEPTNO"[NUMBER,22]
PREDICATE
If relevant, the PREDICATE keyword shows the predicate section.
PROJECTION
The PROJECTION keyword shows the projection section, if relevant.
ALIAS
If relevant, the ALIAS keyword shows the "Query Block Name/Object Alias" section.
REMOTE, and
If relevant, the REMOTE keyword shows the information for the distributed query (for
example, remote from serial distribution and remote SQL).
NOTE
The NOTE keyword shows the note section of the explain plan, if relevant.
If the target plan table also stores plan statistics columns (for example, it is a table used
to capture the content of the fixed view V$SQL_PLAN_STATISTICS_ALL), additional
format keywords can be used to specify which class of statistics to display when using the
DISPLAY function. These additional format keywords are IOSTATS, MEMSTATS,
ALLSTATS, and LAST.

Code

SQL> SELECT * FROM


table(DBMS_XPLAN.DISPLAY(null,null,'ALL'));
Plan hash value: 3956160932
-----------------------------------------------------------|Id|Operation
|Name|Rows|Bytes|Cost (%CPU)|Time
|
-----------------------------------------------------------| 0|SELECT STATEMENT |
|
1|
37|
3 (0)|00:00:01|
|*1| TABLE ACCESS FULL|EMP |
1|
37|
3 (0)|00:00:01|
-----------------------------------------------------------Query Block Name / Object Alias (identified by operation
id):
-----------------------------------------------------------1 - SEL$1 / EMP@SEL$1
Predicate Information (identified by operation id):
--------------------------------------------------1 - filter("ENAME"='KING')
Column Projection Information (identified by operation id):
----------------------------------------------------------1 - "EMP"."EMPNO"[NUMBER,22], "ENAME"[VARCHAR2,10],
"EMP"."JOB"[VARCHAR2,9], "EMP"."MGR"[NUMBER,22],
"EMP"."HIREDATE"[DATE,7], "EMP"."SAL"[NUMBER,22],
"EMP"."COMM"[NUMBER,22], "EMP"."DEPTNO"[NUMBER,22]

Note
Format keywords can be prefixed with the "-" sign to exclude the specified
information. For example, "-PROJECTION" excludes projection information.
The ADVANCED format is available only from Oracle Database 10g, Release 2 and later
versions. This output format includes all sections from the ALL format plus the outline
data that represents a set of hints to reproduce that particular plan. This section may be
useful if you want to reproduce a particular execution plan in a different environment. This
is the same section, which is displayed in the trace file for event 10053.

Code
SELECT plan_table_output FROM
table(DBMS_XPLAN.DISPLAY(null,null,'ADVANCED
-PROJECTION -PREDICATE -ALIAS'));
Plan hash value: 3956160932
-----------------------------------------------------------|Id|Operation
|Name|Rows|Bytes|Cost (%CPU)|Time
|
-----------------------------------------------------------| 0|SELECT STATEMENT |
|
1|
37|
3 (0)|00:00:01|
|*1| TABLE ACCESS FULL|EMP |
1|
37|
3 (0)|00:00:01|

-----------------------------------------------------------Outline Data
------------/*+
BEGIN_OUTLINE_DATA
FULL(@"SEL$1" "EMP"@"SEL$1")
OUTLINE_LEAF(@"SEL$1")
ALL_ROWS
DB_VERSION('11.1.0.6')
OPTIMIZER_FEATURES_ENABLE('11.1.0.6')
IGNORE_OPTIM_EMBEDDED_HINTS
END_OUTLINE_DATA
*/

Note
When the ADVANCED format is used with V$SQL_PLAN, there is one more section
called Peeked Binds (identified by position).

4. Using the AUTOTRACE facility


AUTOTRACE is a SQL*Plus facility introduced with Oracle 7.3. When running SQL
statements under SQL*Plus, you can automatically get a report on the execution plan and
the statement execution statistics. The report is generated after successful SQL DML
(that is, SELECT, DELETE, UPDATE, and INSERT) statements. AUTOTRACE is useful for
monitoring and tuning the performance of these statements.
To use the AUTOTRACE feature, you must have a PLAN_TABLE available in your schema
and then have the PLUSTRACE role granted to you. Database administrator, or DBA,
privileges are required to grant the PLUSTRACE role. The PLUSTRACE role is created and
granted to the DBA role by running the supplied plustrce.sql script.

Graphic
The plustrace.sql script is located at $ORACLE_HOME/sqlplus/admin/plustrce.sql.
On some versions and platforms, the plustrace.sql script is run by the database
creation scripts. If this is not the case on your platform, connect as SYSDBA and run the
plustrce.sql script. The PLUSTRACE role contains the select privilege on three V$
views. These privileges are necessary to generate AUTOTRACE statistics.
AUTOTRACE is an excellent diagnostic tool for SQL statement tuning. Because it is purely
declarative, it is easier to use than EXPLAIN PLAN.

Note
The system does not support EXPLAIN PLAN for statements performing implicit
type conversion of date bind variables. With bind variables in general, the
EXPLAIN PLAN output might not represent the real execution plan.
You can use this syntax to enable AUTOTRACE in various ways. The options are as
follows:
OFF
You can use the OFF option to disable autotracing SQL statements.
ON
You use the ON option to enable autotracing SQL statements.
TRACE or TRACE[ONLY]
The TRACE or TRACE[ONLY] option enable autotracing SQL statements and suppresses
statement output.
EXPLAIN, and
To display execution plans, but not the statistics, you use the EXPLAIN option.
STATISTICS
The STATISTICS option displays statistics, but does not display execution plans.
If both the EXPLAIN and STATISTICS command options are omitted, execution plans
and statistics are displayed by default.
You can control the report by setting the AUTOTRACE system variable. The following are
some examples:
SET AUTOTRACE ON
This AUTOTRACE report includes both the optimizer execution plan and the SQL statement
execution statistics.
SET AUTOTRACE TRACEONLY EXPLAIN
This AUTOTRACE report shows only the
optimizer execution path without executing the statement.
SET AUTOTRACE ON STATISTICS
This AUTOTRACE report shows the SQL statement execution statistics and rows.
SET AUTOTRACE TRACEONLY, and
This is similar to SET AUTOTRACE ON, but it suppresses the printing of the user's query
output, if any. If STATISTICS is enabled, the query data is still fetched, but not printed.
SET AUTOTRACE OFF

No AUTOTRACE report is generated. This is the default.

Question
Which AUTOTRACE example should you use to display rows and statistics?
Options:
1.

SET AUTOTRACE ON

2.

SET AUTOTRACE ON STATISTICS

3.

SET AUTOTRACE TRACEONLY

4.

SET AUTOTRACE TRACEONLY EXPLAIN

Answer
Option 1: Incorrect. This option is used to start tracing statements using
AUTOTRACE. The AUTOTRACE report includes both the optimizer execution plan
and SQL statement execution statistics.
Option 2: Correct. This option is used to display rows and statistics. The
AUTOTRACE report shows SQL statement execution statistics and rows.
Option 3: Incorrect. This option is used to get the plan and statistics only. This is
similar to SET AUTOTRACE ON, but it suppresses the printing of the user's query
output.
Option 4: Incorrect. This option is used to display the execution plan only without
execution. The AUTOTRACE report shows only the optimizer execution path
without executing the statement.
Correct answer(s):
2. SET AUTOTRACE ON STATISTICS
The statistics are recorded by the server when your statement executes and indicates the
system resources required to execute your statement. The results include several
statistics.

Code
SQL> show autotrace
autotrace OFF
SQL> set autotrace traceonly statistics
SQL> SELECT * FROM oe.products;

288 rows selected.


Statistics
-------------------------------------------------------1334 recursive calls
0 db block gets
686 consistent gets
394 physical reads
0 redo size
103919 bytes sent via SQL*Net to client
629 bytes received via SQL*Net from client
21 SQL*Net roundtrips to/from client
22 sorts (memory)
0 sorts (disk)
288 rows processed
recursive calls
The recursive calls statistic is the number of recursive calls generated at both the user and
system level. The Oracle Database maintains tables used for internal processing. When the Oracle
Database needs to make a change to these tables, it internally generates an internal SQL statement,
which in turn generates a recursive call.
db block gets
The db block gets statistic is the number of times a CURRENT block was requested.
consistent gets
The consistent gets statistic is the number of times a consistent read was requested for a
block.
physical reads
The physical reads statistic is the total number of data blocks read from disk. This number
equals the value of "physical reads direct" plus all reads into buffer cache.
redo size
The redo size statistic is the total amount of redo generated in bytes.
The results also include six additional statistics.

Code
SQL> show autotrace
autotrace OFF
SQL> set autotrace traceonly statistics
SQL> SELECT * FROM oe.products;
288 rows selected.
Statistics

-------------------------------------------------------1334 recursive calls


0 db block gets
686 consistent gets
394 physical reads
0 redo size
103919 bytes sent via SQL*Net to client
629 bytes received via SQL*Net from client
21 SQL*Net roundtrips to/from client
22 sorts (memory)
0 sorts (disk)
288 rows processed
bytes sent via SQL*Net to client
The bytes sent via SQL*Net to client statistic is the total number of bytes sent to the
client from the foreground processes.
bytes received via SQL*Net from client
The bytes received via SQL*Net from client statistic is the total number of bytes
received from the client over Oracle Net.
SQL*Net roundtrips to/from client
The SQL*Net roundtrips to/from client statistic is the total number of Oracle Net
messages sent to and received from the client.
sorts (memory)
The sorts (memory) statistic is the number of sort operations that were performed completely in
memory and did not require any disk writes.
sorts (disk)
The sorts (disk) statistic is the number of sort operations that required at least one disk write.
rows processed
The rows processed statistic is the number of rows processed during the operation.
The client referred to in the statistics is SQL*Plus. Oracle Net refers to the generic
process communication between SQL*Plus and the server, regardless of whether Oracle
Net is installed. You cannot change the default format of the statistics report. Also note
that the statistics printed by AUTOTRACE are retrieved from V$SESSTAT.

Code
SQL> show autotrace
autotrace OFF
SQL> set autotrace traceonly statistics
SQL> SELECT * FROM oe.products;

288 rows selected.


Statistics
-------------------------------------------------------1334 recursive calls
0 db block gets
686 consistent gets
394 physical reads
0 redo size
103919 bytes sent via SQL*Net to client
629 bytes received via SQL*Net from client
21 SQL*Net roundtrips to/from client
22 sorts (memory)
0 sorts (disk)
288 rows processed

Note
db block gets indicates reads of the current block from the database.
consistent gets are reads of blocks that must satisfy a particular system
change number, or SCN. physical reads indicates reads of blocks from disk.
db block gets and consistent gets are the two statistics that are usually
monitored. These should be low compared to the number of rows retrieved. Sorts
should be performed in memory rather than on disk.

Summary
The execution plan is the output of the optimizer, which is presented to the execution
engine. The execution engine then implements the execution plan. There are various
ways to view the execution plan.
The EXPLAIN PLAN command helps generate the execution plan used to execute a SQL
statement. This command doesn't execute the statement, but produces the plan and
inserts it into a table named PLAN_TABLE. You can retrieve a PLAN_TABLE by using both
the ID and PARENT_ID columns with a CONNECT BY clause in a SELECT statement.
You can use the AUTOTRACE SQL*Plus facility to get a report on the execution plan and
statistics for SQL DML statements. These reports are useful for monitoring and tuning the
performance of the statements. To use AUTOTRACE, a PLAN_TABLE must be available in
your schema, and you must have the PLUSTRACE role.

Table of Contents
| Top of page |
| Learning Objectives |

| 1.Understanding execution plans |


| 2.Gathering execution plans |
| 3.Displaying execution plans |
| 4.Using the AUTOTRACE facility |
| Summary |
Copyright 2009 SkillSoft. All rights reserved.
SkillSoft and the SkillSoft logo are trademarks or registered trademarks of SkillSoft in the United States and certain other countries.
All other logos or trademarks are the property of their respective owners.

| Print | Contents | Close |

Using Views and AWR


Learning Objectives

After completing this topic, you should be able to

recognize the views containing execution plan information

recognize how to use the AWR

1. Using the V$SQL_PLAN view


The V$SQL_PLAN view provides a way of examining the execution plan for cursors that
are still in the library cache. The information in this view is very similar to the information
in PLAN_TABLE. However, EXPLAIN PLAN shows a theoretical plan that can be used if
this statement were to be executed, whereas V$SQL_PLAN contains the actual plan used.
The execution plan obtained by the EXPLAIN PLAN statement can be different from the
execution plan used to execute the cursor. This is because the cursor might have been
compiled with different values of session parameters.
V$SQL_PLAN shows the plan for a cursor rather than for all cursors associated with a
SQL statement. The difference is that a SQL statement can have more than one cursor
associated with it, with each cursor further identified by a CHILD_NUMBER.
For example, the same statement executed by different users has different cursors
associated with it if the object that is referenced is in a different schema. Similarly,

different hints can cause different cursors. The V$SQL_PLAN view can be used to see the
different plans for different child cursors of the same statement.

Note
Another useful view is V$SQL_PLAN_STATISTICS, which provides the execution
statistics of each operation in the execution plan for each cached cursor. Also the
V$SQL_PLAN_STATISTICS_ALL view concatenates information from
V$SQL_PLAN with execution statistics from V$SQL_PLAN_STATISTICS and
V$SQL_WORKAREA.
The V$SQL_PLAN view contains almost all the PLAN_TABLE columns, in addition to
others. The ADDRESS and HASH_VALUE columns present in PLAN_TABLE have the same
values:
ADDRESS and HASH_VALUE and
The ADDRESS and HASH_VALUE columns can be used to join with V$SQLAREA to add the
cursor specific information.
ADDRESS, HASH_VALUE, and CHILD_NUMBER
The ADDRESS, HASH_VALUE, and CHILD_NUMBER columns can be used to join with
V$SQL to add the child cursor-specific information.
The PLAN_HASH_VALUE column is a numerical representation of the SQL plan for the
cursor. By comparing one PLAN_HASH_VALUE with another, you can easily identify
whether the two plans are the same or not (rather than comparing the two plans line-byline).

Note
Since Oracle Database 10g, SQL_HASH_VALUE in V$SESSION has been
complemented with SQL_ID, which you retrieve in many other V$ views.
SQL_HASH_VALUE is a 32-bit value and deemed to not be unique enough for
large repositories of AWR data. SQL_ID is a 64-bit hash value, which is more
unique, the bottom 32 bits of which are SQL_HASH_VALUE. It is normally
represented as a character string to make it more manageable.
The V$SQL_PLAN_STATISTICS view provides the actual execution statistics for every
operation in the plan, such as the number of output rows and elapsed time. All statistics,
except the number of output rows, are cumulative.
For example, the statistics for a join operation also include the statistics for its two inputs.
The statistics in V$SQL_PLAN_STATISTICS are available for cursors that have been

compiled with the STATISTICS_LEVEL initialization parameter set to ALL or using the
GATHER_PLAN_STATISTICS hint.
The V$SQL_PLAN_STATISTICS_ALL view contains memory-usage statistics for row
sources that use SQL memory (sort or hash join). This view concatenates information in
V$SQL_PLAN with execution statistics from V$SQL_PLAN_STATISTICS and
V$SQL_WORKAREA.

2. Linking dynamic performance views


V$SQLAREA displays statistics on shared SQL areas and contains one row per SQL
string.

Graphic
In this example, V$SQLAREA expands into V$SQL in the V$SQLSTATS layer.
V$SQL in the V$SQLSTATS layer is connected V$SQL_WORKAREA,
V$SQL_PLAN, and V$SQL_PLAN_STATISTICS in the
V$SQL_PLAN_STATISTICS_ALL layer. V$SQL_PLAN contains estimated
statistics for each row source and V$SQL_PLAN_STATISTICS contains execution
statistics for each row source.
V$SQLAREA provides statistics on SQL statements that are in memory, parsed, and ready
for execution:
SQL_ID and
SQL_ID is the SQL identifier of the parent cursor in the library cache.
VERSION_COUNT
VERSION_COUNT is the number of child cursors that are present in the cache under this
parent.
V$SQL lists statistics on shared SQL areas and contains one row for each child of the
original SQL text entered:
ADDRESS
ADDRESS represents the address of the handle to the parent for this cursor.
HASH_VALUE
HASH_VALUE contains the value of the parent statement in the library cache.
SQL_ID
The SQL identifier of the parent cursor in the library cache is represented by SQL_ID.
PLAN_HASH_VALUE, and

PLAN_HASH_VALUE is a numeric representation of the SQL plan for this cursor. By


comparing one PLAN_HASH_VALUE with another, you can easily identify if the two plans
are the same or not (rather than comparing the two plans line-by-line).
CHILD_NUMBER
CHILD_NUMBER is the number of this child cursor.
Statistics displayed in V$SQL are normally updated at the end of query execution.
However, for long-running queries, they are updated every five seconds. This makes it
easy to see the impact of long-running SQL statements while they are still in progress.
V$SQL_PLAN contains the execution plan information for each child cursor loaded in the
library cache. The ADDRESS, HASH_VALUE, and CHILD_NUMBER columns can be used to
join with V$SQL to add the child cursor-specific information.
V$SQL_PLAN_STATISTICS provides execution statistics at the row source level for each
child cursor. The ADDRESS and HASH_VALUE columns can be used to join with
V$SQLAREA to locate the parent cursor. The ADDRESS, HASH_VALUE, and
CHILD_NUMBER columns can be used to join with V$SQL to locate the child cursor using
this area.
V$SQL_PLAN_STATISTICS_ALL contains memory usage statistics for row sources that
use SQL memory (sort or hash join). This view concatenates information in V$SQL_PLAN
with execution statistics from V$SQL_PLAN_STATISTICS and V$SQL_WORKAREA.
V$SQL_WORKAREA displays information about work areas used by SQL cursors. Each
SQL statement stored in the shared pool has one or more child cursors that are listed in
the V$SQL view. V$SQL_WORKAREA lists all work areas needed by these child cursors.
V$SQL_WORKAREA can be joined with V$SQLAREA on (ADDRESS, HASH_VALUE) and with
V$SQL on (ADDRESS, HASH_VALUE, CHILD_NUMBER).
You can use V$SQL_WORKAREA view to find answers to the following questions:

What are the top 10 work areas that require the most cache area?
For work areas allocated in the AUTO mode, what percentage of work areas run using maximum
memory?
V$SQLSTATS displays basic performance statistics for SQL cursors, with each row
representing the data for a unique combination of SQL text and optimizer plan (that is,
unique combination of SQL_ID and PLAN_HASH_VALUE). The column definitions for
columns in V$SQLSTATS are identical to those in the V$SQL and V$SQLAREA views.
However, the V$SQLSTATS view differs from V$SQL and V$SQLAREA in that it is faster,

more scalable, and has a greater data retention (the statistics may still appear in this
view, even after the cursor has been aged out of the shared pool).

Note
V$SQLSTATS contains a subset of columns that appear in V$SQL and
V$SQLAREA.

Question
Which statements accurately describe the V$SQL_PLAN view?
Options:
1.

It is similar to the PLAN_TABLE, but contains the actual plan used

2.

It concatenates information from V$SQL_PLAN_STATISTICS and


V$SQL_WORKAREA

3.

It provides a way of examining the execution plan for cursors that are still in the
library cache

4.

It provides the execution statistics of each operation in the execution plan for each
cached cursor

Answer
Option 1: Correct. EXPLAIN PLAN shows a theoretical plan that can be used if
this statement were to be executed, whereas V$SQL_PLAN contains the actual
plan used.
Option 2: Incorrect. The V$SQL_PLAN_STATISTICS_ALL view concatenates
information from V$SQL_PLAN with execution statistics from
V$SQL_PLAN_STATISTICS and V$SQL_WORKAREA.
Option 3: Correct. This view provides a way of examining the execution plan for
cursors that are still in the library cache, and shows the plan for a cursor rather
than for all cursors associated with a SQL statement.
Option 4: Incorrect. V$SQL_PLAN_STATISTICS provides the execution statistics
of each operation in the execution plan for each cached cursor.
Correct answer(s):
1. It is similar to the PLAN_TABLE, but contains the actual plan used
3. It provides a way of examining the execution plan for cursors that are still in the
library cache

You can query V$SQL_PLAN using the DBMS_XPLAN.DISPLAY_CURSOR() function to


display the current or last executed statement as in this example.

Graphic
The SQL_ID parameter that is being passed is the following: 47ju6102uvq5q.

Code
SELECT PLAN_TABLE_OUTPUT FROM
TABLE(DBMS_XPLAN.DISPLAY_CURSOR('47ju6102uvq5q'));
SQL_ID 47ju6102uvq5q, child number 0
------------------------------------SELECT e.last_name, d.department_name
FROM hr.employees e, hr.departments d WHERE
e.department_id =d.department_id
Plan hash value: 2933537672
------------------------------------------------------------------|Id|Operation
|Name
|Rows|Bytes|
Cost (%CPU|
------------------------------------------------------------------| 0|SELECT STATEMENT
|
|
|
|
6 (100|
| 1| MERGE JOIN
|
| 106| 2862|
6
(17|
| 2| TABLE ACCESS BY INDEX ROWID|
DEPARTMENTS| 27| 432|
2
(0|
| 3|
INDEX FULL SCAN
|DEPT_ID_PK
| 27|
|
1
(0|
|*4| SORT JOIN
|
| 107| 1177|
4
(25|
| 5|
TABLE ACCESS FULL
|EMPLOYEES
| 107| 1177|
3
(0|
------------------------------------------------------------------Predicate Information (identified by operation id):
--------------------------------------------------4 - access("E"."DEPARTMENT_ID"="D"."DEPARTMENT_ID")
filter("E"."DEPARTMENT_ID"="D"."DEPARTMENT_ID")
24 rows selected.

You can pass the value of SQL_ID for the statement as a parameter to obtain the
execution plan for a given statement. SQL_ID is the SQL_ID of the SQL statement in the
cursor cache.
You can retrieve the appropriate value by querying the SQL_ID column in V$SQL or
V$SQLAREA. Alternatively, you could select the PREV_SQL_ID column for a specific
session out of V$SESSION. This parameter defaults to null in which case the plan of the
last cursor executed by the session is displayed.

Graphic
The SQL_ID parameter that is being passed is the following: 47ju6102uvq5q.

Code
SELECT PLAN_TABLE_OUTPUT FROM
TABLE(DBMS_XPLAN.DISPLAY_CURSOR('47ju6102uvq5q'));
SQL_ID 47ju6102uvq5q, child number 0
------------------------------------SELECT e.last_name, d.department_name
FROM hr.employees e, hr.departments d WHERE
e.department_id =d.department_id
Plan hash value: 2933537672
------------------------------------------------------------------|Id|Operation
|Name
|Rows|Bytes|
Cost (%CPU|
------------------------------------------------------------------| 0|SELECT STATEMENT
|
|
|
|
6 (100|
| 1| MERGE JOIN
|
| 106| 2862|
6
(17|
| 2| TABLE ACCESS BY INDEX ROWID|
DEPARTMENTS| 27| 432|
2
(0|
| 3|
INDEX FULL SCAN
|DEPT_ID_PK
| 27|
|
1
(0|
|*4| SORT JOIN
|
| 107| 1177|
4
(25|
| 5|
TABLE ACCESS FULL
|EMPLOYEES
| 107| 1177|
3
(0|
-------------------------------------------------------------------

Predicate Information (identified by operation id):


--------------------------------------------------4 - access("E"."DEPARTMENT_ID"="D"."DEPARTMENT_ID")
filter("E"."DEPARTMENT_ID"="D"."DEPARTMENT_ID")
24 rows selected.
To obtain SQL_ID, execute this query.

Code
SELECT e.last_name, d.department_name
FROM hr.employees e, hr.departments d
WHERE e.department_id =d.department_id;
SELECT SQL_ID, SQL_TEXT FROM V$SQL
WHERE SQL_TEXT LIKE '%SELECT e.last_name,%' ;
13saxr0mmz1s3 SELECT SQL_id, sql_text from v$SQL
47ju6102uvq5q SELECT e.last_name, d.department_name
You can also pass the CHILD_NUMBER parameter to the
DBMS_XPLAN.DISPLAY_CURSOR()function. CHILD_NUMBER is the child number of the
cursor to display. If not supplied, the execution plan of all cursors matching the supplied
SQL_ID parameter is displayed. CHILD_NUMBER can be specified only if SQL_ID is
specified.

Code
SELECT PLAN_TABLE_OUTPUT FROM
TABLE(DBMS_XPLAN.DISPLAY_CURSOR('47ju6102uvq5q'));
SQL_ID 47ju6102uvq5q, child number 0
------------------------------------SELECT e.last_name, d.department_name
FROM hr.employees e, hr.departments d WHERE
e.department_id =d.department_id
Plan hash value: 2933537672
------------------------------------------------------------------|Id|Operation
|Name
|Rows|Bytes|
Cost (%CPU|
-------------------------------------------------------------------

| 0|SELECT STATEMENT
|
|
|
|
6 (100|
| 1| MERGE JOIN
|
| 106| 2862|
6
(17|
| 2| TABLE ACCESS BY INDEX ROWID|
DEPARTMENTS| 27| 432|
2
(0|
| 3|
INDEX FULL SCAN
|DEPT_ID_PK
| 27|
|
1
(0|
|*4| SORT JOIN
|
| 107| 1177|
4
(25|
| 5|
TABLE ACCESS FULL
|EMPLOYEES
| 107| 1177|
3
(0|
------------------------------------------------------------------Predicate Information (identified by operation id):
--------------------------------------------------4 - access("E"."DEPARTMENT_ID"="D"."DEPARTMENT_ID")
filter("E"."DEPARTMENT_ID"="D"."DEPARTMENT_ID")
24 rows selected.
The DBMS_XPLAN.DISPLAY_CURSOR()function can also accept the FORMAT parameter.
The FORMAT parameter controls the level of detail for the plan. In addition to the standard
values (BASIC, TYPICAL, SERIAL, and ALL), there are additional supported values to
display run-time statistics for the cursor:

Code
SELECT PLAN_TABLE_OUTPUT FROM
TABLE(DBMS_XPLAN.DISPLAY_CURSOR('47ju6102uvq5q'));
SQL_ID 47ju6102uvq5q, child number 0
------------------------------------SELECT e.last_name, d.department_name
FROM hr.employees e, hr.departments d WHERE
e.department_id =d.department_id
Plan hash value: 2933537672
------------------------------------------------------------------|Id|Operation
|Name
|Rows|Bytes|
Cost (%CPU|
------------------------------------------------------------------| 0|SELECT STATEMENT

|
| 1| MERGE JOIN

(100|

|
| 106| 2862|
6
(17|
| 2| TABLE ACCESS BY INDEX ROWID|
DEPARTMENTS| 27| 432|
2
(0|
| 3|
INDEX FULL SCAN
|DEPT_ID_PK
| 27|
|
1
(0|
|*4| SORT JOIN
|
| 107| 1177|
4
(25|
| 5|
TABLE ACCESS FULL
|EMPLOYEES
| 107| 1177|
3
(0|
------------------------------------------------------------------Predicate Information (identified by operation id):
--------------------------------------------------4 - access("E"."DEPARTMENT_ID"="D"."DEPARTMENT_ID")
filter("E"."DEPARTMENT_ID"="D"."DEPARTMENT_ID")
24 rows selected.
IOSTATS
Assuming that the basic plan statistics are collected when SQL statements are executed
(either by using the GATHER_PLAN_STATISTICS hint or by setting the
statistics_level parameter to ALL), the IOSTATS format shows I/O statistics for ALL
(or only for LAST) executions of the cursor.
MEMSTATS
Assuming that the Program Global Area, or PGA, memory management is enabled (that is,
the pga_aggregate_target parameter is set to a nonzero value), the MEMSTATS format
allows to display memory management statistics (for example, execution mode of the
operator, how much memory was used, number of bytes spilled to disk, and so on.) These
statistics only apply to memory-intensive operations, such as hash joins, sort, or some
bitmap operators.
ALLSTATS, and
It is a shortcut for IOSTATS MEMSTATS.
LAST
By default, plan statistics are shown for all executions of the cursor. The LAST keyword
can be specified to see only the statistics for the last execution.

3. Using Automatic Workload Repository


The Automatic Workload Repository, or AWR, is part of the intelligent infrastructure
introduced with Oracle Database 10g. This infrastructure is used by many components,

such as Automatic Database Diagnostic Monitor, or ADDM, for analysis.


The AWR automatically collects, processes, and maintains system performance statistics
for problem-detection and self-tuning purposes and stores the statistics persistently in the
database.
The statistics collected and processed by the AWR include

object statistics that determine both access and usage statistics of database segments

time-model statistics based on time usage for activities, displayed in the V$SYS_TIME_MODEL
and V$SESS_TIME_MODEL views

some of the system and session statistics collected in the V$SYSSTAT and V$SESSTAT views

SQL statements that produce the highest load on the system, based on criteria, such as elapsed
time, CPU time, buffer gets, and

Active Session History, or ASH, statistics, representing the history of recent sessions
The database automatically generates snapshots of the performance data once every
hour and collects the statistics in the workload repository. The data in the snapshot
interval is then analyzed by ADDM.
The ADDM compares the differences between snapshots to determine which SQL
statements to capture based on the effect on the system load. This reduces the number
of SQL statements that need to be captured over time.

Note
By using PL/SQL packages such as DBMS_WORKLOAD_REPOSITORY or Oracle
Enterprise Manager, you can mange the frequency and retention period of SQL
that is stored in the AWR.
Although the primary interface for managing the AWR is Enterprise Manager, monitoring
functions can be managed with procedures in the DBMS_WORKLOAD_REPOSITORY
package.
Snapshots are automatically generated for an Oracle database; however, you can use
DBMS_WORKLOAD_REPOSITORY procedures to manually create, drop, and modify the
snapshots and baselines that are used by the ADDM.
Snapshots and baselines are sets of historical data for specific time periods that are used
for performance comparisons. To invoke these procedures, a user must be granted the
DBA role.

You can manually create snapshots with the CREATE_SNAPSHOT procedure if you want
to capture statistics at times different than those of the automatically generated
snapshots.
In this CREATE_SNAPSHOT procedure example, a snapshot for the instance is created
immediately with the flush level specified to the default flush level of TYPICAL. You can
view this snapshot in the DBA_HIST_SNAPSHOT view.

Code
Exec DBMS_WORKLOAD_REPOSITORY.CREATE_SNAPSHOT ('ALL');
You can drop a range of snapshots using the DROP_SNAPSHOT_RANGE procedure. To
view a list of the snapshot IDs along with database IDs, check the DBA_HIST_SNAPSHOT
view. For example, you can drop the range of snapshots provided in this example.
In this example, the range of snapshot IDs to drop is specified from 22 to 32. The optional
database identifier is 3310949047. If you do not specify a value for dbid, the local
database identifier is used as the default value.
ASH data that belongs to the time period specified by the snapshot range is also purged
when the DROP_SNAPSHOT_RANGE procedure is called.

Code
Exec DBMS_WORKLOAD_REPOSITORY.DROP_SNAPSHOT_RANGE (low_snap_id =>
22, high_snap_id => 32, dbid => 3310949047);
You can adjust the interval and retention of snapshot generation for a specified database
ID. However, note that this can affect the precision of the Oracle diagnostic tools. The
INTERVAL setting specifies how often (in minutes) snapshots are automatically
generated. The RETENTION setting specifies how long (in minutes) snapshots are stored
in the workload repository. To adjust the settings, use the
MODIFY_SNAPSHOT_SETTINGS procedure.
In this example, the retention period is specified as 43,200 minutes (30 days), and the
interval between each snapshot is specified as 30 minutes. If NULL is specified, the
existing value is preserved. The optional database identifier is 3310949047. If you do not
specify a value for dbid, the local database identifier is used as the default value. You
can check the current settings for your database instance with the
DBA_HIST_WR_CONTROL view.

Code

Exec DBMS_WORKLOAD_REPOSITORY.MODIFY_SNAPSHOT_SETTINGS(
-retention
=> 43200, interval => 30, dbid => 3310949047);
You can view the AWR data on Oracle Enterprise Manager screens or in AWR reports.
However, you can also view the statistics directly using
V$ACTIVE_SESSION_HISTORY and
The V$ACTIVE_SESSION_HISTORY view displays active database session activity,
sampled once every second.
V$ metric views
V$ metric views provide metric data to track the performance of the system. The metric
views are organized into various groups, such as event, event class, system, session,
service, file, and tablespace metrics. These groups are identified in the V$METRICGROUP
view.
The DBA_HIST views contain historical data stored in the database. This group of views
include
DBA_HIST_ACTIVE_SESS_HISTORY
DBA_HIST_ACTIVE_SESS_HISTORY displays the history of the contents of the sampled
in memory active session history for recent system activity.
DBA_HIST_BASELINE
Information about the baselines captured in the system is displayed in
DBA_HIST_BASELINE.
DBA_HIST_DATABASE_INSTANCE
To display information about the database environment, you can use
DBA_HIST_DATABASE_INSTANCE.
DBA_HIST_SNAPSHOT
DBA_HIST_SNAPSHOT contains information about snapshots in the system.
DBA_HIST_SQL_PLAN, and
SQL execution plans are retrieved by DBA_HIST_SQL_PLAN.
DBA_HIST_WR_CONTROL
DBA_HIST_WR_CONTROL displays the settings for controlling AWR.

Question
Identify the statements that accurately describe AWR.
Options:

1.

It automatically generates snapshots of performance data

2.

It is used to manually collect, process, and maintain system-performance statistics

3.

You can manage the frequency and retention period of SQL that is stored in the
AWR

4.

You can view AWR data on OEM screens or AWR reports only

Answer
Option 1: Correct. The database automatically generates snapshots of the
performance data once every hour and collects the statistics in the workload
repository.
Option 2: Incorrect. The AWR automatically collects, processes, and maintains
system-performance statistics for problem-detection and self-tuning purposes and
stores the statistics persistently in the database.
Option 3: Correct. By using PL/SQL packages, such as
DBMS_WORKLOAD_REPOSITORY or OEM, you can mange the frequency and
retention period of SQL that is stored in the AWR.
Option 4: Incorrect. You can use OEM and AWR reports to view AWR data.
However, you can also query V$ACTIVE_SESSION_HISTORY, the V$ metric
views, and the DBA_HIST views.
Correct answer(s):
1. It automatically generates snapshots of performance data
3. You can manage the frequency and retention period of SQL that is stored in the
AWR
You can use the DBMS_XPLAN.DISPLAY_AWR() function to display all stored plans in
the AWR.
In this example, you pass in a SQL_ID as an argument. SQL_ID is the SQL_ID of the
SQL statement in the cursor cache.

Code
SQL> SELECT PLAN_TABLE_OUTPUT FROM TABLE
(DBMS_XPLAN.DISPLAY_AWR('454rug2yva18w'));
PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------SQL_ID 454rug2yva18w

-------------------SELECT /* example */ * from hr.employees natural join


hr.departments
Plan hash value: 4179021502
-----------------------------------------------------------------|Id|Operation
|Name
|Rows|Bytes|Cost (%CPU)|
Time
|
-----------------------------------------------------------------|0 |SELECT STATEMENT |
|
|
|
6
(100)|
|
|1 | HASH JOIN
|
| 11| 968|
6 (17)|
00:00:01|
|2 | TABLE ACCESS FULL|DEPARTMENTS| 11| 220|
2
(0)|
00:00:01|
|2 | TABLE ACCESS FULL|DEPARTMENTS| 11| 220|
2
(0)|
00:00:01|
|3 | TABLE ACCESS FULL|EMPLOYEES | 107| 7276|
3
(0)|
00:00:01|
-----------------------------------------------------------------Beside the SQL_ID parameter, the DISPLAY_AWR() function also takes the
PLAN_HASH_VALUE, DB_ID, and FORMAT parameters.

Code
SELECT tf.* FROM DBA_HIST_SQLTEXT ht, table
(DBMS_XPLAN.DISPLAY_AWR(ht.sql_id,null, null, 'ALL' ))
tf
WHERE ht.sql_text like '%JF%';
You follow five steps to complete this example.

Code
SQL> SELECT /* example */ * FROM hr.employees NATURAL
JOIN hr.departments;
SQL> SELECT sql_id, sql_text FROM v$SQL
WHERE sql_text
LIKE '%example%';

SQL> SELECT sql_id, sql_text FROM dba_hist_sqltext WHERE


sql_id ='
454rug2yva18w';
SQL> EXEC DBMS_WORKLOAD_REPOSITORY.CREATE.SNAPSHOT;
PL/SQL procedure successfully completed.
SQL> SELECT sql_id, sql_text FROM dba_hist_sqltext WHERE
sql_id
=' 454rug2yva18w';
SQL>SELECT plan_table_output FROM table
(DBMS_XPLAN.DISPLAY_AWR('454rug2yva18w));
SQL> SELECT /* example */ * FROM hr.employees NATURAL
JOIN hr.departments;
You first execute the SQL statement.
SQL> SELECT sql_id, sql_text FROM v$SQL
WHERE sql_text
LIKE '%example%';
Then you query V$SQL_TEXT to obtain the SQL_ID.
SQL> SELECT sql_id, sql_text FROM dba_hist_sqltext WHERE sql_id ='
454rug2yva18w';
Using the SQL_ID, verify that this statement has been captured in the
DBA_HIST_SQLTEXT dictionary view. If the query does not return rows, it indicates that
the statement has not yet been loaded in the AWR.
SQL> EXEC DBMS_WORKLOAD_REPOSITORY.CREATE.SNAPSHOT;
PL/SQL procedure successfully completed.
SQL> SELECT sql_id, sql_text FROM dba_hist_sqltext WHERE sql_id
=' 454rug2yva18w';
You can take a manual AWR snapshot rather than wait for the next snapshot (which
occurs every hour). Then check to see if it has been captured in DBA_HIST_SQLTEXT.
SQL>SELECT plan_table_output FROM table
(DBMS_XPLAN.DISPLAY_AWR('454rug2yva18w));
Use the DBMS_XPLAN.DISPLAY_AWR() function to retrieve the execution plan.
Since Oracle Database 10g, Release 2 (R2), it is possible to generate SQL reports from
AWR data, which is basically the equivalent to sqrepsql.sql with Statspack. In 10.1.0.4.0,
the equivalent to sprepsql.sql is not available in AWR.
However in 10gR2, the equivalent of sprepsql.sql is available. In 10gR2, the AWR SQL
report can be generated by calling the awrsqrpt.sql file.

Code
SQL> @$ORACLE_HOME/rdbms/admin/awrsqrpt
Specify the Report Type
Would you like an HTML report, or a plain text report?
Specify the number of days of snapshots to choose from
Specify the Begin and End Snapshot Ids
Specify the SQL Id
Enter value for sql_id: 6g1p4s9ra6ag8
Specify the Report Name
You can display the plan information in AWR by using the DISPLAY_AWR table function in
the DBMS_XPLAN PL/SQL package.
For example, this displays the plan information for a SQL_ID in AWR.
You can retrieve the appropriate value for the SQL statement of interest by querying the
SQL_ID in DBA_HIST_SQLTEXT column.

Code
SELECT * FROM
table(DBMS_XPLAN.DISPLAY_AWR('6g1p4s9ra6ag8'));

Summary
The information in V$SQL_PLAN view provides a way of examining the execution plan for
cursors that are still in the library cache. The V$SQL_PLAN_STATISTICS view provides
the execution statistics of each operation in the execution plan for each cached cursor.
All the statistics displayed in V$SQL are updated at the end of query execution. The
V$SQL_PLAN_STATISTICS view provides execution statistics, and the ADDRESS and
HASH_VALUE columns can be used to join with V$SQLAREA. The ADDRESS,
HASH_VALUE, and CHILD_NUMBER columns can be used to join with V$SQL.
The AWR automatically collects, processes, and maintains system performance statistics
and stores them persistently in the database.

Table of Contents
| Top of page |
| Learning Objectives |

| 1.Using the V$SQL_PLAN view |


| 2.Linking dynamic performance views |
| 3.Using Automatic Workload Repository |
| Summary |
Copyright 2009 SkillSoft. All rights reserved.
SkillSoft and the SkillSoft logo are trademarks or registered trademarks of SkillSoft in the United States and certain other countries.
All other logos or trademarks are the property of their respective owners.

| Print | Contents | Close |

SQL Monitoring and Execution Plans


Learning Objectives

After completing this topic, you should be able to

recognize how to perform SQL monitoring

interpret execution plans

1. Performing SQL monitoring


The SQL monitoring feature is enabled by default when the STATISTICS_LEVEL
initialization parameter is either set to ALL or TYPICAL (the default value).
Additionally, the CONTROL_MANAGEMENT_PACK_ACCESS parameter must be set to
DIAGNOSTIC+TUNING (the default value) because SQL monitoring is a feature of the
Oracle Database Tuning Pack.
By default, SQL monitoring is automatically started when a SQL statement runs parallel,
or when it has consumed at least five seconds of the CPU or I/O time in a single
execution.
SQL monitoring is active by default. However, two statement-level hints are available to
force or prevent a SQL statement from being monitored. To force SQL monitoring, use the
MONITOR hint. To prevent the hinted SQL statement from being monitored, use the
NO_MONITOR hint.
You can monitor the statistics for SQL statement execution using the V$SQL_MONITOR
and V$SQL_PLAN_MONITOR views. After monitoring is initiated, an entry is added to the

dynamic performance V$SQL_MONITOR view. This entry tracks key performance metrics
collected for the execution, including the elapsed time, CPU time, number of reads and
writes, I/O wait time, and various other wait times. These statistics are refreshed in near
real time as the statement executes, generally once every second.
After the execution ends, monitoring information is not deleted immediately, but is kept in
the V$SQL_MONITOR view for at least one minute. The entry is eventually deleted so its
space can be reclaimed as new statements are monitored.
The V$SQL_MONITOR and V$SQL_PLAN_MONITOR views can be used in conjunction
with the following views to get additional information about the execution that is
monitored:

V$SQL

V$SQL_PLAN

V$ACTIVE_SESSION_HISTORY

V$SESSION_LONGOPS, and

V$SESSION
Instead, you can use the SQL Monitoring Report to view SQL monitoring data. The SQL
monitoring report is also available in a GUI version through Enterprise Manager.
In this example, it is assumed that you SELECT from SALES from a different session than
the one used to print the SQL monitoring report.

Code
SQL> SELECT count(*) FROM sales;
In the SQL Monitoring Report, the DBMS_SQLTUNE.REPORT_SQL_MONITOR function
accepts several input parameters to specify the execution, the level of detail in the report,
and the report type (TEXT, HTML, or XML). By default, a text report is generated for the
last execution that was monitored if no parameters are specified.
After the SELECT statement is started, and while it executes, you print the SQL
monitoring report from a second session. From the report, you can see that the SELECT
statement executes currently.

Code

SQL>
SQL>
SQL>
SQL>

set long 10000000


set longchunksize 10000000
set linesize 200
SELECT dbms_sqltune.report_sql_monitor FROM dual;

SQL Monitoring Report


SQL Text
-------------------------SELECT count(*) FROM sales
Global Information
Status
: EXECUTING
Instance ID
: 1
Session ID
: 125
SQL ID
: fazrk33ng71km
SQL Execution ID
: 16777216
Plan Hash Value
: 1047182207
Execution Started : 02/19/2008 21:01:18
First Refresh Time : 02/19/2008 21:01:22
Last Refresh Time : 02/19/2008 21:01:42
-----------------------------------------------------------| Elapsed |
Cpu
|
IO
| Other
| Buffer | Reads |
| Time(s) | Time(s) | Waits(s) | Waits(s) | Gets |
|
-----------------------------------------------------------|
22 |
3.36 |
0.01 |
19 |
259K | 199K |
-----------------------------------------------------------The Global Information section in the SQL Monitoring Report gives you some important
information. To uniquely identify two executions of the same SQL statement, a composite
key called an execution key is generated.
This execution key consists of three attributes, each corresponding to a column in
V$SQL_MONITOR:

Code
SQL>
SQL>
SQL>
SQL>

set long 10000000


set longchunksize 10000000
set linesize 200
SELECT dbms_sqltune.report_sql_monitor FROM dual;

SQL Monitoring Report


SQL Text
--------------------------

SELECT count(*) FROM sales


Global Information
Status
: EXECUTING
Instance ID
: 1
Session ID
: 125
SQL ID
: fazrk33ng71km
SQL Execution ID
: 16777216
Plan Hash Value
: 1047182207
Execution Started : 02/19/2008 21:01:18
First Refresh Time : 02/19/2008 21:01:22
Last Refresh Time : 02/19/2008 21:01:42
-----------------------------------------------------------| Elapsed |
Cpu
|
IO
| Other
| Buffer | Reads |
| Time(s) | Time(s) | Waits(s) | Waits(s) | Gets |
|
-----------------------------------------------------------|
22 |
3.36 |
0.01 |
19 |
259K | 199K |
-----------------------------------------------------------

a SQL identifier to identify the SQL statement (SQL_ID)


an internally generated identifier to ensure that this primary key is truly unique (SQL_EXEC_ID),
and
a start execution time stamp (SQL_EXEC_START)

Note
The report also includes some important statistics calculated so far.
The SQL Monitoring Report then displays the execution path currently used by your
statement. SQL monitoring gives you the display of the current operation that executes in
the plan. This enables you to detect parts of the plan that are the most time-consuming,
so that you can focus your analysis on those parts. The running operation is marked by
an arrow in the Id column of the report.
The Time Active(s) column shows how long the operation has been active (the delta in
seconds between the first and the last active time).

Code
SQL Plan Monitoring Details
============================================================
========================
| Id
|
Operation
| Name | Rows
| Cost
|
Time
| Start |

|
|
|
| (Estim)
|
| Active(s) | Active |
============================================================
========================
|
0 | SELECT STATEMENT
|
|
| 78139
|
|
|
|
1 |
SORT AGGREGATE
|
|
1
|
|
|
|
| -> 2 |
TABLE ACCESS FULL | SALES | 53984K | 78139
|
23 |
+1 |
|
|
|
|
|
|
|
|
============================================================
========================
============================================================
======================
Starts |
Rows
| Activity |
Activity Detail
| Progress |
|
(Actual) | (percent) |
(sample #)
|
|
1
|
|
|
|
|
1
|
|
|
|
|
1 |
42081K |
100.00 | Cpu (4)
| 74%
|
============================================================
======================
The Start Active column shows, in seconds, when the operation in the execution plan
started relative to the SQL statement execution start time. In this report, the table access
full operation at Id 2 was the first to start (+1s Start Active) and ran for the first 23
seconds so far.
The Starts column shows the number of times the operation in the execution plan was
executed.
The Rows (Actual) column indicates the number of rows produced, and the Rows (Estim)
column shows the estimated cardinality from the optimizer.

Code

SQL Plan Monitoring Details


============================================================
========================
| Id
|
Operation
| Name | Rows
| Cost
|
Time
| Start |
|
|
|
| (Estim)
|
| Active(s) | Active |
============================================================
========================
|
0 | SELECT STATEMENT
|
|
| 78139
|
|
|
|
1 |
SORT AGGREGATE
|
|
1
|
|
|
|
| -> 2 |
TABLE ACCESS FULL | SALES | 53984K | 78139
|
23 |
+1 |
|
|
|
|
|
|
|
|
============================================================
========================
============================================================
======================
Starts |
Rows
| Activity |
Activity Detail
| Progress |
|
(Actual) | (percent) |
(sample #)
|
|
1
|
|
|
|
|
1
|
|
|
|
|
1 |
42081K |
100.00 | Cpu (4)
| 74%
|
============================================================
======================
The Activity (percent) and Activity Detail (sample #) columns are derived by joining the
V$SQL_PLAN_MONITOR and V$ACTIVE_SESSION_HISTORY views. Activity (percent)
shows the percentage of database time consumed by each operation of the execution
plan. Activity Detail (sample #) shows the nature of that activity (such as CPU or wait
event).
In this report, 100% of the database time is consumed by operation Id 2 (TABLE ACCESS
FULL of SALES) as provided in the Activity Detail (sample #) column. So far, this activity
consists of four samples, which are only attributed to CPU.

Code
SQL Plan Monitoring Details
============================================================
========================
| Id
|
Operation
| Name | Rows
| Cost
|
Time
| Start |
|
|
|
| (Estim)
|
| Active(s) | Active |
============================================================
========================
|
0 | SELECT STATEMENT
|
|
| 78139
|
|
|
|
1 |
SORT AGGREGATE
|
|
1
|
|
|
|
| -> 2 |
TABLE ACCESS FULL | SALES | 53984K | 78139
|
23 |
+1 |
|
|
|
|
|
|
|
|
============================================================
========================
============================================================
======================
Starts |
Rows
| Activity |
Activity Detail
| Progress |
|
(Actual) | (percent) |
(sample #)
|
|
1
|
|
|
|
|
1
|
|
|
|
|
1 |
42081K |
100.00 | Cpu (4)
| 74%
|
============================================================
======================
The last column, Progress, shows progress monitoring information for the operation from
the V$SESSION_LONGOPS view. According to this report, so far, the TABLE ACCESS
FULL operation is 74% complete. This column only appears in the report after a certain
amount of time, and only for the instrumented row sources.

Code

SQL Plan Monitoring Details


============================================================
========================
| Id
|
Operation
| Name | Rows
| Cost
|
Time
| Start |
|
|
|
| (Estim)
|
| Active(s) | Active |
============================================================
========================
|
0 | SELECT STATEMENT
|
|
| 78139
|
|
|
|
1 |
SORT AGGREGATE
|
|
1
|
|
|
|
| -> 2 |
TABLE ACCESS FULL | SALES | 53984K | 78139
|
23 |
+1 |
|
|
|
|
|
|
|
|
============================================================
========================
============================================================
======================
Starts |
Rows
| Activity |
Activity Detail
| Progress |
|
(Actual) | (percent) |
(sample #)
|
|
1
|
|
|
|
|
1
|
|
|
|
|
1 |
42081K |
100.00 | Cpu (4)
| 74%
|
============================================================
======================

Note
The SQL Plan Monitoring Details report can also contain the Memory and Temp
columns. These indicate the amount of memory and temporary space consumed
by corresponding operation of the execution plan.

Question

You are examining a SQL monitoring report. The Time Active(s) column displays a
value of 23. What does this number present?
Options:
1.

How long the operation has been active

2.

The number of rows produced

3.

The number of times the operation in the execution plan was executed

4.

When the operation in the execution plan started relative to the SQL statement
execution start time

Answer
Option 1: Correct. The Time Active(s) column shows how long the operation has
been active the delta in seconds between the first and the last active time.
Option 2: Incorrect. The Rows (Actual) column shows the number of rows
produced.
Option 3: Incorrect. The Starts column shows the number of times the operation
in the execution plan was executed.
Option 4: Incorrect. The Start Active column shows, in seconds, when the
operation in the execution plan started relative to the SQL statement execution
start time.
Correct answer(s):
1. How long the operation has been active

2. Interpreting an execution plan


Explain plan output is a representation of a tree of row sources. Each step (line in the
execution plan or node in the tree) represents a row source. The explain plan utility
indents nodes to indicate that they are the children of the parent above it.
The order of the nodes under the parent indicates the order of execution of the nodes
within that level. If two steps are indented at the same level, the first one is executed first.
In the tree format, the leaf at the left on each level of the tree is where the execution
starts. The steps of the execution plan are not performed in the order in which they are
numbered. There is a parent-child relationship between steps.

Graphic

There are four levels in the tree format. The node Root/Parent is on Level 1. This
node is divided into two subnodes on Level 2. These subnodes are named
Parent/Child. The Parent/Child subnode on the left is executed first. The two
Parent/Child subnodes are divided into two subnodes each on Level 3. Both of
their subnodes are named Child/Leaf and Parent/Child. The left Parent/Child
subnode on Level 3 is further divided into two subnodes named Child/Leaf. The
right Parent/Child subnode on Level 3 is divided into one subnode named
Child/Leaf.
In PLAN_TABLE and V$SQL_PLAN, the important elements to retrieve the tree structure
are the ID, PARENT_ID, and POSITION columns. In a trace file, these columns
correspond to the id, pid, and pos fields, respectively.
One way to read an execution plan is by converting it into a graph that has a tree
structure. You can start from the top, with id= 1, which is the root node in the tree. Next,
you must find the operations that feed this root node. That is accomplished by operations,
which have parent_id, or pid, with value 1.
To draw plan as a tree, do the following:
1. take the ID with the lowest number and place it at the top
2. look for rows which have a PID (parent) equal to this value
3. place these in the tree below the Parent according to their POS values from the lowest to the highest,
ordered from left to right, and
4. move down to the next ID after all the IDs for a parent have been found, and repeat the process, finding
new rows with the same PID
The first thing to determine in an explain plan is which node is executed first. With
complicated plans it is difficult to do this and also difficult to follow the steps through to the
end. Large plans are exactly the same as smaller ones, but with more entries.
The same basic rules apply. You can always collapse the plan to hide a branch of the tree
which does not consume much of the resources.
The standard explain plan interpretation is as follows:
1. Start at the top.
2. Move down the row sources until you get to one that produces data, but does not consume any. This is
the start row source.
3. Look at the siblings of this row source. These row sources are executed next.
4. After the children are executed, the parent is executed next.

5. Now that this parent and its children are completed, work back up the tree, and look at the siblings of the
parent row source and its parents. Execute as before.
6. Move back up the plan until all row sources are executed.
The standard tree interpretation is as follows:
1. Start at the top.
2. Move down the tree to the left until you reach the left node. This is executed first.
3. Look at the siblings of this row source. These row sources are executed next.
4. After the children are executed, the parent is executed next.
5. Now that this parent and its children are completed, work back up the tree, and look at the siblings of the
parent row source and its parents. Execute as before.
6. Move back up the tree until all row sources are exhausted.

Note
If you remember the few basic rules of explain plans and with some experience,
you can read most plans easily.

Question
Sequence the steps you take to interpret a standard explain plan.
Options:
A.

Start at the top and move down row sources until you get to one that produces data
but does not consume any

B.

Look at the siblings of the start row source

C.

Work back up the tree and look at the siblings of the parent row source and its
parents and execute as before

D.

Move back up the plan until all row sources are exhausted

Answer
Correct answer(s):
Start at the top and move down row sources until you get to one that
produces data but does not consume any is ranked as the first step.

The first step in interpreting a standard explain plan is to start at the top and
then move down the row sources until you get to one that produces data, but
does not consume any. This is the start row source.
Look at the siblings of the start row source is ranked as the second step.
The second step in interpreting a standard explain plan is to look through the
siblings of the start row source, as these are the row sources executed next.
Work back up the tree and look at the siblings of the parent row source and
its parents and execute as before is ranked as the third step.
The third step in interpreting a standard explain plan is to work back up the
tree and look at the siblings of the parent row source and its parents. After
the children are executed, the parent is executed next.
Move back up the plan until all row sources are exhausted is ranked as the
final step.
The final step in interpreting a standard explain plan is to move back up the
plan until all row sources are exhausted.
You start with an example query to illustrate how to interpret an execution plan. The query
with its associated execution plan and the same plan in the tree format is shown in this
example.

Graphic
The example query is the following:
SELECT /*+ RULE */ ename,job,sal,dname
FROM emp,dept
WHERE dept.deptno=emp.deptno and not exists(SELECT *
FROM salgrade
WHERE emp.sal between losal and hisal);
The output is displayed in a tabular format with Id, Operation, Name as columns.
The query tries to find employees who have salaries outside the range of salaries in the
salary grade table. The query is a SELECT statement from two tables with a subquery
based on another table to check the salary grades.

Code
SELECT /*+ RULE */ ename,job,sal,dname
FROM emp,dept
WHERE dept.deptno=emp.deptno and not exists(SELECT *
FROM salgrade
WHERE emp.sal
between losal and hisal);

-------------------------------------------------| Id | Operation
| Name
|
-------------------------------------------------|
0 | SELECT STATEMENT
|
|
|* 1 | FILTER
|
|
|
2 |
NESTED LOOPS
|
|
|
3 |
TABLE ACCESS FULL
| EMP
|
|
4 |
TABLE ACCESS BY INDEX ROWID| DEPT
|
|* 5 |
INDEX UNIQUE SCAN
| PK_DEPT |
|* 6 |
TABLE ACCESS FULL
| SALGRADE |
-------------------------------------------------Predicate Information (identified by operation id):
--------------------------------------------------1 - filter( NOT EXISTS
(SELECT 0 FROM "SALGRADE" "SALGRADE" WHERE
"HISAL">=:B1 AND "LOSAL"<=:B2))
5 - access("DEPT"."DEPTNO"="EMP"."DEPTNO")
6 - filter("HISAL">=:B1 AND "LOSAL"<=:B2)
This is the execution order for the query:
3
The plan starts with a full table scan of EMP (ID=3).
5
The rows are passed back to the controlling nested loops join step (ID=2), which uses
them to execute the lookup of rows in the PK_DEPT index in ID=5.
4
The ROWIDs from the index are used to lookup the other information from the DEPT table in
ID=4.
2
ID=2, the nested loops join step, is executed until completion.
6, and
After ID=2 has exhausted its row sources, a full table scan of SALGRADE in ID=6 (at the
same level in the tree as ID=2, therefore, its sibling) is executed.
1
This is used to filter the rows from ID2 and ID6.
The children are executed before parents, so although structures for joins must be set up
before the child execution, the children are notated as executed first.

Perhaps the easiest way is to consider it as the order in which execution completes, so
for the NESTED LOOPS join at ID=2, the two children {ID=3 and ID=4 (together with its
child)} must have completed their execution before ID=2 can be completed.
In this example, a plan dump from V$SQL_PLAN with STATISTICS_LEVEL is set to ALL.
This report includes some important additional information compared to the output of the
EXPLAIN PLAN command:

Code
SQL> ALTER SESSION SET statistics_level=ALL;
Session altered.
SQL> SELECT /*+ RULE to make sure it reproduces 100% */
ename,job,sal,dname
FROM emp,dept WHERE dept.deptno = emp.deptno AND NOT EXISTS
(SELECT * FROM salgrade
WHERE emp.sal BETWEEN losal AND hisal);
no rows selected
SQL> SELECT * FROM
table(DBMS_XPLAN.DISPLAY_CURSOR(null,null,'TYPICAL IOSTATS
LAST'));
SQL_ID 274019myw3vuf, child number 0
------------------------------------
Plan hash value: 1175760222
------------------------------------------------------------------------------| Id | Operation
| Name
| Starts
| A-Rows | Buffers |
------------------------------------------------------------------------------|* 1 | FILTER
|
|
1
|
0 |
61 |
|
2 |
NESTED LOOPS
|
|
1
|
14 |
25 |
|
3 |
TABLE ACCESS FULL
| EMP
|
1
|
14 |
7 |
|
4 |
TABLE ACCESS BY INDEX ROWID | DEPT
|
14
|
14 |
18 |
|* 5 |
INDEX UNIQUE SCAN
| PK_DEPT |
14

|
14 |
4 |
|* 6 |
TABLE ACCESS FULL
| SALGRADE |
12
|
12 |
36 |
------------------------------------------------------------------------------

A-Rows corresponds to the number of rows produced by the corresponding row source

Buffers corresponds to the number of consistent reads done by the row source, and

Starts indicates how many times the corresponding operation was processed
For each row from the EMP table, the system gets its ENAME, SAL, JOB, and DEPTNO.
Then the system accesses the DEPT table by its unique index (PK_DEPT) to get DNAME
using DEPTNO from the previous result set.
The TABLE ACCESS FULL operation on the EMP table (ID=3) is started once. However,
operations from ID 5 and 4 are started 14 times; once for each EMP row. At this step
(ID=2), the system gets all ENAME, SAL, JOB, and DNAME.

Code
SQL> ALTER SESSION SET statistics_level=ALL;
Session altered.
SQL> SELECT /*+ RULE to make sure it reproduces 100% */
ename,job,sal,dname
FROM emp,dept WHERE dept.deptno = emp.deptno AND NOT EXISTS
(SELECT * FROM salgrade
WHERE emp.sal BETWEEN losal AND hisal);
no rows selected
SQL> SELECT * FROM
table(DBMS_XPLAN.DISPLAY_CURSOR(null,null,'TYPICAL IOSTATS
LAST'));
SQL_ID 274019myw3vuf, child number 0
------------------------------------
Plan hash value: 1175760222
------------------------------------------------------------------------------| Id | Operation
| Name
| Starts
| A-Rows | Buffers |

------------------------------------------------------------------------------|* 1 | FILTER
|
|
1
|
0 |
61 |
|
2 |
NESTED LOOPS
|
|
1
|
14 |
25 |
|
3 |
TABLE ACCESS FULL
| EMP
|
1
|
14 |
7 |
|
4 |
TABLE ACCESS BY INDEX ROWID | DEPT
|
14
|
14 |
18 |
|* 5 |
INDEX UNIQUE SCAN
| PK_DEPT |
14
|
14 |
4 |
|* 6 |
TABLE ACCESS FULL
| SALGRADE |
12
|
12 |
36 |
------------------------------------------------------------------------------The system now must filter out employees who have salaries outside the range of
salaries in the salary grade table. To do that, for each row from ID=2, the system
accesses the SALGRADE table using a FULL TABLE SCAN operation to check if the
employees salary is outside the salary range.
This operation only needs to be done 12 times in this case because at run time the
system does the check for each distinct salary, and there are 12 distinct salaries in the
EMP table.

Code
SQL> ALTER SESSION SET statistics_level=ALL;
Session altered.
SQL> SELECT /*+ RULE to make sure it reproduces 100% */
ename,job,sal,dname
FROM emp,dept WHERE dept.deptno = emp.deptno AND NOT EXISTS
(SELECT * FROM salgrade
WHERE emp.sal BETWEEN losal AND hisal);
no rows selected
SQL> SELECT * FROM
table(DBMS_XPLAN.DISPLAY_CURSOR(null,null,'TYPICAL IOSTATS
LAST'));
SQL_ID 274019myw3vuf, child number 0
-------------------------------------


Plan hash value: 1175760222
------------------------------------------------------------------------------| Id | Operation
| Name
| Starts
| A-Rows | Buffers |
------------------------------------------------------------------------------|* 1 | FILTER
|
|
1
|
0 |
61 |
|
2 |
NESTED LOOPS
|
|
1
|
14 |
25 |
|
3 |
TABLE ACCESS FULL
| EMP
|
1
|
14 |
7 |
|
4 |
TABLE ACCESS BY INDEX ROWID | DEPT
|
14
|
14 |
18 |
|* 5 |
INDEX UNIQUE SCAN
| PK_DEPT |
14
|
14 |
4 |
|* 6 |
TABLE ACCESS FULL
| SALGRADE |
12
|
12 |
36 |
------------------------------------------------------------------------------In this second example, the query retrieves names, department names, and addresses
for employees whose departments are located in Seattle and who have managers.

Graphic
The example query is the following:
SQL> select /*+ USE_NL(d) use_nl(m) */ m.last_name as dept_manager
2 , d.department_name
3 , l.street_address
4 from hr.employees m join
5 hr.departments d on (d.manager_id = m.employee_id)
6 natural join
7 hr.locations l
8 where l.city = 'Seattle';
0 SELECT STATEMENT
1 0 NESTED LOOPS
2 1 NESTED LOOPS
3 2 TABLE ACCESS BY INDEX ROWID LOCATIONS
4 3 INDEX RANGE SCAN LOC_CITY_IX
5 2 TABLE ACCESS BY INDEX ROWID DEPARTMENTS
6 5 INDEX RANGE SCAN DEPT_LOCATION_IX

7 1 TABLE ACCESS BY INDEX ROWID EMPLOYEES


8 7 INDEX UNIQUE SCAN EMP_EMP_ID_PK
For formatting reasons, the explain plan has the ID in the first column, and PID in the
second column. The position is reflected by the indentation. The execution plan shows
two nested loops join operations.
You follow the same steps from the previous example to see the execution plan for this
example:
1. Start at the top with ID=0.
2. Move down the row sources until you get to the one, that produces data, but does not consume any. In
this case, ID 0, 1, 2, and 3 consume data. ID=4 is the first row source that does not consume any. This
is the start row source. ID=4 is executed first. The index range scan produces ROWIDs, which are used to
lookup in the LOCATIONS table in ID=3.
3. Look at the siblings of this row source. These row sources are executed next. The sibling at the same
level as ID=3 is ID=5. Node ID=5 has a child ID=6, which is executed before it. This is another index
range scan producing ROWIDs, which are used to lookup in the DEPARTMENTS table in ID=5.
4. After the children operation, the parent operation is next. The NESTED LOOPS join at ID=2 is executed
next bringing together the underlying data.
The next three steps are as follows:
1. Now that this parent and its children are completed, walk back up the tree, and look at the
siblings of the parent row source and its parents. Execute as before. The sibling of ID=2 at the
same level in the plan is ID=7. This has a child ID=8, which is executed first. The index unique
scan produces ROWIDs, which are used to lookup in the EMPLOYEES table in ID=7.
2. Move back up the plan until all row sources are exhausted. Finally, this is brought together with the
NESTED LOOPS at ID=1, which passes the results back to ID=0.
3. The execution order is 4 3 6 5 2 8 7 1 0.
Here is the complete description of this plan:

The inner nested loops is executed first using LOCATIONS as the driving table, using an index
access on the CITY column. This is because you search for departments in Seattle only.

The result is joined with the DEPARTMENTS table, using the index on the LOCATION_ID join
column; the result of this first join operation is the driving row source for the second nested loops
join.

The second join probes the index on the EMPLOYEE_ID column of the EMPLOYEES table. The
system can do that because it knows (from the first join) the employee ID of all managers of
departments in Seattle. Note that this is a unique scan because it is based on the primary key.
Finally, the EMPLOYEES table is accessed to retrieve the last name.
In this example, try to find the order in which the plan is executed and deduce what is the
join order (order in which the system joins tables). Again, ID is in the first column and PID
in the second column. The position is reflected by the indentation.
It is important to recognize what the join order of an execution plan is, to be able to find
your plan into a 10053 event trace file.

Code
SELECT /*+ ORDERED use_hash(b) swap_join_inputs(c) */
max(a.i)
FROM t1 a, t2 b, t3 c
WHERE a.i = b.i AND a.i = c.i;
0
1
2
3
4
5
6

1
2
2
4
4

SELECT STATEMENT
SORT AGGREGATE
HASH JOIN
TABLE ACCESS FULL T3
HASH JOIN
TABLE ACCESS FULL T1
TABLE ACCESS FULL T2

Here is the interpretation of this plan:

Code
SELECT /*+ ORDERED use_hash(b) swap_join_inputs(c) */
max(a.i)
FROM t1 a, t2 b, t3 c
WHERE a.i = b.i AND a.i = c.i;
0
1
2
3
4
5
6

1
2
2
4
4

SELECT STATEMENT
SORT AGGREGATE
HASH JOIN
TABLE ACCESS FULL T3
HASH JOIN
TABLE ACCESS FULL T1
TABLE ACCESS FULL T2

the system first hashes the T3 table (Operation ID=3) into memory

then it hashes the T1 table (Operation ID=5) into memory

then the scan of the T2 table begins (Operation ID=6)

the system picks a row from T2 and probes T1 (T1.i=T2.i)

if the row survives, the system probes T3 (T1.i=T3.i)

if the row survives, the system sends it to next operation, and

the system outputs the maximum value from the previous result set
In conclusion, the execution order is : 3 5 6 4 2 1. The join order is: T1 T2
T3. You can also use Enterprise Manager to understand execution plans, especially
because it displays the Order column.

Note
A special hint was used to make sure T3 would be first in the plan.

3. Reading complex execution plans


The plan in this example comes from the query on the data dictionary. It is so long that it
is very difficult to apply the previous method to interpret it and locate the first operation.
You can always collapse a plan to make it readable. This is easy to do when using the
Enterprise Manager interface. You can clearly see that this plan is a UNION-ALL of two
branches.
Your knowledge about the data dictionary enables you to understand that the two
branches correspond to dictionary-managed tablespaces and locally-managed ones.
Your knowledge about your database enables you to know that there are no dictionarymanaged tablespaces.
So, if there is a problem, it must be on the second branch. To get confirmation, you must
look at the plan information and execution statistics of each row source to locate the part
of the plan that consumes most resources. Then, you just need to expand the branch you
want to investigate (where time is being spent).
To use this method, you must look at the execution statistics that are generally found in
V$SQL_PLAN_STATISTICS or in the tkprof reports generated from trace files. For
example, tkprof cumulates for each parent operation the time it takes to execute itself
plus the sum of all its child operation time.

When you tune a SQL statement in an Online Transaction Processing or OLTP


environment, the goal is to drive from the table that has the most selective filter. This
means that there are fewer rows passed to the next step. If the next step is a join, this
means fewer rows are joined. Check to see whether the access paths are optimal.
When you examine the optimizer execution plan, observe the
driving table
Observe if the plan is such that the driving table has the best filter.
join order
Observe if the join order in each step means that the fewest number of rows are returned
to the next step (that is, the join order should reflect going to the best not-yet-used filters).
join method
Observe if the join method is appropriate for the number of rows being returned. For
example, nested loop joins through indexes may not be optimal when many rows are
returned.
views
Observe if views are used efficiently. Look at the SELECT list to see whether access to the
view is necessary.
cartesian products, and
Observe if there are any unintentional cartesian products (even with small tables).
tables
Observe if each table is being accessed efficiently: Consider the predicates in the SQL
statement and the number of rows in the table. Observe suspicious activity, such as a full
table scans on tables with large number of rows, which have predicates in the WHERE
clause. Also, a full table scan might be more efficient on a small table, or to leverage a
better join method (for example, hash_join) for the number of rows returned.
If any of these conditions are not optimal, consider restructuring the SQL statement or the
indexes available on the tables.
The execution plan alone cannot differentiate between well-tuned statements and those
that perform poorly. For example, an EXPLAIN PLAN output that shows that a statement
uses an index does not necessarily mean that the statement runs efficiently. Sometimes
indexes can be extremely inefficient.
It is best to use EXPLAIN PLAN to determine an access plan, and then later prove that it
is the optimal plan through testing. When evaluating a plan, you should examine the
statements actual resource consumption.

Summary

By default, SQL monitoring is automatically started when a SQL statement runs. You can
monitor the statistics for a SQL statement execution using the V$SQL_MONITOR and
V$SQL_PLAN_MONITOR views.
Execution plan output is a representation of a tree of row sources. In such a tree format,
the leaf at the left on each level of the tree is where the execution starts. You interpret an
execution plan and a tree in much the same manner.
An execution plan alone cannot tell you whether a plan is good or not; you may need to
perform additional testing and tuning.

Table of Contents
| Top of page |
| Learning Objectives |
| 1.Performing SQL monitoring |
| 2.Interpreting an execution plan |
| 3.Reading complex execution plans |
| Summary |
Copyright 2009 SkillSoft. All rights reserved.
SkillSoft and the SkillSoft logo are trademarks or registered trademarks of SkillSoft in the United States and certain other countries.
All other logos or trademarks are the property of their respective owners.

| Print | Contents | Close |

Extracting Execution Plans


Learning Objective

After completing this topic, you should be able to

extract an execution plan used by the optimizer to execute a query

Exercise overview
In the EP schema, the TEST table consists of two columns - C and D. All rows of column
C contain the value 1 and all rows of column D contain a string of the letter A. An index

has been created on the C column. Using the TEST table, you want to examine various
methods that can be used to extract the execution plan used by the optimizer to execute
a query.
In this exercise, you're required to extract execution plans used by the optimizer.
This involves the following tasks:

extracting execution plans

monitoring execution plans

retrieving execution plans

Task 1: Extracting execution plans


You want to extract the execution plan used by the optimizer to execute a query. From a
first SQL*Plus session, you have started the execution of the "ep_session_issue" script,
which counts the rows returned by a query. From a second SQL*Plus session, you want
to monitor the execution plan used by the first session. Execute the "ep_monitor" script
from the second SQL*Plus session. Use the '/" character to execute the last command of
the script three more times while the script in the first session finishes executing. Return
to the first SQL*Plus session to view the results by minimizing the second session's
window. Use the @ command to execute all scripts and enter each command using one
line only.

Steps list
Instructions
1. Type @ep_monitor and press Enter
2. Type / and press Enter
3. Type / and press Enter
4. Type / and press Enter
5. Click Minimize

Task 2: Monitoring execution plans


In session one, you have executed the "ep_explain" script and determined that the
execution plan uses a hash join on top of two index fast full scans. You have enabled
autotrace, executed the "ep_execute" script in session one, and then executed the
"ep_monitor" script in session two. From session two, use the / command to execute the
last command three more times while the script in session one finishes executing. Then
return to session one to view the results by minimizing the current SQL*Plus window. Use
the @ command to execute all scripts and enter each command using one line only.

Steps list
Instructions
1. Type / and press Enter
2. Type / and press Enter
3. Type / and press Enter
4. Click the Minimize icon

Task 3: Retrieving execution plans


You now want to ensure that you can gather all execution plans for a query without
changing any session parameters. You also want to retrieve all execution plans
corresponding to all the queries you have executed. Execute the "ep_execute_with_all"
and "ep_retrieve_all_plans" scripts respectively. You then want to try and retrieve your
execution plans from the Automatic Workload Repository by executing the
"ep_retrieve_awr" script. You notice that none of your queries were stored in the AWR.
Ensure that you can retrieve your queries from the AWR using the CREATE_SNAPSHOT
procedure of the DBMS_WORKLOAD_REPOSITORY package, specifying a flush level of
"ALL." Then test your solution by executing the "ep_show_awr" script. Execute all scripts
using the @ command and enter each command using one line only.

Steps list
Instructions
1. Type @ep_execute_with_all and press Enter
2. Type @ep_retrieve_all_plans and press Enter
3. Type @ep_retrieve_awr and press Enter
4. Type EXEC DBMS_WORKLOAD_REPOSITORY.CREATE_SNAPSHOT('ALL'); and press Enter
5. Type @ep_show_awr and press Enter

Table of Contents
| Top of page |
| Learning Objective |
| Exercise overview |
| Task 1: Extracting execution plans |
| Task 2: Monitoring execution plans |
| Task 3: Retrieving execution plans |

Copyright 2009 SkillSoft. All rights reserved.


SkillSoft and the SkillSoft logo are trademarks or registered trademarks of SkillSoft in the United States and certain other countries.
All other logos or trademarks are the property of their respective owners.

| Print | Contents | Close |

Working with Star Transformation


Learning Objective

After completing this topic, you should be able to

recognize how to use star transformation

1. Star schema and star transformation


The star schema is the simplest data warehouse schema. It is called a star schema
because the entity relationship diagram of this schema resembles a star, with points
radiating from a central table.
The center of the star consists of one or more fact tables and the points of the star are the
dimension tables.
A star schema is characterized by one or more very large fact tables that contain the
primary information in the data warehouse. And a number of much smaller dimension
tables (or lookup tables), each of which contains information about the entries for a
particular attribute in the fact table.

Graphic
The Star Schema Model contains a fact table named SALES, surrounded by four
Dimension/Lookup tables on each corner PRODUCTS, CUSTOMERS, TIMES,
and CHANNELS. Each of the Dimension/Lookup table is connected to the fact
table.
A star query is a join between a fact table and a number of dimension tables. Each
dimension table is joined to the fact table using a primary key to foreign key join. But the
dimension tables are not joined to each other.
The Cost-Based Optimizer or CBO recognizes star queries and generates efficient
execution plans for them. A typical fact table contains keys and measures.
For example, in the Sales History schema, the SALES fact table contains the

QUANTITY_SOLD, AMOUNT_SOLD, and COST measures. And the CUST_ID, TIME_ID,


PROD_ID, and CHANNEL_ID keys. The dimension tables are CUSTOMERS, TIMES,
PRODUCTS, and CHANNELS. The PRODUCTS dimension table, for example, contains
information about each product number that appears in the fact table.

Graphic
The PRODUCTS table contains the PROD_ID, PROD_NAME, and PROD_DESC
fields. The CUSTOMERS table contains the CUST_ID, CUST_GENDER, and
CUST_CITY fields. The TIMES table contains the TIME_ID, DAY_NAME, and
CALENDAR_YEAR fields. And the CHANNELS table contains the CHANNEL_ID,
CHANNEL_DESC, and CHANNEL_CLASS fields.

Note
It is easy to generalize this model to include more than one fact table.
The snowflake schema is a more complex data warehouse model than a star schema,
and is a type of star schema. It is called a snowflake schema because the diagram of the
schema resembles a snowflake. Snowflake schemas normalize dimensions to eliminate
redundancy. That is, the dimension data has been grouped into multiple tables instead of
one large table.
For example, a product dimension table in a star schema might be normalized into a
PRODUCTS table, a PRODUCT_CATEGORY table, and a PRODUCT_MANUFACTURER table in
a snowflake schema or you can normalize the CUSTOMERS table using the COUNTRIES
table.
While this saves space, it increases the number of dimension tables and requires more
foreign key joins. The result is more complex queries and reduced query performance.

Graphic
The Snowflake Schema Model contains the SALES table in the center. This table
is connected to the PRODUCTS, CUSTOMERS, COUNTRIES, TIMES, and
CHANNELS tables.

Note
It is suggested that you select a star schema over a snowflake schema unless you
have a clear reason not to.
Consider this star query example.

Code
SELECT ch.channel_class, c.cust_city,
t.calendar_quarter_desc,
SUM(s.amount_sold) sales_amount
FROM sales s,times t,customers c,channels ch
WHERE s.time_id = t.time_id AND
s.cust_id = c.cust_id AND
s.channel_id = ch.channel_id AND
c.cust_state_province = 'CA' AND
ch.channel_desc IN ('Internet','Catalog') AND
t.calendar_quarter_desc IN ('1999-Q1','1999-Q2')
GROUP BY ch.channel_class, c.cust_city,
t.calendar_quarter_desc;
In the example star query, for the star transformation to operate, it is supposed that the
SALES table of the Sales History schema has bitmap indexes on the TIME_ID,
CHANNEL_ID, and CUST_ID columns.

Code
SELECT ch.channel_class, c.cust_city,
t.calendar_quarter_desc,
SUM(s.amount_sold) sales_amount
FROM sales s,times t,customers c,channels ch
WHERE s.time_id = t.time_id AND
s.cust_id = c.cust_id AND
s.channel_id = ch.channel_id AND
c.cust_state_province = 'CA' AND
ch.channel_desc IN ('Internet','Catalog') AND
t.calendar_quarter_desc IN ('1999-Q1','1999-Q2')
GROUP BY ch.channel_class, c.cust_city,
t.calendar_quarter_desc;
Before you identify the benefits of a star transformation, you should review how a join on
a star schema is processed without their benefits.

Graphic
The Execution Plan Without Star Transformation image contains a flowchart, and
the result of running the query. The flowchart begins with a Hash Join that

connects with the CHANNELS table and another Hash Join. The second Hash
Join connects to the TIMES table and a third Hash Join. The third Hash Join in
turn connects with the CUSTOMERS and the SALES tables.
The fundamental issue with this plan, which is executed without star transformation, is
that the query always starts joining the SALES table to a dimension table. This results in a
very large number of rows that can only be trimmed down by the other parent joins in the
execution plan.
To get the best possible performance for star queries, it is important to follow some basic
guidelines or conditions:

A bitmap index should be built on each of the foreign key columns of the fact table or tables.
The STAR_TRANSFORMATION_ENABLED initialization parameter should be set to TRUE. This
enables an important optimizer feature for star queries. It is set to FALSE by default for backwards
compatibility.
When a data warehouse satisfies these conditions, the majority of the star queries that
run in the data warehouse use the query execution strategy known as star transformation.
Star transformation provides very efficient query performance for star queries.
Star transformation is a powerful optimization technique that relies on implicitly rewriting
(or transforming) the SQL of the original star query. The end user never needs to know
any of the details about the star transformation. The system's CBO automatically selects
star transformation where appropriate.
Oracle processes a star query using two basic phases:
1. The first phase retrieves exactly the necessary rows from the fact table (the result set). Because
this retrieval utilizes bitmap indexes, it is very efficient.

2. The second phase joins this result set to the dimension tables. This operation is called a semijoin.

Note
At least three tables are used in the query (two dimensions and one fact).
Star transformation is not supported for tables with certain characteristics. These
characteristics are

queries with a table hint that is incompatible with a bitmap access path

queries that contain bind variables

tables with too few bitmap indexes, because there must be a bitmap index on a fact table column
for the optimizer to generate a subquery for it

remote fact tables, however, remote dimension tables are allowed in the subqueries that are
generated

antijoined tables

tables that are already used as a dimension table in a subquery, and

tables that are really unmerged views, which are not view partitions

Question
What characteristics cause star transformation to be unsupported for a table?
Options:
1.

Bitmap indexes on a fact table column

2.

Queries containing antijoined tables

3.

Queries referring to remote fact tables

4.

Queries without bind variables

Answer
Option 1: Incorrect. There must be a bitmap index on a fact table column for the
optimizer to generate a subquery for it.
Option 2: Correct. Tables that contain queries that refer to antijoined tables,
unmerged nonpartitioned views, and bind variables are not transformed.
Option 3: Correct. Tables that contain queries that refer to remote fact tables are
not transformed. However, remote dimension tables are allowed in the subqueries
that are generated.
Option 4: Incorrect. Tables that contain bind variables are not transformed. This is
also the case for queries with a table hint that is incompatible with a bitmap
access path.
Correct answer(s):
2. Queries containing antijoined tables
3. Queries referring to remote fact tables

2. Queries in star transformation


In this star query example, the system processes the query in two phases.
In the first phase, the system uses the filters against the dimensional tables to retrieve the
dimensional primary keys, which match those filters.
Then the system uses those primary keys to probe the bitmap indexes on the foreign key
columns of the fact table to identify and retrieve only the necessary rows from the fact
table. That is, the system retrieves the result set from the SALES table by using
essentially the rewritten query.

Code
SELECT s.amount_sold
FROM sales s
WHERE time_id IN (SELECT time_id
FROM times
WHERE calendar_quarter_desc
IN('1999-Q1','1999-Q2'))
AND

cust_id IN (SELECT cust_id


FROM customers
WHERE cust_state_province = 'CA')

AND channel_id IN(SELECT channel_id


FROM channels
WHERE channel_desc IN
('Internet','Catalog'));

Note
The SQL statement is a theoretical statement that represents what goes on in
phase I.
You can retrieve fact table rows using only one dimension table. Based on the
corresponding dimension filter predicates, like in t.calendar_quarter_desc IN
('1999- Q1','1999-Q2'), from the star query example, the system scans the
dimension table. And for each corresponding row, it probes the corresponding fact bitmap
index and fetches the corresponding bitmap.

Graphic

The image depicts Retrieving fact Rows from One Dimension, which is part of
Phase 1. This phase begins with BITMAP MERGE that connects to BITMAP KEY
ITERATION. BITMAP KEY ITERATION further connects to Dimension Table
Access and Fact Table Bitmap Access. This entire process produces one bitmap.
BITMAP KEY ITERATION then makes each key coming from its left input a lookup key for
the index on its right input, and returns all bitmaps fetched by that index. Note that its left
input supplies join keys from the dimension table in this case.
The last step in this tree merges all fetched bitmaps from the previous steps. This merge
operation produces one bitmap that can be described as representing the rows of the fact
table that join with the rows of interest from the dimension table.

Note
BITMAP_MERGE_AREA_SIZE plays an important role in tuning the performance of
this operation when using the shared server mode. The system does not
recommend using the BITMAP_MERGE_AREA_SIZE parameter unless the
instance is configured with the shared server option. The system recommends
that you enable automatic sizing of SQL working areas by setting
PGA_AGGREGATE_TARGET instead. BITMAP_MERGE_AREA_SIZE is retained for
backward compatibility.
You can also retrieve fact rows from all dimensions in the first phase. When you do this,
the steps for retrieving fact rows from one dimension are repeated for each dimension
table. So each BITMAP MERGE in the plan generates a bitmap for a single dimension
table. To identify all rows from the fact table that are of interest, the system must intersect
all generated bitmaps.
This is to eliminate fact rows that join with one dimension, but not with all of them. This is
achieved by performing a very efficient BITMAP AND operation on all the bitmaps
generated for each dimension. The resulting bitmap can be described as representing the
rows from the fact table that are known to join with all the qualified dimension rows.

Graphic
When retrieving fact rows from all dimensions, the process begins with BITMAP
Conversion To Rowids, which is an Intermediate Result Set, or IRS. This connects
to BITMAP AND, which is further connected to Merge 1, Merge i, and Merge n,
which are separated by ellipses. This whole procedure ANDs multiple bitmaps
together.

Note

Until now, only fact bitmap indexes and dimension tables were used. To further
access the fact table, the system must convert the generated bitmap to a rowids
set.
After the result set is determined, the system enters phase 2 of the star transformation
algorithm. In this phase, it is needed to join the sales data, corresponding to the result
set, with the dimension tables data used to group the rows pertaining to the query's select
list.
Note that a hash join is performed between the fact table and its dimensions. Although a
hash join is statistically the most-used technique to join rows in a star query, this might
not be always true, as this is evaluated by the CBO.

Graphic
Joining the Intermediate Result Set with Dimensions is part of Phase 2. This
procedure begins with a HASH JOIN that connects to Dimension n Table Access
and a HASH JOIN in a dotted circle. The dotted HASH JOIN connects to a
Dimension i Table Access in a dotted circle and another HASH JOIN. This HASH
JOIN further connects to Dimension 1 Table Access and Fact Table Access From
IRS.
This query is a possible plan to answer the query in the star query example of execution
plan without star transformation. Note that for formatting purposes, only the channels and
times dimensions are shown. It is easy to generalize the case for n dimensions.

Code
SORT GROUP BY
HASH JOIN
HASH JOIN
TABLE ACCESS BY INDEX ROWID SALES
BITMAP CONVERSION TO ROWIDS
BITMAP AND
BITMAP MERGE
BITMAP KEY ITERATION
BUFFER SORT
TABLE ACCESS FULL CHANNELS
BITMAP INDEX RANGE SCAN SALES_CHANNELS_BX
BITMAP MERGE
BITMAP KEY ITERATION
BUFFER SORT
TABLE ACCESS FULL TIMES
BITMAP INDEX RANGE SCAN SALES_TIMES_BX
'...

TABLE ACCESS FULL CHANNELS


TABLE ACCESS FULL TIMES

Note
It is supposed that SALES is not partitioned.
In the previous execution plan, you notice that each dimension table is accessed twice
once during the first phase, where the system determines the necessary fact table rows.
And once when joining the fact rows to each dimension table during the second phase.
This might be a performance issue if the dimension tables are big and there is no fast
access path to them for solving the problem.
In such cases, the system might decide to create temporary tables containing information
needed for both phases. This decision is made if the costs for creating a temporary table,
consisting of the result set for both the predicate and the join columns on the dimension
table, is cheaper than accessing the dimension table twice. In the previous execution plan
example, the TIMES and CHANNELS tables are very small, and accessing them using a
full table scan is not a big deal.

Code
SORT GROUP BY
HASH JOIN
HASH JOIN
TABLE ACCESS BY INDEX ROWID SALES
BITMAP CONVERSION TO ROWIDS
BITMAP AND
BITMAP MERGE
BITMAP KEY ITERATION
BUFFER SORT
TABLE ACCESS FULL CHANNELS
BITMAP INDEX RANGE SCAN SALES_CHANNELS_BX
BITMAP MERGE
BITMAP KEY ITERATION
BUFFER SORT
TABLE ACCESS FULL TIMES
BITMAP INDEX RANGE SCAN SALES_TIMES_BX
'...
TABLE ACCESS FULL CHANNELS
TABLE ACCESS FULL TIMES
The creation of these temporary tables and the data insertion are shown in this execution
plan.

The plan contains an extract from a plan using temporary tables for the CUSTOMERS
table. The name of those temporary tables is system-generated and varies.

Code
LOAD AS SELECT
SYS_TEMP_0FD9D6720_BEBDC
TABLE ACCESS FULL
CUSTOMERS
'...
filter("C"."CUST_STATE_PROVINCE"='CA')
In addition, temporary tables are not used by star transformation under two conditions:

the database is in the read-only mode and

the star query is part of a transaction that is in the serializable mode


The volume of data that must be joined can be reduced if the join indexes used as joins
have already been precalculated.
In addition, the join indexes, which contain multiple dimension tables, can eliminate
bitwise operations, which are necessary in the star transformation with existing bitmap
indexes.
Finally, bitmap join indexes are much more efficient in storage than materialized join
views or MJVs, which do not compress rowids of the fact tables. Assume that you have
created the additional index structure.

Code
CREATE BITMAP INDEX sales_q_bjx
ON sales(times.calendar_quarter_desc)
FROM sales, times
WHERE sales.time_id = times.time_id
The processing of the same star query using the bitmap join index is similar to the
previous example. The only difference is that the system uses the join index instead of a
single-table bitmap index to access the times data in the first phase of the star query.
The difference between this plan as compared to the previous one is that the inner part of
the bitmap index scan for the times dimension has no subselect in the rewritten query for
phase 1. This is because the join predicate information on
TIMES.CALENDAR_QUARTER_DESC can be satisfied with the SALES_Q_BJX bitmap join
index.

Note that access to the join index is done twice because the corresponding query's
predicate is t.calendar_quarter_desc IN ('1999-Q1','1999-Q2').

Code
SORT GROUP BY
HASH JOIN
HASH JOIN
TABLE ACCESS BY INDEX ROWID SALES
BITMAP CONVERSION TO ROWIDS
BITMAP AND
BITMAP MERGE
BITMAP KEY ITERATION
BUFFER SORT
TABLE ACCESS FULL CHANNELS
BITMAP INDEX RANGE SCAN SALES_CHANNELS_BX
BITMAP OR
BITMAP INDEX SINGLE VALUE SALES_Q_BJX
BITMAP INDEX SINGLE VALUE SALES_Q_BJX
TABLE ACCESS FULL CHANNELS
TABLE ACCESS FULL TIMES
The types of hints available for a star transformation are
STAR_TRANSFORMATION
The STAR_TRANSFORMATION hint makes the optimizer use the best plan in which the
transformation has been used. Without the hint, the optimizer could make a cost-based
decision to use the best plan generated without the transformation, instead of the best plan
for the transformed query.
Even if the hint is given, there is no guarantee that the transformation takes place. The
optimizer only generates the subqueries if it seems reasonable to do so. If no subqueries
are generated, there is no transformed query, and the best plan for the untransformed
query is used, regardless of the hint.
FACT, and
The FACT hint is used in the context of the star transformation to indicate to the
transformation that the hinted table should be considered as a fact table and all other
tables regardless of their size are considered as dimensions.
The FACT hint might be useful only in case there are more than one fact tables accessed
in the star query.
NO_FACT

The NO_FACT hint is used in the context of the star transformation to indicate to the
transformation that the hinted table should not be considered as a fact table.
The NO_FACT hint might be useful only in case there are more than one fact tables
accessed in the star query.

Question
Identify the statements that accurately describe star transformation hints.
Options:
1.

The FACT hint indicates that the hinted table should be considered as a fact table

2.

The NO_FACT hint indicates that the hinted table should not be considered as a fact
table

3.

The STAR_TRANSFORMATION hint might only be useful when there are multiple fact
tables accessed in a star query

4.

The use of the STAR_TRANSFORMATION hint forces the transformation to take place

Answer
Option 1: Correct. The FACT hint is used in the context of the star transformation
to indicate to the transformation that the hinted table should be considered as a
fact table and all other tables regardless of their size are considered as
dimensions.
Option 2: Correct. The NO_FACT hint is used in the context of the star
transformation to indicate to the transformation that the hinted table should not be
considered as a fact table.
Option 3: Incorrect. The FACT and NO_FACT hints might be useful only in case
there are more than one fact table accessed in the star query.
Option 4: Incorrect. The STAR_TRANSFORMATION hint makes the optimizer use
the best plan in which the transformation has been used. Even if the hint is given,
there is no guarantee that the transformation takes place. The optimizer only
generates the subqueries if it seems reasonable to do so.
Correct answer(s):
1. The FACT hint indicates that the hinted table should be considered as a fact
table
2. The NO_FACT hint indicates that the hinted table should not be considered as a
fact table

In the four examples of the bitmap join indexes, F represents the fact table, D the
dimension table, PK a primary key, and FK a foreign key. The examples include
Bitmap Join Indexes: Join Model 1
A bitmap join index can be used in the SELECT statement in the first join model to avoid
the join operation. Similar to the materialized join view, a bitmap join index precomputes
the join and stores it as a database object. The difference is that a materialized join view
materializes the join into a table while a bitmap join index materializes the join into a
bitmap index.
C1 is the indexed column in the dimension table.
In the first join model of bitmap join indexes, the dimension table contains one index
column, c1 and a primary key column, pk. This is connected to the fact table that contains
only a foreign key column, fk.
The query using the bitmap join index is the following:
CREATE BITMAP INDEX bji ON f(d.c1)
FROM f, d
WHERE d.pk = f.fk;
And the select query is the following:
SELECT sum(f.facts)
FROM d, f
WHERE d.pk = f.fk AND d.c1 = 1;
Bitmap Join Indexes: Join Model 2
The second model is an extension of model 1, requiring a concatenated bitmap join index
to represent it.
Note that BJX, in this case, can also be used to answer the second select statement
without the portion after the second AND. This is due to the fact that D.C1 is the leading
part of the BJX.
In the second join model of bitmap join indexes, the dimension table contains two index
columns, c1 and c2, and a primary key column, pk. This table is connected to the fact
table that contains a foreign key column, fk.
The query using the concatenated bitmap join index is the following:
CREATE BITMAP INDEX bjx ON f(d.c1,d.c2)
FROM f, d
WHERE d.pk = f.fk;
And the select query is the following:
SELECT sum(f.facts)

FROM d, f
WHERE d.pk = f.fk AND d.c1 = 1 AND d.c2 = 1;
Bitmap Join Indexes: Join Model 3, and
The third model also requires the concatenated bitmap join index. In this case, two
dimension tables are used.
In the third join model of bitmap join indexes, there are two dimension tables d1 and d2,
and a fact table. d1 contains one index column, c1. Both d1 and d2 a primary key column,
pk each. The fact table contains two foreign key columns, fk1 and fk2. d1 is connected to
the fact table, which in turn is connected to d2. d1 and d2 are not directly connected to
each other.
The query using the concatenated bitmap join index is the following:
CREATE BITMAP INDEX bjx ON f(d1.c1,d2.c1)
FROM f, d1, d2
WHERE d1.pk = f.fk1 AND d2.pk = f.fk2;
And the select query is the following:
SELECT sum(f.sales)
FROM d1, f, d2
WHERE d1.pk = f.fk1 AND d2.pk = f.fk2 AND
d1.c1 = 1 AND d2.c1 = 2;
Bitmap Join Indexes: Join Model 4
The snowflake model, which is the fourth model, involves joins between two or more
dimension tables. It can be expressed by a bitmap join index.
The bitmap join index can be either single or concatenated depending on the number of
columns in the dimension tables to be indexed.
A bitmap join index on D1.C1 with a join between D1 and D2 and a join between D2 and F
can be created with BJX.
In the fourth join model of bitmap join indexes, there are two dimension tables, d1 and d2,
and a fact table. d1 and d2 both contain an index column, c1 and c2, and a primary key
column, pk. The fact table contains only a foreign key column fk. d1 and d2 are connected
to each other. And d2 is connected to the fact table.
The query using the concatenated bitmap join index is the following:
CREATE BITMAP INDEX bjx ON f(d1.c1)
FROM f, d1, d2
WHERE d1.pk = d2.c2 AND d2.pk = f.fk;
And the select query is the following:

SELECT sum(f.sales)
FROM d1, d2, f
WHERE d1.pk = d2.c2 AND d2.pk = f.fk AND
d1.c1 = 1;

Summary
You can use a simple star schema to connect a large fact table with smaller dimension or
lookup tables. Queries from these tables, called star queries, often join the fact and one
or more dimension tables using primary and foreign keys.
Although you can execute queries without a star transformation, doing so results in a
large number of rows. To use the star transformation execution strategy, foreign keys of
fact or other tables should have a bitmap index. The STAR_TRANSFORMATION_ENABLED
initialization parameter should be set to TRUE.
The first phase of star transformation execution uses bitmap indexes to retrieve result
sets, and the second phase joins result sets to dimension tables. To avoid performance
issues caused by large dimension tables, use temporary tables that contain information
for both phases.

Table of Contents
| Top of page |
| Learning Objective |
| 1.Star schema and star transformation |
| 2.Queries in star transformation |
| Summary |
Copyright 2009 SkillSoft. All rights reserved.
SkillSoft and the SkillSoft logo are trademarks or registered trademarks of SkillSoft in the United States and certain other countries.
All other logos or trademarks are the property of their respective owners.

| Print | Contents | Close |

Star Schema Tuning


Learning Objective

After completing this topic, you should be able to

use star transformation and access the benefits of using this optimizer technique

Exercise overview
You have written a query that queries the CUSTOMERS, SALES, TIMES, and
CHANNELS tables and returns the CHANNEL_CLASS, CUST_CITY, CALENDAR, and
SALES_AMOUNT columns based on a number of WHERE conditions and joins. You
have saved the query to a script called "sales query." You want to optimize the query to
use star transformation and make further use of the benefits of this technique.
In this exercise, you're required to optimize a query to use star transformation.
This involves the following tasks:

viewing optimizer results

using star transformation

enhancing optimization

eliminating table access

querying PLAN_TABLE

Task 1: Viewing optimizer results


You want to execute a saved query and examine the optimizer results. Before executing
the query, flush the buffer cache and the shared pool respectively to avoid caching issues
as much as possible. Then execute the "sales_query" script using the @ command. Type
each command using one line only.

Steps list
Instructions
1. Type ALTER SYSTEM FLUSH BUFFER_CACHE; and press Enter
2. Type ALTER SYSTEM FLUSH SHARED_POOL; and press Enter
3. Type @sales_query and press Enter

Task 2: Using star transformation


After viewing the output of the execution plan for your saved query, you have noticed that
the query seems to use a large number of bytes to access the SALES table. Without
modifying the SH schema, you want to improve the execution plan for your query. You
have flushed the buffer cache and the shared pool again. Enable star transformation for

your session. Do not use a temporary table for the star transformation. Then execute the
"sales_query" script using the @ command. Type each command using one line only.

Steps list
Instructions
1. Type ALTER SESSION SET star_transformation_enabled = temp_disable; and press Enter
2. Type @sales_query and press Enter

Task 3: Enhancing optimization


You want to further enhance the previous optimization without changing the SH schema.
You decide to let the optimizer decide if it is better to use a temporary table. You have
already flushed the buffer cache and shared pool again. Enable star transformation for
your session. Then execute the "sales_query" script using the @ command. Type each
command using one line only.

Steps list
Instructions
1. Type ALTER SESSION SET star_transformation_enabled = true; and press Enter
2. Type @sales_query and press Enter

Task 4: Eliminating table access


You want to eliminate one table access on the CUSTOMERS table from the previous
execution plan for your saved query. You decide to create a bitmap join index between
the SALES and CUSTOMERS tables and save the statement as a script called
"create_bji." You execute the script and the ORA-25954 error is returned, specifying that
there is a missing primary key or unique constraint on a dimension. Alter the
CUSTOMERS table to enable the CUSTOMERS_PK constraint. Then execute the
"create_bji" script using the @ command. Type each command using one line only.

Steps list
Instructions
1. Type ALTER TABLE customers ENABLE CONSTRAINT customers_pk; and press Enter
2. Type @create_bji and press Enter

Task 5: Querying PLAN_TABLE


You want to verify that you eliminated one table access from the CUSTOMERS table from
the previous execution plan. You also want to determine how the system could

dynamically determine which SALES partitions to access for your "sales_query" query.
You have already flushed the buffer cache and shared pool. Execute the "sales_query"
and "dynamic_partition_pruning" scripts respectively using the @ command. Then view
the OTHER column of PLAN_TABLE table for the PARTITION RANGE operation. Type
each command using one line only.

Steps list
Instructions
1. Type @sales_query and press Enter
2. Type @dynamic_partition_pruning and press Enter
3. Type SELECT other FROM plan_table WHERE operation = 'PARTITION RANGE'; and press Enter

Table of Contents
| Top of page |
| Learning Objective |
| Exercise overview |
| Task 1: Viewing optimizer results |
| Task 2: Using star transformation |
| Task 3: Enhancing optimization |
| Task 4: Eliminating table access |
| Task 5: Querying PLAN_TABLE |
Copyright 2009 SkillSoft. All rights reserved.
SkillSoft and the SkillSoft logo are trademarks or registered trademarks of SkillSoft in the United States and certain other countries.
All other logos or trademarks are the property of their respective owners.

Вам также может понравиться