Oracle SQL Tuning PDF
Oracle SQL Tuning PDF
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
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
Parse SQL
Bind Variables
Execute SQL
Query?
Close Cursor
Re-execute
Cursor
Close Cursor
Fetch rows
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
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
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
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
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
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]
Operation
Option
Description
Table Access
Paths
TABLE ACCESS
FULL
TABLE ACCESS
BY ROWID
Index
Operations
AND-EQUAL
INDEX
UNIQUE SCAN
INDEX
RANGE SCAN
Operation
Join Operations
CONNECT BY
MERGE JOIN
MERGE JOIN
Option
OUTER
NESTED LOOPS
NESTED LOOPS
Description
OUTER
Operation
Option
Description
Set Operations
CONCATENATION
INTERSECTION
MINUS
UNION
VIEW
Operation
Miscellaneous
FOR UPDATE
FILTER
REMOTE
SEQUENCE
SORT
Option
Description
Operation
Aggregation
COUNT
Option
Description
An operation that counts the
number of rows selected from a
table.
COUNT
STOPKEY
SORT
AGGREGATE
SORT
JOIN
SORT
UNIQUE
SORT
GROUP BY
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;
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;
Queries Involving OR
For queries involving OR condition try using the hints
USE_CONCAT, FULL or INDEX
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
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