You are on page 1of 70

Oracle SQL Tuning

Why Tune ?
To improve response time
To improve batch throughput
To ensure scalability
To reduce system load
To avoid hardware upgrades

Tuning Techniques
Re-wording the SQL
Giving Oracle explicit instructions called Hints
Creating or changing indexes or clusters
Changing the table structure

Types of SQL Statements


Data Definition Language (DDL), used to define the
database structure or schema: CREATE, DROP, ALTER,
TRUNCATE
Data Manipulation Language (DML), used for managing
data within schema objects: SELECT, INSERT, UPDATE,
DELETE, MERGE/UPSERT
Data Control Language (DCL), used to control access to
data stored in a database: GRANT, REVOKE, DENY
Transaction Control Language (TCL), used to manage
the changes made by DML statements: COMMIT,
SAVEPOINT, ROLLBACK

Query Operations
Subqueries: nested subquery (in the WHERE clause),
inline views (in the FROM clause), in the SELECT clause,
correlated subquery
Joins: inner, outer, self, equi-joins
Set: UNION, UNION ALL, MINUS, INTERSECT
Aggregations: AVG, COUNT, MAX, MIN, SUM

SQL Processing
Create Cursor

Allocate memory for cursor

Parse SQL

Check syntax and security

Bind Variables

Associate program variable


with SQL

Execute SQL

Execute DML statement or


prepare query to

Query?

Close Cursor

Re-execute
Cursor

Close Cursor

Fetch rows

Retrieve one or more rows

SQL execution ended

Re-execute SQL statement

De-allocate cursor memory


and discard

What is Parsing?
It is the process of preparing the SQL statement for
execution
Process:
Check that the SQL statement syntactically valid
Check that the statement is semantically valid
Check security
Determine an execution plan

Improving Parse Speed


The parse phase for statements can be decreased by
efficient use of aliasing. If an alias is not present, the
engine must resolve which tables own the specified
columns. The following is an example:
Bad Statement
SELECT first_name, last_name,
country
FROM employee, countries
WHERE country_id = id
AND lastname = 'HALL';

Good Statement
SELECT e.first_name, e.last_name,
c.country
FROM employee e, countries c
WHERE e.country_id = c.id
AND
e.last_name = 'HALL';

Shared SQL
It is a cache of recently executed SQL
Maintained in SQL Area of Shared Pool
Avoids unnecessary parsing

Bind Variables
Bind Variables are fixed references to variables contained
elsewhere in the programming language

Why are we talking of Parsing,


Shared SQL and Bind Variables?
Parsing is expensive
Excessive parsing can bottleneck the application
If you are going to re-execute an SQL with different
parameters use bind variables

Advantages of using Bind Variables


No new cursor is created
No re-parsing takes place
If another session executes the same SQL statement, a
match is found in the shared pool

Bind Variables in SQL*Plus


In SQL*Plus you can use bind variables as follows:
SQL> variable deptno number
SQL> exec :deptno := 10
SQL> select * from emp where deptno = :deptno;

Bind Variables in PL/SQL


The good news is that every reference to a PL/SQL
variable is in fact a bind variable
create or replace procedure dsal(p_empno in number)
as
begin
update emp
set sal=sal*2
where empno = p_empno;
commit;
end;

Dynamic SQL
The only time you need to consciously decide to use bind
variables when working with PL/SQL is when using
Dynamic SQL, which allows you to execute a string
containing SQL using the EXECUTE IMMEDIATE
command

Bind Variables in VB, Java and other


applications
When you put together an SQL statement using Java, or
VB, or whatever, you usually use an API for accessing the
database; ADO in the case of VB, JDBC in the case of
Java. All of these APIs have built-in support for bind
variables, and it's just a case of using this support rather
than just concatenating a string yourself and submitting it to
the database.
For example, Java has PreparedStatement, which allows
the use of bind variables, and Statement, which uses the
string concatenation approach. If you use the method that
supports bind variables, the API itself passes the bind
variable value to Oracle at runtime, and you just submit your
SQL statement as normal.

Execution Plan
The combination of the steps Oracle uses to execute a
statement is called an execution plan.

Query Optimization
It is the process of determining the optimal path to
retrieve data

Approaches to Query Optimization


Rule based
Based on predefined set of precedence rules (rigid
rules) to figure out which path it will use to access the
database.
Does not take into account the volume of data
Cost based
Takes into account statistical information relating to
volume and distribution of data within tables and
indexes (it uses database information such as table
size, number of rows, key spread, and so forth, rather
than rigid rules).

Goals of Query Optimization (1 of 2)


RULE
This specifies that the optimizer is to take the rule based
approach to optimization
CHOOSE
This specifies that the optimizer is to use the cost based
approach if any of the table in the SQL statement has
been analyzed.
If no tables have been analyzed, then use the rule based
approach.

Goals of Query Optimization (2 of 2)


ALL_ROWS
This explicitly chooses the cost-based approach to
optimize a statement block with a goal of best
throughput (that is, minimum total resource)
FIRST_ROWS
This explicitly chooses the cost-based approach to
optimize a statement block with a goal of best response
time (minimum resource usage to return first row).

Statistics Used for the Cost-Based Approach


The cost-based approach uses statistics to estimate the
cost of each execution plan.
These statistics can be generated using the ANALYZE
command, or DBMS_STATS package.
Using these statistics, the optimizer estimates how much
I/O, CPU time, and memory are required to execute a SQL
statement using a particular execution plan.

ANALYZE Command (1 of 2)
You can analyze the storage characteristics of tables, indexes, and clusters to
gather statistics which are then stored in the data dictionary.
The optimizer uses these statistics in a cost-based approach to determine the
most efficient execution plan for the SQL statements you issue. Note that
statistics can be either computed or estimated, depending on the amount of
overhead you are willing to allow for this purpose.
Queries with many joins are quite sensitive to the accuracy of the statistics.
Use the COMPUTE option of the ANALYZE command if possible (it may take
quite some time and a large amount of temporary space). If you must use the
ESTIMATE option, sample as large a percentage as possible.
When you analyze a table, the indexes that are defined on that table are also
analyzed.

ANALYZE Command (2 of 2)
Syntax:
ANALYZE TABLE <table name> COMPUTE/ESTIMATE
STATISTICS
The statistics are visible through these data dictionary
views:
USER_TABLES, ALL_TABLES, and DBA_TABLES
USER_TAB_COLUMNS, ALL_TAB_COLUMNS, and
DBA_TAB_COLUMNS

How Oracle Optimizes SQL Statements


Evaluation of expressions and conditions
Statement transformation
View merging
Choice of optimization approaches
Choice of access paths
Choice of join orders
Choice of join operations

How does Oracle access data?


At the physical level Oracle reads blocks of data. The
smallest amount of data read is a single Oracle block, the
largest is constrained by operating system limits (and
multiblock I/O)

Logical Access Method


Full Table Scan (FTS) - In a FTS operation, the whole table is read
up to the high water mark (HWM). The HWM marks the last block in
the table that has ever had data written to it. If you have deleted all
the rows then you will still read up to the HWM. Truncate resets the
HWM back to the start of the table.
Index Lookup (unique & non-unique) - Data is accessed by
looking up key values in an index and returning rowids. A rowid
uniquely identifies an individual row in a particular data block. This
block is read via single block I/O.
Rowid - This is the quickest access method available Oracle simply
retrieves the block specified and extracts the rows it is interested in.
Most frequently seen in explain plans as Table access by Rowid

What is EXPLAIN PLAN? (1 of 2)


The EXPLAIN PLAN command displays the execution plan
chosen by the Oracle optimizer for SELECT, UPDATE,
INSERT, and DELETE statements.
A statement's execution plan is the sequence of operations
that Oracle performs to execute the statement.
The general syntax of EXPLAIN PLAN is:
explain plan for sql-statement;

If you do an EXPLAIN PLAN, Oracle will analyze the


statement and fill a special table with the Execution plan for
that statement.

What is EXPLAIN PLAN? (2 of 2)


You can indicate which table has to be filled with the
following SQL command:
explain plan into table_name for sql-statement;

If you omit the INTO TABLE_NAME clause, Oracle fills a


table named PLAN_TABLE by default.
The plan table is the table that Oracle fills when you have it
explain an execution plan for an SQL Statement.
Oracle ships with the script UTLXPLAN.SQL in
$ORACLE_HOME/rdbms/admin/ directory which creates
this table, named PLAN_TABLE.

Understanding Explain Plan


Simple explain plan:
Query Plan
----------------------------------------SELECT STATEMENT [CHOOSE] Cost=1234
TABLE ACCESS FULL LARGE [:Q65001] [ANALYZED]

In this case TABLE ACCESS FULL LARGE is the first operation.


This statement means we are doing a full table scan of table LARGE. The resultant
row source is passed up to the next level of the query for processing (SELECT
STATEMENT)
[CHOOSE] is an indication of the optimizer_goal for the query.
To determine the optimizer_goal observe the following
- If cost has value it means CBO is used
SELECT STATEMENT [CHOOSE] Cost=1234

- If cost is blank it mean RBO is used


SELECT STATEMENT [CHOOSE] Cost=

Access Methods in Detail (1 of 3)


FULL TABLE SCAN Example:
SQL> explain plan for select * from dual;
Query Plan
----------------------------------------SELECT STATEMENT [CHOOSE] Cost=
TABLE ACCESS FULL DUAL

Access Methods in Detail (2 of 3)


INDEX LOOKUP
SQL> explain plan for select empno, ename from emp where empno=7566;
Query Plan
-----------------------------------SELECT STATEMENT [CHOOSE] Cost=1
TABLE ACCESS BY ROWID EMP [ANALYZED]
INDEX UNIQUE SCAN EMP_I1

Notice the 'TABLE ACCESS BY ROWID' section. This indicates that


the table data is not being accessed via a FTS operation but rather
by a rowid lookup. In this case the rowid has been produced by
looking up values in the index first. The index is being accessed by
an 'INDEX UNIQUE SCAN' operation. This is explained below. The
index name in this case is EMP_I1. If all the required data resides in
the index then a table lookup may be unnecessary and all you will
see is an index access with no table access.

Access Methods in Detail (3 of 3)


In the following example all the columns (empno) are in the
index. Notice that no table access takes place:
SQL> explain plan for select empno from emp where empno=7566;
Query Plan
-----------------------------------SELECT STATEMENT [CHOOSE] Cost=1
INDEX UNIQUE SCAN EMP_I1

Indexes are presorted so sorting may be unecessary if the


sort order required is the same as the index.

Index Lookup Methods (1 of 5)


Index Unique Scan - Method for looking up a single key
value via a unique index, which always returns a single
value. You must supply AT LEAST the leading column of
the index to access data via the index. However this may
return > 1 row as the uniqueness will not be guaranteed.
SQL> explain plan for select empno,ename from emp where empno=7566;
Query Plan
-----------------------------------SELECT STATEMENT [CHOOSE] Cost=1
TABLE ACCESS BY ROWID EMP [ANALYZED]
INDEX UNIQUE SCAN EMP_I1

Index Lookup Methods (2 of 5)


Index Range Scan - Method for accessing multiple column
values You must supply AT LEAST the leading column of
the index to access data via the index, which can be used
for range operations (e.g. > < <> >= <= between).
SQL> explain plan for select empno,ename from emp where empno > 7566
order by empno;
Query Plan
-----------------------------------SELECT STATEMENT [CHOOSE] Cost=1
TABLE ACCESS BY ROWID EMP [ANALYZED]
INDEX RANGE SCAN EMP_I1 [ANALYZED]

Index Lookup Methods (3 of 5)


Index Full Scan - In certain circumstances it is possible for
the whole index to be scanned as opposed to a range
scan.
--create concatenated index
CREATE INDEX EMP_INDEX ON EMP(EMPNO,ENAME);
SQL> explain plan for select empno, ename from emp order by empno,
ename;
Query Plan
-----------------------------------SELECT STATEMENT [CHOOSE] Cost=26
INDEX FULL SCAN EMP_INDEX [ANALYZED]

Index Lookup Methods (4 of 5)


Index Fast Full Scan
empno is PK and index name is pk_emp
SELECT /*+INDEX_FFS(EMP PK_EMP)*/ EMPNO FROM EMP;

Scans all the block in the index. Rows are not returned in
sorted order.
Query Plan
-----------------------------------SELECT STATEMENT [CHOOSE] Cost=1
INDEX FAST FULL SCAN PK_EMP [ANALYZED]

Index Lookup Methods (5 of 5)


Rowid
This is the quickest access method available Oracle simply
retrieves the block specified and extracts the rows it is
interested in.
SQL> explain plan for select * from dept where rowid = ':x';
Query Plan
-----------------------------------SELECT STATEMENT [CHOOSE] Cost=1
TABLE ACCESS BY ROWID DEPT [ANALYZED]

Common Execute Steps (1 of 5)


Category

Operation

Option

Description

Table Access
Paths

TABLE ACCESS

FULL

Implies a full table scan

TABLE ACCESS

BY ROWID

Access a row by specifying the


ROWID

Index
Operations

AND-EQUAL

Results from one or more index


scans are combined

INDEX

UNIQUE SCAN

An index lookup which will


return the address of only one
row

INDEX

RANGE SCAN

An index lookup which will


return the address of more than
one row. Like a non-unique
index

Common Execute Steps (2 of 5)


Category

Operation

Join Operations

CONNECT BY

A retrieval of rows in a hierarchical


order for a query containing a
CONNECT BY clause.

MERGE JOIN

An operation that accepts two sets


of rows, each sorted by a specific
value, combines each row from one
set with the matching rows from the
other, and returns the result.

MERGE JOIN

Option

OUTER

NESTED LOOPS

NESTED LOOPS

Description

A merge join operation to perform an


outer join statement.
An operation that accepts two sets
of rows, an outer set and an inner
set. Oracle compares each row of
the outer set with each row of the
inner set and returns those rows that
satisfy a condition.

OUTER

A nested loops operation to perform


an outer join statement.

Common Execute Steps (3 of 5)


Category

Operation

Option

Description

Set Operations

CONCATENATION

An operation that accepts multiple sets


of rows and returns the union-all of the
sets.

INTERSECTION

An operation that accepts two sets of


rows and returns the intersection of the
sets, eliminating duplicates.

MINUS

An operation that accepts two sets of


rows and returns rows that appear in
the first set but not in the second,
eliminating duplicates.

UNION

An operation that accepts two sets of


rows and returns the union of the sets,
eliminating duplicates.

VIEW

An operation that performs a view's


query and then returns the resulting
rows to another operation.

Common Execute Steps (4 of 5)


Category

Operation

Miscellaneous

FOR UPDATE

An operation that retrieves and


locks the rows selected by a
query containing a FOR
UPDATE clause.

FILTER

An operation that accepts a set


of rows, eliminates some of
them, and returns the rest.

REMOTE

A retrieval of data from a remote


database.

SEQUENCE

An operation involving accessing


values of a sequence.

SORT

Option

Description

ORDER BY An operation that sorts a set of


rows for a query with an ORDER
BY clause.

Common Execute Steps (5 of 5)


Category

Operation

Aggregation

COUNT

Option

Description
An operation that counts the
number of rows selected from a
table.

COUNT

STOPKEY

A count operation where the


number of rows returned is limited
by the ROWNUM expression in the
WHERE clause.

SORT

AGGREGATE

A retrieval of a single row that is


the result of applying a group
function to a group of selected
rows.

SORT

JOIN

An operation that sorts a set of


rows before a merge-join operation

SORT

UNIQUE

An operation that sorts a set of


rows to eliminate duplicates.

SORT

GROUP BY

An operation that sorts a set of


rows into groups for a query with a
GROUP BY clause.

Influencing Optimizer using HINTS


Hints are instructions that can be included in the SQL
statement to instruct or guide the optimizer.

Some HINTS (1 of 8)
FULL(table name)
The FULL hint explicitly chooses a full table scan for the
specified table. For example, Oracle performs a full table
scan on the ACCOUNTS table to execute this statement,
even if there is an index on the ACCNO column that is
made available by the condition in the WHERE clause:
SELECT /*+ FULL(a) Don't use the index on ACCNO */ accno, bal
FROM accounts a
WHERE accno = 7086854;

Some HINTS (2 of 8)
INDEX(table name, index name)
The INDEX hint explicitly chooses an index scan for the specified
table. If this hint specifies a single available index, the optimizer
performs a scan on this index. If this hint specifies a list of
available indexes, the optimizer considers the cost of a scan on
each index in the list and then performs the index scan with the
lowest cost. If this hint specifies no indexes, the optimizer
considers the cost of a scan on each available index on the table
and then performs the index scan with the lowest cost.
SELECT /*+ INDEX(patients, sex_index) Use SEX_INDEX, since there are few
male patients */ name, height, weight
FROM patients
WHERE sex = 'M';

Some HINTS (3 of 8)
ROWID(table name)
The ROWID hint explicitly chooses a table scan by ROWID
for the specified table
SELECT /*+ROWID(emp)
'AAAAtkAABAAAFNTAAA'
AND empno = 7566;

*/

FROM

emp

WHERE

rowid

>

Some HINTS (4 of 8)
ORDERED
The ORDERED hint causes Oracle to join tables in the order in
which they appear in the FROM clause. For example, this
statement joins table TAB1 to table TAB2 and then joins the
result to table TAB3:
SELECT /*+ ORDERED */ tab1.col1, tab2.col2, tab3.col3
FROM tab1, tab2, tab3
WHERE tab1.col1 = tab2.col1
AND tab2.col1 = tab3.col1;

If you omit the ORDERED hint from a SQL statement


performing a join, the optimizer chooses the order in which to
join the tables.

Some HINTS (5 of 8)
Index Fast Full Scan
The INDEX_FFS will process ONLY the index. All columns
that are used and retrieved by the query MUST be
contained in the index.
SELECT /*+INDEX_FFS(EMPLOYEES EMP_NAME_IX)*/ LAST_NAME
FROM EMPLOYEES
WHERE LAST_NAME='KING';

Some HINTS (6 of 8)
USE_NL
Use nested loop joins when the subset of data between the
two joining tables is small. Because nested loop joins fetch
the data as soon as possible, they are the preferred joins
when either the data doesn't need to be sorted or you need
the queries to return quickly. For the example below,
assume B is having 1000 rows and A is having 100 rows:
SELECT /*+ ORDERED USE_NL(A) */
FROM B, A
Where A.column1 = B.column2;

Some HINTS (7 of 8)
USE_HASH
This hint is best suited for joining tables that have a large
subset of data. A hash join offers better throughput and is
best suited for sorting and ordering queries. When the size
of the tables is large, the hash table size becomes pretty
large and it requires more CPU and memory. The syntax
for the hint is:
/*+ USE_HASH (table_name) */

For example:
SELECT /*+ USE_HASH (s i) */ DISTINCT s.srvr_id
FROM servers s, serv_inst i
WHERE s.srvr_id = i.srvr_id;

Some HINTS (8 of 8)
USE_MERGE
The merge hint requires that both inputs be sorted on the merge
columns, which are defined by the equality (WHERE) clauses of the join
predicate. Because each input is sorted, the merge join operator gets a
row from each input and compares them. For example, for inner join
operations, the rows are returned if they are equal. If they are not equal,
whichever row has the lower value is discarded and another row is
obtained from that input. This process repeats until all rows have been
processed. The syntax for this hint is:
/*+ USE_MERGE(table_name) */

For example:
SELECT /*+ USE_MERGE (s i) */ DISTINCT s.srvr_id
FROM servers s, serv_inst i
WHERE s.srvr_id = i.srvr_id;

Full Table Scans vs Index Lookups


If all rows or a large number of rows of a table has to be
accessed then a full table scan is the quickest way of doing
it.
If a single row or 5% to 10% of the rows in a table has to
be accessed, use indexes.

Avoiding Accidental Table Scans


Sometimes the index may not be used if queries are
framed as:
Queries involving != (NOT EQUALS) condition
Searching for NULLS
Accidentally disabling an index with a function (eg
upper(last_name))

Optimizing Index Lookups


Where possible optimize a query by including all of the
columns contained in the WHERE clause within a
concatenated index
Try to maintain the order of the column in the index in the
WHERE clause
A LIKE SM% will benefit from the index whereas a %SM
% will not be able to leverage the benefits of an index

Queries Involving OR
For queries involving OR condition try using the hints
USE_CONCAT, FULL or INDEX

Index merges for queries involving AND


If Oracle performs an index merge (AND-EQUALS in the
execution plan) it may indicate that an appropriate
concatenated index is missing.
Avoid index merges especially if using rule based optimizer

Minimize table lookups in queries

Join Techniques
Sort-merge joins
Sort merge join does not require indexes. Each table is first sorted
on the column values used to join the tables and then merges the
two sorted result set into one.
Nested loops join
Nested loop involves an index on at least one of the table. In this
case a full table scan is done on one table. For every row found a
lookup is performed on the second table (usually the one which is
indexed)
Hash Join
In a hash join, a hash table is constructed for the larger table. The
smaller table is then scanned and the hash table is then used to find
matching rows in the larger table

Using Join Techniques


Use nested loops when only a small subset of the rows
needs to be accessed and an index is available to support
it.
Use sort and hash merge if joining most or all rows of the
tables.
When determining the best join order try to start with the
table which will return the smallest number of rows,
providing that the subsequent tables can be joined
efficiently.

Controlling Joins with Hints


The ORDERED hint tells the optimizer to join the tables in
the exact order in which it appears in the FROM clause.
Use hints like FULL and INDEX.
The hints USE_NL, USE_MERGE and USE_HASH can
force a particular join method.

EXISTS vs IN Clause
An IN subquery is only executed once, while an EXISTS
subquery is executed once per row of parent query.
An IN subquery might not be able to take advantage of
indexes on the subquery table, while EXISTS can.
An EXISTS subquery might not be able to take advantage
of indexes on the parent table, while IN can.
The optimizer sometimes automatically translates IN-based
subqueries into a join.

Anti-joins
When using a rule-based optimizer avoid using NOT IN to
perform anti-joins.
Use NOT EXISTS.
Cost based optimizer treats both equally whereas the rule
based optimizer performs the NOT EXISTS more efficiently
MINUS operators can be used efficiently to perform antijoins if the number and type in each query match.

Sorts
Avoid unnecessary use of DISTINCT.
Use UNION ALL in place of UNION, if the duplicate rows
need not be eliminated.

Aggregate Operations
COUNT(*) goes for a full table scan. However Oracle has
some special optimization for it.
COUNT(0) also goes for a full table scan however is slower
than count(*).
COUNT(fld_name) is faster than the above two if the
fld_name is indexed.
Where ever possible use WHERE to eliminate rows before
grouping. Use HAVING only with group functions.
Try translating an INTERSECT statement into a join.
When performing a MINUS operation consider re-coding it
into an anti-join using HASH_AJ hint.

Optimizing DML (1 of 4)
Optimize WHERE clause.
TRUNCATE tables, if possible, instead of DELETEing them
Indexes add to the overhead of INSERT, UPDATE and DELETE. Avoid
over indexing, specially for columns which are frequently updated.
Use array inserts.
Use SET TRANSACTION options where possible
USE ROLLBACK SEGMENT <segment name>
READ ONLY
Since COMMITing a transaction involves an I/O overhead, COMMIT
infrequently.
Avoid arithmetic calculations in SQL. Perform this work in the program
code.

Optimizing DML (2 of 4)
Retrieve only the columns necessary. Do not use SELECT *.
Specify the fields in an insert statement, even if all fields are inserted.
Always try to use joins instead of sub-queries within queries.
Do not retrieve columns that are used for equal qualification in the
predicate.
Avoid use of NOT (!=, <>, etc.) in the WHERE clause, use BETWEEN, '>='
'<=', or '>' '<'.
Use column names in the ORDER BY clause.
Use ORDER BY only when absolutely necessary and minimize the result
set by using additional constraints in the WHERE clause.

Optimizing DML (3 of 4)
Be careful in the use of GROUP BY. Oracle will sort the
answer set.
Validate requirements for ORDER BY DESCENDING. This
will cause a sort regardless of indexes.
Use DECODE if possible, as it avoids scanning the same
rows repeatedly.
Use appropriate data types in SQL. When using a variable
as a bind variable ensure the data type match. An implicit
type conversion causes an index to be disregarded.
Place the Driving Table at the END of the FROM clause.
Oracle reads the tables from last to first (right to left).

Optimizing DML (4 of 4)
Use ROWID for fast updates:
SELECT rowid, balance
INTO
rid,bal
FROM policy
WHERE policy_num=5;
UPDATE policy
SET balance=10
WHERE rowid=rid;

Thank You

You might also like