Ven ORA Query Optimization Notes
Ven ORA Query Optimization Notes
CONTENTS
Introduction........................................................................................................................5
Optimizer Operations........................................................................................................6
Evaluation of Expressions and Conditions..................................................................6
Transforming and Optimizing Statements..................................................................9
Optimizer Modes.............................................................................................................11
Cost-Based Optimization............................................................................................11
Rule-Base Optimization..............................................................................................11
Choosing an Optimization Mode................................................................................11
Examine RULE-Based versus COST-Based Optimization......................................12
Choosing Access Paths....................................................................................................14
Explanation of the Access Paths.................................................................................15
Path 1: Single Row by Rowid.................................................................................15
Path 2: Single Row by Cluster Join........................................................................15
Path 3: Single Row by Hash Cluster Key with Unique or Primary Key............16
Path 4: Single Row by Unique or Primary Key....................................................17
Path 5: Clustered Join.............................................................................................17
Path 6: Hash Cluster Key........................................................................................18
Path 7: Indexed Cluster Key...................................................................................18
Path 8: Composite Index.........................................................................................19
Path 9: Single-Column Indexes..............................................................................20
Path 10: Bounded Range Search on Indexed Columns........................................21
Path 11: Unbounded Range Search on Indexed Columns...................................22
Path 12: Sort-Merge Join........................................................................................22
Path 13: MAX or MIN of Indexed Column...........................................................23
Path 14: ORDER BY on Indexed Column............................................................24
Path 15: Full Table Scan.........................................................................................25
Choosing Among Access Paths...................................................................................25
Choosing an Access Path with the Cost-Based Optimization Mode...................25
Choosing an Access Path with the Rule-Based Optimization Mode...................26
Access Methods................................................................................................................28
Ways of Table Access..................................................................................................28
Table Access Full.....................................................................................................28
Table Access By ROWID........................................................................................28
Ways of index access....................................................................................................28
Index Unique Scan...................................................................................................28
Index Range Scan....................................................................................................28
Cluster Scans................................................................................................................29
Hash Scans....................................................................................................................29
Optimizing Join Statements............................................................................................29
Sort-Merge Join..........................................................................................................29
Nested Loops................................................................................................................30
Hash Join......................................................................................................................30
Cluster Join..................................................................................................................30
Tips on Optimization :.....................................................................................................31
How does ORACLE make use of an Index...............................................................31
How does ORACLE make use of multiple Indexes..................................................32
Ensure the Leading Column of a Concatenated Index is used................................32
When to avoid use of Indexes.....................................................................................34
Beware of Index Suppression....................................................................................34
Beware of Oracle internal suppression......................................................................36
Avoid using inequalities along with an indexed column..........................................37
If the MAX or MIN function is Used........................................................................37
Improve Subquery Execution.....................................................................................38
Force the Driving Table..............................................................................................39
Joining three or more tables.......................................................................................40
Equality and range predicates....................................................................................41
No clear ranking winner.............................................................................................41
Automatic index suppression......................................................................................42
Reducing the Number of Trips to the Database.......................................................42
Using DECODE to reduce processing........................................................................43
Using WHERE in place of HAVING.........................................................................44
Consider Table Joins in place of EXISTS.................................................................44
Hinting for a better plan.................................................................................................45
Examining Hint Syntax...............................................................................................45
Understanding the Available Hints............................................................................46
Explanation of some the hints...................................................................................47
INDEX Hint..............................................................................................................48
INDEX_ASC Hint....................................................................................................48
INDEX_DESC Hint.................................................................................................49
FULL Hint................................................................................................................50
ROWID Hint............................................................................................................50
FIRST_ROWS Hint.................................................................................................50
ALL_ROWS Hint....................................................................................................51
CHOOSE Hint.........................................................................................................51
RULE Hint...............................................................................................................52
AND_EQUAL Hint.................................................................................................52
APPENDIX A...................................................................................................................53
Using the Explain Plan Feature..................................................................................53
Showing the execution plan for a query....................................................................53
Execution Plan Operations.........................................................................................55
APPENDIX B...................................................................................................................57
Using SQL Trace and TKPROF................................................................................57
Taking care of prerequisites.......................................................................................57
Checking Initialization Parameters...........................................................................57
Finding Your Trace Files............................................................................................58
Enabling the SQL Trace feature................................................................................59
Enabling SQL Trace for Your Session......................................................................59
Enabling SQL Trace for Another Session.................................................................59
Enabling SQL Trace for All Sessions.........................................................................60
Using the TKPROF command....................................................................................61
Using TKPROF Syntax...............................................................................................61
Executing TKPROF.....................................................................................................62
Explaining Plans..........................................................................................................63
Interpreting TKPROF’s output.................................................................................63
APPENDIX C...................................................................................................................66
Using SQL*Plus Autotrace.........................................................................................66
Introduction
Optimization is the process of choosing the most efficient way to execute a SQL
statement. This is an important step in the processing of any data manipulation language
(DML) statement: SELECT, INSERT, UPDATE, or DELETE. Many different ways to
execute a SQL statement often exist, for example, by varying the order in which tables or
indexes are accessed. The procedure Oracle uses to execute a statement can greatly affect
how quickly the statement executes.
A part of the Oracle kernel, the optimizer examines each SQL statement it encounters in
your application and chooses the optimal execution plan, or access path for the statement.
Execution Plan are sequence of physical steps the RDBMS must take to perform the
operation (e.g. retrieval, update) that you have specified.
While querying the database, you should be aware of the operations Oracle performs to
retrieve and manipulate the data. The better you understand the execution path, the better
you will be able to manipulate and tune the query.
You can discover the execution plan for a statement in at least three ways. One is to issue
an EXPLAIN PLAN statement from SQL*Plus. Another alternative is to use the
SQL*Plus autotrace feature, and still another alternative is to use Oracle’s SQL Trace
feature.
Oracle bases the execution of every SQL statement on an execution plan. An execution
plan is created internally by Oracle during the SQL statement parsing process. The
execution plan tells Oracle what path to follow to process a SQL statement to return the
requested result set. Oracle’s optimizer determines the execution plan based on the
manner in which the SQL statement is written and varies based on the optimizer mode
used.
Optimizer Operations
For any SQL statement processed by Oracle, the optimizer does the following:
The following sections discuss how the optimizer evaluates expressions and conditions
that contain:
Constants
Computation of constants is performed only once, when the statement is
optimized, rather than each time the statement is executed.
Consider these conditions that test for monthly salaries greater than 2000:
If a SQL statement contains the first condition, the optimizer simplifies it into the
second condition.
Note that the optimizer does not simplify expressions across comparison
operators. In the examples above, the optimizer does not simplify the third
expression into the second. For this reason, application developers should write
conditions that compare columns with constants whenever possible, rather than
conditions with expressions involving columns.
LIKE Operator
The optimizer simplifies conditions that use the LIKE comparison operator to
compare an expression with no wildcard characters into an equivalent condition
that uses an equality operator instead. For example, the optimizer simplifies the
first condition below into the second.
ename LIKE 'SMITH'
ename = 'SMITH'
IN Operator
The optimizer expands a condition that uses the IN comparison operator to and
equivalent condition that uses equality comparison operators and OR logical
operators.
For example, the optimizer expands the first condition below into the second:
ANY Operator
The optimizer expands a condition that uses the ANY comparison operator
followed by a parenthesized list of values into an equivalent condition that uses
equality comparison operators and OR logical operators.
For example, the optimizer expands the first condition below into the second.
ALL Operator
The optimizer expands a condition that uses the ALL comparison operator
followed by a parenthesized list of values into an equivalent condition that uses
equality comparison operators and AND logical operators.
For example, the optimizer expands the first condition below into the second:
BETWEEN Operator
The optimizer always replaces a condition that uses the BETWEEN comparison
operator with an equivalent condition that uses the >= and <= comparison
operators.
For example, the optimizer replaces the first condition below with the second:
Transitivity
If two conditions in the WHERE clause involve a common column, the optimizer
can sometimes infer a third condition using the transitivity principle. The
optimizer can then use the inferred condition to optimize the statement. The
inferred condition could potentially make available an index access path that was
not made available by the original conditions.
where:
comp_oper is any of the comparison operators =, !=, ^=, <, <>, >, <=, or >=.
Consider this query in which the WHERE clause contains two conditions, each or
which uses the [Link] column:
SELECT *
FROM emp, dept
WHERE [Link] = 20
AND [Link] = [Link];
[Link] = 20
If an index exists on the [Link] column, this condition makes available
access paths using that index.
SQL is a very flexible query language; there are often many statements you could
formulate to achieve the same goal. Sometimes the optimizer transforms one such
statement into another that achieves the same goal if the second statement can be
executed more efficiently.
Transform the complex statement into an equivalent join statement and then
optimize the join statement.
Optimize the complex statement as is.
The optimizer transforms a complex statement into a join statement whenever the
resulting join statement is guaranteed to return exactly the same rows as the
complex statement.
Consider this complex statement that selects all rows from the ACCOUNTS table
whose owners appear in the CUSTOMERS table:
SELECT *
FROM accounts
WHERE custno IN
(SELECT custno FROM customers);
SELECT accounts.*
FROM accounts, customers
WHERE [Link] = [Link];
Consider this query that accesses the view. The query selects the IDs greater than
7800 of employees who work in department 10:
SELECT empno
FROM emp_10
WHERE empno > 7800;
The optimizer transforms the query into the following query that accesses the
view's base table:
SELECT empno
FROM emp
WHERE deptno = 10
AND empno > 7800;
If there are indexes on the DEPTNO or EMPNO columns, the resulting WHERE
clause makes them available.
Optimizer Modes
Cost-based
Rule-based
Cost-Based Optimization
Using the cost-based optimization mode, the optimizer determines which execution plan
is most efficient by considering available access paths and factoring in information based
on statistics for the schema objects (tables or indexes) accessed by the SQL statement.
The cost-based optimization mode also considers hints, which are optimization
suggestions placed in a comment in the statement.
The optimizer generates a set of potential execution plans for the SQL statement
based on its available access paths and hints.
The optimizer estimates the cost of each execution plan based on statistics in the
data dictionary for the data distribution and storage characteristics of the tables,
indexes, and partitions accessed by the statement. The statistics can be available
once the table has been analyzed via the ANALYZE command. The cost is an
estimated value proportional to the expected resource use needed to execute the
statement with a particular execution plan. The optimizer calculates the cost of
each possible access method and join order based on the estimated computer
resources, including I/O, CPU time, and memory, that are required to execute the
statement using the plan.
The optimizer compares the costs of the execution plans and chooses the one with
the smallest cost.
Rule-Base Optimization
Using the rule-based mode, the optimizer chooses an execution plan based on the access
paths available and the ranks of these access paths (shown in Table 1).
CHOOSE
The optimizer chooses between a cost-based optimization mode and a rule-based
optimization mode based on whether statistics are available for the cost-based
optimization mode. If the data dictionary contains statistics for at least one of the
accessed tables, the optimizer uses a cost-based optimization mode and optimizes
with a goal of best throughput. If the data dictionary contains no statistics for any
of the accessed tables, the optimizer uses a rule-based optimization mode.
ALL_ROWS
The optimizer uses a cost-based optimization mode for all SQL statements in the
session regardless of the presence of statistics and optimizes with a goal of best
throughput (minimum resource use to complete the entire statement).
FIRST_ROWS
The optimizer uses a cost-based optimization mode for all SQL statements in the
session regardless of the presence of statistics and optimizes with a goal of best
response time (minimum resource use to return the first row of the result set).
RULE
The optimizer chooses a rule-based optimization mode for all SQL statements
issued to the Oracle instance regardless of the presence of statistics.
SELECT name,value
FROM v$parameter
WHERE name='optimizer_mode';
NAME VALUE
--------------- ---------------
Optimizer_mode CHOOSE
The following is an example which displays the difference in optimizer mode execution
plan.
Example 1.
The breakdown of the deptid values for the records in s_employee table are shown below.
An index exists on the deptid column.
Oracle uses rule-based optimizer as the s_employee table has not been analyzed.
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE
1 0 TABLE ACCESS (BY INDEX ROWID) OF 'S_EMPLOYEE'
2 1 INDEX (RANGE SCAN) OF 'S_EMP_DEPTID' (NON-UNIQUE)
Example 2.
In the following example Oracle uses cost-based optimization as the s_employee table
has been analyzed using
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=1 Card=9 Bytes=126)
1 0 TABLE ACCESS (FULL) OF 'S_EMPLOYEE' (Cost=1 Card=9 Bytes=1
26)
The cost-based optimization logs the statistical information in the data dictionary when
the objects are analyzed. It decided to pass on using the index and perform a full table
scan as the deptid of 10 comprised 40 percent of the data.
One of the most important choices the optimizer makes when formulating an execution
plan is how to retrieve data from the database. For any row in any table accessed by a
SQL statement, there may be many access paths by which that row can be located and
retrieved. The optimizer chooses one of them.
Rank Path
1 Single Row by Rowid
2 Single Row by Cluster Join
3 Single Row by Hash Cluster Key with Unique or Primary Key
4 Single Row by Unique or Primary Key
5 Clustered Join
6 Hash Cluster Key
7 Indexed Cluster Key
8 Composite index
9 Single-Column Indexes
10 Bounded Range Search on Indexed Columns
11 Unbounded Range Search on Indexed Columns
12 Sort merge join
13 MAX or MIN of Indexed Column
14 ORDER BY on Indexed Column
15 Full tables scans
Explanation of the Access Paths
This access path is available only if the statements WHERE clause identifies the selected
rows by rowid
SELECT *
FROM DEPT
WHERE ROWID = 'AAACqoAACAAAAD9AAA';
The Execution Plan for this statement might look like this:
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE
1 0 TABLE ACCESS (BY USER ROWID) OF 'DEPT'
This access path is available for statements that join tables stored in the same cluster if
both of these conditions are true:
The statement's WHERE clause contains conditions that equate each column of
the cluster key in one table with the corresponding column in the other table.
The statement's WHERE clause also contains a condition that guarantees that the
join returns only one row. Such a condition is likely to be an equality condition on
the column(s) of a unique or primary key.
This access path is available for the following statement in which the EMP and DEPT
tables are clustered on the DEPTNO column and the EMPNO column is the primary key
of the EMP table:
SELECT *
FROM EMP, dept
WHERE [Link] = [Link]
AND [Link] = 7900;
The Execution Plan for this statement might look like this:
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE
1 0 NESTED LOOPS
2 1 TABLE ACCESS (BY INDEX ROWID) OF 'EMP'
3 2 INDEX (UNIQUE SCAN) OF ‘PK_EMP' (UNIQUE)
4 1 TABLE ACCESS (CLUSTER) OF 'DEPT'
Path 3: Single Row by Hash Cluster Key with Unique or Primary Key
The statement's WHERE clause uses all columns of a hash cluster key in equality
conditions. For composite cluster keys, the equality conditions must be combined
with AND operators.
The statement is guaranteed to return only one row because the columns that
make up the hash cluster key also make up a unique or primary key.
To execute the statement, Oracle applies the cluster's hash function to the hash cluster
key value specified in the statement to obtain a hash value. Oracle then uses the hash
value to perform a hash scan on the table.
This access path is available in the following statement in which the ORDERS and
LINE_ITEMS tables are stored in a hash cluster, and the ORDERNO column is both the
cluster key and the primary key of the ORDERS table:
SELECT *
FROM orders
WHERE orderno = 65118968;
The Execution Plan for this statement might look like this:
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE
1 0 TABLE ACCESS (HASH) OF 'ORDERS'
This access path is available if the statement's WHERE clause uses all columns of a
unique or primary key in equality conditions. For composite keys, the equality conditions
must be combined with AND operators. To execute the statement, Oracle performs a
unique scan on the index or the unique or primary key to retrieve a single rowid and then
accesses the table by that rowid.
This access path is available in the following statement in which the EMPNO column is
the primary key of the EMP table:
SELECT *
FROM EMP
WHERE empno = 7900;
The Execution Plan for this statement might look like this:
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE
1 0 TABLE ACCESS (BY INDEX ROWID) OF 'EMP'
2 1 INDEX (UNIQUE SCAN) OF 'PK_EMP' (UNIQUE)
PK_EMP is the name of the index that enforces the primary key.
This access path is available for statements that join tables stored in the same cluster if
the statement's WHERE clause contains conditions that equate each column of the cluster
key in one table with the corresponding column in the other table. For a composite cluster
key, the equality conditions must be combined with AND operators. To execute the
statement, Oracle performs a nested loops operation.
This access path is available in the following statement in which the EMP and DEPT
tables are clustered on the DEPTNO column:
SELECT *
FROM emp, dept
WHERE [Link] = [Link];
The Execution Plan for this statement might look like this:
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE
1 0 NESTED LOOPS
2 1 TABLE ACCESS (FULL) OF 'DEPT'
3 1 TABLE ACCESS (CLUSTER) OF 'EMP'
This access path is available if the statement's WHERE clause uses all the columns of a
hash cluster key in equality conditions. For a composite cluster key, the equality
conditions must be combined with AND operators. To execute the statement, Oracle
applies the cluster's hash function to the hash cluster key value specified in the statement
to obtain a hash value. Oracle then uses this hash value to perform a hash scan on the
table.
This access path is available for the following statement in which the ORDERS and
LINE_ITEMS tables are stored in a hash cluster and the ORDERNO column is the
cluster key:
SELECT *
FROM line_items
WHERE orderno = 65118968;
The Execution Plan for this statement might look like this:
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE
1 0 TABLE ACCESS (HASH) OF 'LINE_ITEMS'
This access path is available if the statement's WHERE clause uses all the columns of an
indexed cluster key in equality conditions. For a composite cluster key, the equality
conditions must be combined with AND operators. To execute the statement, Oracle
performs a unique scan on the cluster index to retrieve the rowid of one row with the
specified cluster key value. Oracle then uses that rowid to access the table with a cluster
scan. Since all rows with the same cluster key value are stored together, the cluster scan
requires only a single rowid to find them all.
This access path is available in the following statement in which the EMP table is stored
in an indexed cluster and the DEPTNO column is the cluster key:
The Execution Plan for this statement might look like this:
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE
1 0 TABLE ACCESS (CLUSTER) OF 'EMP'
2 1 INDEX (UNIQUE SCAN) OF 'EMP_DEPT_CLUSTER_INDEX'
This access path is available if the statement's WHERE clause uses all columns of a
composite index in equality conditions combined with AND operators. To execute the
statement, Oracle performs a range scan on the index to retrieve rowids of the selected
rows and then accesses the table by those rowids.
This access path is available in the following statement in which there is a composite
index on the JOB and DEPTNO columns:
SELECT *
FROM emp
WHERE job = 'CLERK'
AND deptno = 30;
The Execution Plan output for this statement might look like this:
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE
1 0 TABLE ACCESS (BY INDEX ROWID) OF 'EMP'
2 1 INDEX (RANGE SCAN) OF ' JOB_DEPTNO_INDEX ' (NON-UNIQUE)
JOB_DEPTNO_INDEX is the name of the composite index on the JOB and DEPTNO
columns.
This access path is available if the statement's WHERE clause uses the columns of one or
more single-column indexes in equality conditions. For multiple single-column indexes,
the conditions must be combined with AND operators. If the WHERE clause uses the
column of only one index, Oracle executes the statement by performing a range scan on
the index to retrieve the rowids of the selected rows and then accessing the table by these
rowids.
This access path is available in the following statement in which there is an index on the
JOB column of the EMP table:
SELECT *
FROM emp
WHERE job = 'ANALYST';
The Execution Plan for this statement might look like this:
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE
1 0 TABLE ACCESS (BY INDEX ROWID) OF 'S_EMPLOYEE'
2 1 INDEX (RANGE SCAN) OF ' JOB_INDEX ' (NON-UNIQUE)
If the WHERE clauses uses columns of many single-column indexes, Oracle executes the
statement by performing a range scan on each index to retrieve the rowids of the rows
that satisfy each condition. Oracle then merges the sets of rowids to obtain a set of rowids
of rows that satisfy all conditions. Oracle then accesses the table using these rowids.
Oracle can merge up to five indexes. If the WHERE clause uses columns of more than
five single-column indexes, Oracle merges five of them, accesses the table by rowid, and
then tests the resulting rows to determine whether they satisfy the
remaining conditions before returning them.
This access path is available if the statement's WHERE clause contains a condition that
uses either the column of a single-column index or one or more columns that make up a
leading portion of a composite index:
column = expr
Each of these conditions specifies a bounded range of indexed values that are accessed by
the statement. The range is said to be bounded because the conditions specify both its
least value and its greatest value. To execute such a statement, Oracle performs a range
scan on the index and then accesses the table by rowid.
This access path is available in this statement in which there is an index on the SAL
column of the EMP table:
SELECT *
FROM emp
WHERE sal BETWEEN 2000 AND 3000;
The Execution Plan for this statement might look like this:
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE
1 0 TABLE ACCESS (BY INDEX ROWID) OF 'EMP'
2 1 INDEX (RANGE SCAN) OF 'SAL_IDX' (NON-UNIQUE)
This access path is available if the statement's WHERE clause contains one of these
conditions that use either the column of a single-column index or one or more columns of
a leading portion of a composite index:
Each of these conditions specifies an unbounded range of index values accessed by the
statement. The range is said to be unbounded because the condition specifies either its
least value or its greatest value, but not both. To execute such a statement, Oracle
performs a range scan on the index and then accesses the table by rowid.
This access path is available in the following statement in which there is an index on the
SAL column of the EMP table:
SELECT *
FROM emp
WHERE sal > 2000;
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE
1 0 TABLE ACCESS (BY INDEX ROWID) OF 'EMP'
2 1 INDEX (RANGE SCAN) OF 'SAL_IDX' (NON-UNIQUE)
This access path is available for statements that join tables that are not stored together in
a cluster if the statement's WHERE clause uses columns from each table in equality
conditions. To execute such a statement, Oracle uses a sort-merge operation. Oracle can
also use a nested loops operation to execute a join statement.
This access path is available for the following statement in which the EMP and DEPT
tables are not stored in the same cluster:
SELECT *
FROM emp, dept
WHERE [Link] = [Link];
The Execution Plan for this statement might look like this:
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE
1 0 MERGE JOIN
2 1 SORT (JOIN)
3 2 TABLE ACCESS (FULL) OF ' EMP '
4 1 SORT (JOIN)
5 4 TABLE ACCESS (FULL) OF ' DEPT '
This access path is available for a SELECT statement for which all of these conditions
are true:
The query uses the MAX or MIN function to select the maximum or minimum
value of either the column of a single-column index or the leading column of a
composite index.
There are no other expressions in the select list.
The statement has no WHERE clause or GROUP BY clause.
To execute the query, Oracle performs a range scan of the index to find the maximum or
minimum indexed value. Since only this value is selected, Oracle need not access the
table after scanning the index.
This access path is available for the following statement in which there is an index on the
SAL column of the EMP table:
The Execution Plan for this statement might look like this:
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE
1 0 SORT (AGGREGATE)
2 1 INDEX (FULL SCAN (MIN/MAX)) OF 'SAL_IDX' (NON-UNIQUE)
Path 14: ORDER BY on Indexed Column
This access path is available for a SELECT statement for which all of these conditions
are true:
The query contains an ORDER BY clause that uses either the column of a single-
column index or a leading portion of a composite index. The index cannot be a
cluster index.
There must be a PRIMARY KEY or NOT NULL integrity constraint that
guarantees that at least one of the indexed columns listed in the ORDER BY
clause contains no nulls.
To execute the query, Oracle performs a range scan of the index to retrieve the rowids of
the selected rows in sorted order. Oracle then accesses the table by these rowids.
This access path is available for the following statement in which there is a primary key
on the EMPNO column of the EMP table:
SELECT *
FROM emp
ORDER BY empno;
The Execution Plan for this statement might look like this:
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE
1 0 TABLE ACCESS (BY INDEX ROWID) OF 'EMP'
2 1 INDEX (FULL SCAN) OF 'PK_EMP' (UNIQUE)
PK_EMP is the name of the index that enforces the primary key. The primary key
ensures that the column does not contain nulls.
Path 15: Full Table Scan
This access path is available for any SQL statement, regardless of its WHERE clause
conditions.
This statement uses a full table scan to access the EMP table:
SELECT *
FROM emp;
The Execution Plan for this statement might look like this:
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE
1 0 TABLE ACCESS (FULL) OF 'EMP'
This section describes how the optimizer chooses among available access paths when
using the cost-based or rule-based optimization mode.
To choose an access path, the optimizer first determines which access paths are available
by examining the conditions in the statement's WHERE clause. The optimizer then
generates a set of possible execution plans using available access paths and estimates the
cost of each plan using the statistics for the index, columns, and tables accessible to the
statement. The optimizer then chooses the execution plan with the lowest estimated cost.
To choose among available access paths, the optimizer considers the Selectivity which is
the percentage of rows in the table that the query selects. A query that selects a small
percentage of a table's rows has good selectivity, while a query that selects a large
percentage of rows has poor selectivity.
The optimizer is more likely to choose an index scan over a full table scan for a query
with good selectivity than for one with poor selectivity. Index scans are usually more
efficient than full table scans for queries that access only a small percentage of a table's
rows, while full table scans are usually faster for queries that access a large percentage.
Consider this query, which uses an equality condition in its WHERE clause to select all
employees named Jackson:
SELECT *
FROM emp
WHERE ename = 'JACKSON';
If the ENAME column is a unique or primary key, the optimizer determines that there is
only one employee named Jackson, and the query returns only one row. In this case, the
query is very selective, and the optimizer is most likely to access the table using a unique
scan on the index that enforces the unique or primary key (access path 4).
With the rule-based optimization mode, the optimizer chooses whether to use an access
path based on these factors:
To choose an access path, the optimizer first examines the conditions in the statement's
WHERE clause to determine which access paths are available. The optimizer then
chooses the most highly ranked available access path.
Note that the full table scan is the lowest ranked access path on the list. This means that
the rule-based optimization mode always chooses an access path that uses an index if one
is available, even if a full table scan might execute faster.
The order of the conditions in the WHERE clause does not normally affect the
optimizer's choice among access paths.
Consider this SQL statement, which selects the employee numbers of all employees in
the EMP table with an ENAME value of 'CHUNG' and with a SAL value greater than
2000.
SELECT empno
FROM emp
WHERE ename = 'CHUNG'
AND sal > 2000;
Consider also that the EMP table has these integrity constraints and indexes:
There is a PRIMARY KEY constraint on the EMPNO column that is enforced by the
index PK_EMPNO. There is an index named ENAME_IND on the ENAME column.
There is an index named SAL_IND on the SAL column.
Based on the conditions in the WHERE clause of the SQL statement, the integrity
constraints, and the indexes, these access paths are available:
Note that the PK_EMPNO index does not make the single row by primary key access
path available because the indexed column does not appear in a condition in the WHERE
clause.
Using the rule-based optimization mode, the optimizer chooses the access path that uses
the ENAME_IND index to execute this statement. The optimizer chooses this path
because it is the most highly ranked path available.
Access Methods
This section describes the basic methods by which Oracle can access data.
Use an index scan over a table scan when accessing less than 5 percent of the rows of a
table.
SELECT *
FROM s_employee
WHERE empid = 1;
SELECT *
FROM s_employee
WHERE LNAME LIKE ‘S%’;
Cluster Scans
From a table stored in an indexed cluster, a cluster scan retrieves rows that have the same
cluster key value. In an indexed cluster, all rows with the same cluster key value are
stored in the same data blocks. To perform a cluster scan, Oracle first obtains the rowid
of one of the selected rows by scanning the cluster index. Oracle then locates the rows
based on this rowid.
Hash Scans
Oracle can use a hash scan to locate rows in a hash cluster based on a hash value. In a
hash cluster, all rows with the same hash value are stored in the same data blocks. To
perform a hash scan, Oracle first obtains the hash value by applying a hash function to a
cluster key value specified by the statement. Oracle then scans the data blocks containing
rows with that hash value.
The optimizer can use the following operations to join two row sources:
Sort-Merge Join
Oracle can only perform a sort-merge join for an equijoin. To perform a sort-merge join,
Oracle follows these steps:
Oracle sorts each row source to be joined . The rows are sorted on the values of
the columns used in the join condition.
Oracle merges the two sources so that each pair of rows, one from each source,
that contain matching values for the columns used in the join condition are
combined and returned as the resulting row source.
To execute Nested Loops join, the optimizer must first select a driving table for the join.
The driving table is the table that will be read first (usually via a TABLE ACCESS FULL
operation). For each record in the driving table, the second table in the join will be
queried. Since an index is available on the deptno column of the emp table , and no
comparable index is available on the dept table, the dept table will be used as the driving
table for the query. During the Nested Loops execution, a TABLE ACCESS FULL
operation will select all the records from the dept table. The index available on the deptno
column of the emp table will be probed to determine if it contains an entry for the value
in the current record from the dept table. If a match is found , then the ROWID for the
matching emp row will be retrieved from the index, and the row will be selected from the
emp table via a TABLE ACCESS BY ROWID operation.
Hash Join
The Hash Join operation compares two tables in memory. During a Hash Join operation,
the first table is scanned via a TABLE ACCESS FULL and the database applies “hashing
” functions to the data to prepare the table for the join. The values from the second table
are then read (also via a TABLE ACCESS FULL operation), and the hashing function is
used to compare the second table with the first table. The rows that result in matches are
returned to the user.
Cluster Join
Oracle can perform a cluster join only for an equijoin that equates the cluster key
columns of two tables in the same cluster. In a cluster, rows from both tables with the
same cluster key values are stored in the same blocks, so Oracle only accesses those
blocks.
SELECT *
FROM emp, dept
WHERE [Link] = [Link];
The outer table (DEPT) is scanned with a full table scan. The [Link] value is
used to find the matching rows in the inner table (EMP) with a cluster scan.
Tips on Optimization :
Example 3.
SELECT order_id,customer_id
FROM s_order
WHERE order_id = 100;
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE
1 0 TABLE ACCESS (BY INDEX ROWID) OF 'S_ORDER'
2 1 INDEX (UNIQUE SCAN) OF 'S_ORDER_ID_PK' (UNIQUE)
A unique index is on the order_id column of the s_order table. We can see that the
s_order table was accessed once the ROWID was retrieved from the index. In the first
line we can see that Optimizer=CHOOSE . CHOOSE means that the method of
optimization used could have been rule-based or cost-based, depending on whether the
s_order table was ever analyzed (if previously analyzed , cost based optimization is used;
otherwise rule-based optimization is used).
Example 4.
SELECT order_id
FROM s_order
WHERE order_id = 100;
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE
1 0 INDEX (UNIQUE SCAN) OF 'S_ORDER_ID_PK' (UNIQUE)
The index has been used to satisfy the search without accessing the database table.
Example 5.
SELECT empid,start_date,title
FROM s_employee
WHERE title = 'CLERK'
AND start_date = '01-JAN-01';
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE
1 0 TABLE ACCESS (BY INDEX ROWID) OF 'S_EMPLOYEE'
2 1 AND-EQUAL
3 2 INDEX (RANGE SCAN) OF 'EMP_IDX2' (NON-UNIQUE)
4 2 INDEX (RANGE SCAN) OF 'EMP_IDX3' (NON-UNIQUE)
The AND-EQUAL operation merges the rowids obtained by the scans of the EMP_IDX2
and the EMP_IDX3, resulting in a set of rowids of rows that satisfy the query.
Oracle can use a concatenated index, but only if the first portion of the index is in the
predicate. In the following example Oracle makes use of the concatenated index
'EMP_IDX4' on the title and start_date column
Example 6.
SELECT empid,start_date,title
FROM s_employee
WHERE title = 'CLERK'
AND start_date = '01-JAN-01';
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE
1 0 TABLE ACCESS (BY INDEX ROWID) OF 'S_EMPLOYEE'
2 1 INDEX (RANGE SCAN) OF 'EMP_IDX4' (NON-UNIQUE)
Example 7.
In the following case Oracle does not make use of the index because only the second part
of the two-part index is referenced in the predicate clause.
SELECT empid,start_date,title
FROM s_employee
WHERE start_date = '01-JAN-01';
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE
1 0 TABLE ACCESS (FULL) OF 'S_EMPLOYEE'
For a concatenated index to be used in full or in part, the leading edge of the index must
be present. If any column contained in the index is not present in the predicate clause,
then all columns of the index following that column cannot use the index.
Example 8.
NULL values are not stored in indexes. The following query will not make use of the
index.
SELECT *
FROM s_employee
WHERE lname is NULL;
Example 9.
If an IS NOT NULL check is performed on the column. All of the non-NULL values for
the column are stored in the index, however the index search would not be efficient. To
resolve the query ,the optimizer would need to read every value from the index and
access the table for each row returned from the index. In most cases, it would be more
efficient to perform a full table scan than to perform an index scan (with associated Table
Access By ROWID operations). The following query should not make use of an index.
SELECT *
FROM s_employee
WHERE lname IS NOT NULL;
Example 10.
SELECT empid,lname
FROM s_employee
WHERE empid = 1;
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE
1 0 TABLE ACCESS (BY INDEX ROWID) OF 'S_EMPLOYEE'
2 1 INDEX (UNIQUE SCAN) OF 'S_EMPID_PK' (UNIQUE)
In the following example rule-based optimization was used and a unique index existing
on the empid column was used.
Example 11.
SELECT empid,lname
FROM s_employee
WHERE substr(empid,1,1) = 1;
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE
1 0 TABLE ACCESS (FULL) OF 'S_EMPLOYEE'
A full table scan was performed. The suppression of the index will occur if any function
or modification is performed on the index column in the predicate clause including any
character, numeric or date functions.
Index suppression may be desired if you need to force the optimizer to disregard an index
in certain cases. To suppress an index , the SQL statement must be changed in a manner
to ensure the same result set. To suppress predicate conditions for numeric values , add a
0 to the column . To suppress predicate conditions for character values , add a NULL
string to the column as shown below in Example 12 and Example 13.
Example 12.
The following illustrates the suppression of numeric column.
SELECT empid,lname
FROM s_employee
WHERE empid + 0 = 1;
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE
1 0 TABLE ACCESS (FULL) OF 'S_EMPLOYEE'
Example 13.
The following illustrates the suppression of character column.
SELECT empid,lname
FROM s_employee
WHERE lname || ‘ ’ = ‘TOM’;
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE
1 0 TABLE ACCESS (FULL) OF 'S_EMPLOYEE'
Example 14.
The empid column is defined as a number. The following illustrates a query containing
an equality that compares the empid column to a character column.
SELECT empid,lname
FROM s_employee
WHERE empid = '1';
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE
1 0 TABLE ACCESS (BY INDEX ROWID) OF 'S_EMPLOYEE'
2 1 INDEX (UNIQUE SCAN) OF 'S_EMPID_PK' (UNIQUE)
The resulting Explain Plan indicates the index was still used. When Oracle compares a
numeric value to a character value, it converts the character value to a number internally.
Example 15.
In this case the emp_dup_id column is a character column and the query contains an
equality that compares the emp_dup_id column to a numeric column.
SELECT emp_dup_id,lname
FROM emp_test
WHERE emp_dup_id = 1;
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE
1 0 TABLE ACCESS (FULL) OF 'EMP_TEST'
The emp_dup_id column was modified internally by oracle with a TO_NUMBER
function , thus suppressing the use of the index.
Example 16.
SELECT *
FROM s_employee
WHERE empid != 1
Example 17.
SELECT *
FROM s_employee
WHERE lname NOT IN
(SELECT lname
FROM emp_test);
Example 18.
SELECT MIN(empid)
FROM s_employee;
Improve Subquery Execution
Using a correlated subquery when a subquery is involved in a SQL statement is generally
more efficient.
When multiple tables are joined in a SQL statement and a table in the join is only used in
the predicate clause and not in the SELECT clause, the statement can be converted to a
subquery to improve performance.
When a subquery is correlated, the outer query executes first, followed by the inner query
executing for each record returned from the outer query. When a subquery is non-
correlated, the inner query executes first (the result set is treated similarly as a set of
values from an IN condition), and then the outer query is executed.
When subqueries are used , using the EXISTS operator versus the IN operator is more
efficient. The EXISTS operator terminates the inner query fetching when one matching
record in the query is found, whereas the IN operator continues until all matching records
are found.
The following Example 19 and Example 20 illustrates the improvements when executing
a correlated subquery versus a non-correlated subquery.
Example 19.
The following query is a non-correlated query.
SELECT lname,fname
FROM s_employee
WHERE lname IN
(SELECT lname from emp_test);
Execution Plan
------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE
1 0 MERGE JOIN
2 1 SORT (JOIN)
3 2 TABLE ACCESS (FULL) OF 'S_EMPLOYEE'
4 1 SORT (JOIN)
5 4 VIEW
6 5 SORT (UNIQUE)
7 6 TABLE ACCESS (FULL) OF 'EMP_TEST'
Example 20.
The statement is modified to a correlated subquery with an EXISTS in the following
example.
SELECT lname,fname
FROM s_employee a
WHERE EXISTS
(SELECT 'X'
FROM emp_test
WHERE lname = [Link]);
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE
1 0 FILTER
2 1 TABLE ACCESS (FULL) OF 'S_EMPLOYEE'
3 1 INDEX (RANGE SCAN) OF 'S_EMP_TEST_IDX' (NON-UNIQUE)
The execution plan chosen by Oracle determines a driving table based on the order
of the table names when a join condition is involved and no predicate condition
exists that leads the optimizer to choose one table over the other.
The object of all your SQL query and update statements is to minimize the total
physical number of database blocks that need to be read and /or written.
If you have two tables in the FROM clause of the statement, you will keep the
driving table last in the FROM clause.
Example 21.
If Tab2 is selected as the driving Table
SELECT count(*)
FROM Tab1, Tab2
0.96 seconds elapsed
Example 22.
If Tab1 is selected as the driving table
SELECT count(*)
FROM Tab2, Tab1
20.96 seconds elapsed
When Oracle processes multiple tables, it uses an internal sort/merge procedure to join
the two tables. First it scans and sorts the first (driver) table. Next it scans the second
table and merges all of the rows retrieved from the second table with those retrieved from
the first table.
If three tables are being joined , try to select the intersection table as the driving
table.
The intersection table is the table that has the most dependencies on it.
In the Example 23 below emp represents the intersection between location and
category table.
Example 23.
SELECT …
FROM location L, category C, emp E
WHERE [Link] BETWEEN 10 AND 20
AND E.cat_no = C.cat_no
AND [Link] = [Link]
Example 24.
SELECT …
FROM emp E , location L, category C
WHERE E.cat_no = C.cat_no
AND [Link] = [Link]
AND [Link] BETWEEN 10 AND 20
Equality and range predicates
When indexes combine both equality and range predicates over the same table, Oracle
cannot merge these indexes. In such cases it uses only the equality predicate. Each row is
individually validated against the second predicate. In the following Example 25 there is
a non-UNIQUE index over dept_no and non-UNIQUE index over emp_cat.
Example 25.
SELECT emp_name
FROM emp
WHERE dept_no > 20
AND emp_cat = ‘A’
Execution Plan
----------------------------------------------------------
Table Access By Rowid on EMP
Index Range Scan on cat_idx
The emp_cat index is used , and then each row is validated manually.
Example 26.
SELECT emp_name
FROM emp
WHERE dept_no > 20
AND emp_cat > ‘A’
Execution Plan
----------------------------------------------------------
Table Access By Rowid on EMP
Index Range Scan on dept_idx
Automatic index suppression
Under certain circumstances, the RDBMS kernel will actually omit particular indexes
from the query plan. Assume that the table has two (or more) available indexes and that
one index is unique and the other index is non-unique. In such cases, Oracle uses the
unique retrieval path and ignores the second option. In the following example, there is a
UNIQUE index over emp_no and non-UNIQUE index over emp_dept.
Example 27.
SELECT emp_name
FROM emp
WHERE emp_no = 10
AND emp_dept = 2;
Execution Plan
----------------------------------------------------------
Table Access By Rowid on EMP
Index Unique Scan on emp_no_idx
The emp_no index is used to fetch the row. The second predicate (emp_dept = 2) is then
manually evaluated (no index used).
The example shows three ways for retrieving data about employees having emp_no 10 or
20. Method 1 is least efficient, method 2 is more efficient and method 3 is most efficient.
Method 1.
Two separate database access
SELECT *
FROM emp
WHERE emp_no = 10;
SELECT *
FROM emp
WHERE emp_no = 20;
Method 2.
One cursor and two fetches
DECLARE
CURSOR C(eno number) IS
SELECT *
FRO M emp
WHERE emp_no = eno;
BEGIN
OPEN C(10);
FETCH C INTO …;
.
.
OPEN C(20);
FETCH C INTO …;
CLOSE C;
END;
Method 3.
SQL table join
SELECT a.emp_name,b.emp_name
FROM emp a, emp b
WHERE a.emp_no = 10
AND a.emp_no = 10;
SELECT COUNT(*),SUM(sal)
FROM emp
WHERE deptno=10
AND hiredate > ‘01-Jan-01’
SELECT COUNT(*),SUM(sal)
FROM emp
WHERE deptno=20
AND hiredate > ‘01-Jan-01’
You can achieve the same result more efficiently using DECODE
SELECT COUNT(DECODE(deptno,10,’X’,NULL)) ,
COUNT(DECODE(deptno,20,’X’,NULL)) ,
SUM(DECODE(deptno,10,sal,NULL)) ,
SUM(DECODE(deptno,20,sal,NULL))
FROM emp
WHERE hiredate > ‘01-Jan-01’;
SELECT deptno,sum(sal)
FROM emp
GROUP BY deptno
HAVING DEPTNO != 40;
SELECT deptno,sum(sal)
FROM emp
WHERE DEPTNO != 40;
SELECT emp_name
FROM emp e
WHERE EXISTS
(SELECT 'X' from dept where dept_no = [Link] and dept_cat = 'A');
To improve the performance we can use the following query.
SELECT emp_name
FROM dept d ,emp e
WHERE d.dept_no = [Link]
AND d.dept_cat='A';
One way that you can change an execution plan is to add optimizer hints to the query.
These hints take the form of specially formatted comments and tell the optimizer how
you want the query to be executed. They aren’t really hints, either, even though Oracle
refers to them as such. They’re more like commands.
All hints force the optimizer to use cost-based optimization, even if the tables being
referenced are not analyzed.
It’s true that Oracle will ignore hints that are contradictory or that are impossible to carry
out, but you’ll never see Oracle ignore a hint when it can be carried out.
Notice the plus (+) sign immediately following the start of the comment. That plus sign
tells Oracle that the comment contains hints. The comment may contain several hints, and
you may have comments interspersed with your hints. You should separate hints from
each other, and from any non-hint text, by at least one space.
The comment with the hints must immediately follow the SELECT, INSERT,
UPDATE or DELETE keyword.
For Oracle to recognize the hints, the comment must start with /*+. As an
alternative, you can use --+to start a comment containing hints. If you do this, the
comment continues until the end of the line is reached. In practice, almost
everyone uses /*+...*/.
Several hints allow you to reference table names and/or index names. Table and
index names are always enclosed within parentheses.
If you alias a table in your query, you must use that alias in any hints that refer to
the table.
If you supply contradictory hints, Oracle will ignore at least one of them.
If your hints refer to indexes that don’t exist, Oracle will ignore them.
If you want to control the execution of a subquery, you must place a hint in that
subquery. Hints in the main query refer to the main query. Hints in a subquery
refer to the subquery.
If you write a hint incorrectly, Oracle will ignore it. Oracle never returns error
messages for badly written hints. Hints are embedded within comments, and to
comply with ANSI standards, error messages can’t be returned for comments.
Table 2 - HINTS
Hint Description
ALL_ROWS Produces an execution plan that optimizes overall
resource usage.
AND_EQUAL(table_name Specifies to access a table by scanning two or more
Index_ name indexes and merging the results. You must specify at
index name ...) least two index names with this hint.
CHOOSE Specifies to use the cost-based optimizer if statistics
exist for any of the tables involved.
CLUSTER(table_name ) Specifies to do a cluster scan to access the specified
table. This hint is valid only for clustered tables.
DRIVING_SITE (table_name Specifies which database to use as the driving site when
). joining tables from two different databases. The driving
site will be the database in which the named table
resides
FIRST_ROWS Produces an execution plan that optimizes for a quick
Initial response.
FULL(table_name ) Specifies to access the named table by reading all
The rows.
HASH(table_name ) Specifies to do a hash scan of the named table. This hint
is valid only for hash-clustered tables.
INDEX(table_name Specifies to access the named table through an index.
[index_name...]) You may optionally specify a list of indexes from which
To choose.
INDEX_ASC(table_name Specifies an index to scan, the same as INDEX , but also
[index_name...]) specifies to scan the index in ascending order.
INDEX_COMBINE Specifies to access the table using a combination of two
(table_ name indexes. You may optionally supply a list of indexes
[index_name...]) from which to choose.
INDEX_DESC(table_name Specifies an index to scan, the same as INDEX , but also
[index_name...]) specifies to scan the index in descending order.
ORDERED Specifies to join tables from left to right, in the same
order in which they are listed in the FROM clause of the
query.
ROWID(table_name ) Specifies to access the named table using ROWIDs.
RULE Specifies to use the rule-based optimizer.
USE_CONCAT Forces combined OR conditions in the WHERE clause
of a query to be transformed into a compound query
using the UNION ALL set operator.
USE_HASH(table_name ) Specifies to use a hash join whenever the named table is
Joined to any other table.
USE_MERGE(table_name ) Specifies to use a merge join whenever the named table
Is joined to any other table.
USE_NL(table_name ) Specifies to use a nested loop when joining the named
Table to any other table. The other table will always be
The driving table.
In order to explain the usage of INDEX , INDEX_ASC and INDEX_DESC hints we will
make use of the following example shown below.
Example 28
SELECT *
FROM HINT_DEPT ;
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE
1 0 TABLE ACCESS (FULL) OF 'HINT_DEPT'
In the above case, a FULL TABLE scan has been performed on the HINT_DEPT table.
INDEX Hint
In the above query in Example 28 is modified to make use of the INDEX hint.
Example 29.
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=826 Card=82 Bytes=22
14)
In the above case the optimizer makes use of the index on deptno column to access the
hint_dept table.
INDEX_ASC Hint
In the above query in Example 28 is modified to make use of the INDEX_ASC hint.
Example 30
In the above case the optimizer to make use of an ascending indexed table scan for the
hint_dept table.
INDEX_DESC Hint
In the above query in Example 28 is modified to make use of the INDEX_DESC hint.
Example 30.
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=826 Card=82 Bytes=16
40)
In the above case the optimizer to make use of an descending indexed table scan for the
hint_dept table.
FULL Hint
Forces the optimizer to make use of a full table scan for the specified table
Example 31.
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=1 Card=1 Bytes=13)
1 0 TABLE ACCESS (FULL) OF 'HINT_DEPT' (Cost=1 Card=1 Bytes=13
)
ROWID Hint
Forces the optimizer to make use of a table scan by ROWID for the hint_dept table.
Example 32.
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=1 Card=1 Bytes=13)
1 0 INDEX (UNIQUE SCAN) OF 'DEPT_PK' (UNIQUE) (Cost=1 Card=1 B
ytes=13)
FIRST_ROWS Hint
Optimizes for best response time at a higher cost. Will always choose an index over a
Full table scan.
Example 33.
ALL_ROWS Hint
Optimizes for best throughput to execute all rows. Cost is very less.
Example 34.
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=HINT: ALL_ROWS (Cost=1 Card=82 By
tes=1066)
CHOOSE Hint
Uses the Cost-based optimizer if statistics are available for atleast one table, otherwise
uses the Rule-based optimizer.
Example 35.
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=HINT: CHOOSE
1 0 TABLE ACCESS (FULL) OF 'HINT_DEPT'
RULE Hint
Uses the Rule-based optimizer
Example 36.
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=HINT: RULE
1 0 TABLE ACCESS (FULL) OF 'HINT_DEPT'
AND_EQUAL Hint
The AND_EQUAL hint explicitly chooses an execution plan that uses an access path that
merges the scans on the indexes on dname and loc column.
Example 37.
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=3 Card=1 Bytes=14)
1 0 AND-EQUAL
2 1 INDEX (RANGE SCAN) OF 'DNAME_IDX' (NON-UNIQUE) (Cost=1 C
ard=1)
Oracle’s Explain Plan feature allows you to discover the execution plan for a SQL
statement. You do this by using a SQL statement, named EXPLAIN PLAN , to which
you append the query of interest. Consider this example:
EXPLAIN PLAN
SET STATEMENT_ID =‘test2 ’
FOR
SELECT [Link],[Link]
FROM emp e,dept d
WHERE [Link]=[Link];
After issuing this statement, you can query a special table known as the plan_table to
find the execution plan that Oracle intends to use for the query.
The records in the plan table are related to each other hierarchically. Each record
has an ID column and a PARENT_ID column. You execute a given SQL statement
by performing a series of operations. Each operation, in turn, may consist of one
or more operations. The most deeply nested operations are executed first. They,
in turn, feed results to their parents. This process continues until only one result
is left —the result of the query —which is returned to you. Using the Plan Table Query
The three most significant columns in the plan table are named OPERATION ,
OPTIONS , and OBJECT_NAME . For each step, these tell you which operation is
going to be performed and which object is the target of that operation.
You can use the following SQL query to display an execution plan once it has
been generated:
You use the CONNECT BY clause to link each operation with its parent. The LPAD
business is for indention so that if an operation has child rows, those rows will be
indented underneath the parent.
Operation Description
APPENDIX B
Using SQL Trace and TKPROF
Oracle includes a facility known as SQL Trace that is extremely useful for diagnosing
performance problems on running systems. It logs information to an operating system file
for all the queries executed by a specific session, or by all sessions. Later, you can review
that information, find out which queries are consuming the most CPU or generating the
most I/O, and take some corrective action.
SQL Trace returns the following information for each SQL statement:
A count of the times that the statement was executed
The total CPU and elapsed time used by the statement
The total CPU and elapsed times for the parse, execute, and fetch phases of the
statement’s execution
The total number of physical reads triggered by the statement
The total number of logical reads triggered by the statement
The total number of rows processed by the statement
The information on physical I/O and CPU time is most helpful when it comes to
identifying statements that are causing performance problems.
TIMED_STATISTICS —Controls whether Oracle tracks CPU and elapsed time for
each statement. Always set this parameter to TRUE . The overhead for that is
minimal, and the value of the timing information is well worth it.
You can’t set the maximum file size at the session level. You must set it in the parameter
file for the instance. You can specify the maximum file size in either bytes or operating-
system blocks. If you specify the size using a raw number, Oracle interprets it to mean
blocks. If you supply a suffix such as K or M, Oracle interprets it as kilobytes or
megabytes. For example:
If you are tracing a long process and the size of the trace file reaches the limit specified
by MAX_DUMP_FILE_SIZE, then Oracle will silently stop tracing. The process will
continue to run.
The USER_DUMP_DEST parameter points you to the directory where the trace files are
created. Knowing its value is critical to the task of finding the trace files that you
generate.
If you change any of these parameters in the database parameter file, you will need to
stop and restart the instance for those changes to take effect.
SELECT value
FROM v$parameter
WHERE name =‘user_dump_dest ’;
If you’re not the DBA, you may not have access to the v$parameter view.
Finding the directory is the easy part. Figuring out which trace file is yours is a bit more
difficult. Oracle generates trace file names automatically, and the names are based on
numbers that aren’t always easy to trace back to a session. A typical trace file name
would be [Link] .
So how do you find your trace file? One way is by looking at the timestamp. Write down
the time of day when you enable tracing, and also the time at which you finish. Later,
look for a trace file with a modification date close to the finish time. If you’re not sure of
your finish time, look at files with modification dates later than your starting time.
Hopefully, there won’t be so many people using the trace facility simultaneously that this
becomes a difficult task. If you have multiple trace files all created around the same time,
you may have to look at the SQL statements inside each file to identify the one that you
generated.
The method that you choose depends on whether you want to enable tracing for your
session, for someone else’s session, or for all sessions connected to the database.
In between these two commands, you should execute the SQL queries that you are
interested in tracing.
Start the batch process or online program that you are interested in tracing.
Start another session using SQL*Plus.
Issue a SELECT statement against the V$SESSION view to determine the SID and
serial number of the session created in step 1 by the program that you want to
trace.
Issue a call to DBMS_SYSTEM.SET_SQL_TRACE_IN_SESSION to turn tracing on
for that session.
Collect the information that you need.
Issue a call to DBMS_SYSTEM.SET_SQL_TRACE_IN_SESSION to turn tracing
off.
SELECT username,sid,serial#
FROM v$session;
USERNAME SID SERIAL#
------------------------------------------------
...
SEAPARK 9 658
SYSTEM 11 1134
Once you have the SID and serial # of the session that you want to trace, you can enable
and disable tracing, as shown in this example:
In this example, tracing was turned on for the SEAPARK user. The first call to DBMS_
SYSTEM.SQL_TRACE_IN_SESSION included a value of TRUE to enable tracing. The
second call included a value of FALSE to stop it.
SQL_TRACE =TRUE
Use care when you enable tracing on a database-wide basis like this. Some performance
overhead is involved. Make sure that you really need database-wide statistics, and
whatever you do, remember to turn it off later by setting
SQL_TRACE =FALSE.
Using the TKPROF command
The raw trace files generated by Oracle aren’t very readable. To view the results of a
trace, you must run the TKPROF utility against the trace file that you generated. The
TKPROF utility will read the trace file and create a new file containing the information in
human readable form.
The TKPROF utility allows you to sort the queries in the output file based on a number
of different parameters. For example, you can choose to have the queries that consumed
the most CPU sorted to the front of the file. With large files, sorting the results makes it
easier for you to quickly identify those queries most in need of work.
The TKPROF utility also provides you with the option of issuing an EXPLAIN PLAN
for each statement in the trace file. The result here is that the output file will contain
execution plans, in addition to the statistics, for each statement.
Executing TKPROF
The simplest way to execute TKPROF is to specify an input and an output file
name, like this:
If your trace file contains a lot of SQL statements, you will want to sort the results.
You’ll likely find it beneficial to sort by the amount of CPU consumed when executing a
statement. Consider this example:
It’s usually wise to generate execution plans for each SQL statement in the file. If you
look at the execution plan for a poorly performing statement, it can help you better
understand the problem.
Explaining Plans
TKPROF’s explain option allows you to generate execution plans for the SQL statements
in the trace file. When you use the explain option, you must supply TKPROF with a
username and password. TKPROF uses it to log on and explain the plans. The user that
you specify must have access to the tables referenced by the queries in the trace file. The
user should also own a plan table named PLAN_TABLE. However, if no plan table
currently exists, and if the user has the CREATE TABLE privilege, TKPROF will create
one temporarily. Here’s an example of the explain option being used:
You’ll notice that when you use the explain option, TKPROF’s execution time is much
longer than otherwise. This is due to the overhead involved in connecting to the database
and issuing EXPLAIN PLAN statements for each query.
SELECT LNAME,FNAME
FROM S_EMPLOYEE
WHERE lname in
(SELECT lname FROM EMP_TEST);
The major sections that you see here include the following:
The SQL statement itself
Statistics related to the execution of that SQL statement
Information about the execution plan used for the statement
The statistics are often the key to diagnosing performance problems with specific SQL
statements. To interpret this output, you need to understand what those statistics are
telling you.
If the TIMED_STATISTICS parameter is not TRUE , you will see zeros for all
the timings.
The column descriptions are as follows:
COUNT
Tells you the number of times that a SQL statement was parsed or executed. For
SELECT statements, this tells you the number of fetches that were made to retrieve
the data.
CPU
Tells you the amount of CPU time spent in each phase.
ELAPSED
Tells you the elapsed time spent in each phase.
DISK
Tells you the number of database blocks that were physically read from disk in each
phase.
QUERY
Tells you the number of buffers that were retrieved in consistent mode (usually for
queries) in each phase.
CURRENT
Tells you the number of buffers that were retrieved in current mode in each phase.
Following the tabular statistics, TKPROF reports the number of library cache misses,
the optimizer goal, and the numeric user ID of the user who parsed the statement.
APPENDIX C
SET AUTOTRACE ON
D
-
X
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE
1 0 TABLE ACCESS (FULL) OF 'DUAL'
Statistics
----------------------------------------------------------
0 recursive calls
4 db block gets
1 consistent gets
0 physical reads
0 redo size
365 bytes sent via SQL*Net to client
456 bytes received via SQL*Net from client
4 SQL*Net roundtrips to/from client
1 sorts (memory)
0 sorts (disk)
1 rows processed
The Explain Plan reveals the execution plan Oracle has chosen and the statistics reveal
the resources required to complete execution of the SQL statement. The main statistics to
review are the physical reads (disk reads), db block gets, consistent gets (memory reads),
and the recursive calls (internal oracle recursive calls that are costly).