Chapter 6, "Automatic Performance Diagnostics"
Chapter 6, "Automatic Performance Diagnostics"
Chapter 6, "Automatic Performance Diagnostics"
1. Determine which period in the day you would like to examine; typically
this is the application's peak processing time.
2. Gather operating system and Oracle statistics at the beginning and end of
that period. The minimum of Oracle statistics gathered should be file I/O
(V$FILESTAT), system statistics (V$SYSSTAT), and SQL statistics
(V$SQLAREA, V$SQL or V$SQLSTATS, V$SQLTEXT, V$SQL_PLAN,
and V$SQL_PLAN_STATISTICS).
See Also:
3. Using the data collected in step two, identify the SQL statements using
the most resources. A good way to identify candidate SQL statements is to
query V$SQLSTATS. V$SQLSTATS contains resource usage information
for all SQL statements in the shared pool. The data in V$SQLSTATS
should be ordered by resource usage. The most common resources are:
o Buffer gets (V$SQLSTATS.BUFFER_GETS, for high CPU using
statements)
o Disk reads (V$SQLSTATS.DISK_READS, for high I/O statements)
o Sorts (V$SQLSTATS.SORTS, for many sorts)
One method to identify which SQL statements are creating the highest load is to
compare the resources used by a SQL statement to the total amount of that
resource used in the period. For BUFFER_GETS, divide each SQL statement's
BUFFER_GETS by the total number of buffer gets during the period. The total
number of buffer gets in the system is available in the V$SYSSTAT table, for
the statistic session logical reads.
If you are most concerned with CPU, then examine the top SQL statements that
performed the most BUFFER_GETS during that interval. Otherwise, start with
the SQL statement that performed the most DISK_READS.
rather than:
WHERE TO_NUMBER (SUBSTR(a.order_no, INSTR(b.order_no,
'.') - 1))
= TO_NUMBER (SUBSTR(a.order_no, INSTR(b.order_no, '.')
- 1))
Do not use SQL functions in predicate clauses or WHERE clauses. Any expression
using a column, such as a function having the column as its argument, causes
the optimizer to ignore the possibility of using an index on that column, even a
unique index, unless there is a function-based index defined that can be used.
For example:
Also:
When you need to use SQL functions on filters or join predicates, do not use
them on the columns on which you want to have an index; rather, use them on
the opposite side of the predicate, as in the following statement:
TO_CHAR(numcol) = varcol
rather than
varcol = TO_CHAR(numcol)
SQL is not a procedural language. Using one piece of SQL to do many different
things usually results in a less-than-optimal result for each task. If you want SQL
to accomplish different things, then write various statements, rather than writing
one statement to do different things depending on the parameters you give it.
It is always better to write separate SQL statements for different tasks, but if you
must use one SQL statement, then you can make a very complex statement
slightly less complex by using the UNION ALL operator.
Optimization (determining the execution plan) takes place before the database
knows what values will be substituted into the query. An execution plan cannot,
therefore, depend on what those values are. For example:
SELECT info
FROM tables
WHERE ...
AND somecolumn BETWEEN DECODE(:loval, 'ALL',
somecolumn, :loval)
AND DECODE(:hival, 'ALL', somecolumn, :hival);
This is not a problem if there is some other highly selective, indexable condition
you can use to access the driving table. Often, however, this is not the case.
Frequently, you might want to use an index on a condition like that shown but
need to know the values of :loval, and so on, in advance. With this
information, you can rule out the ALL case, which should not use the index.
If you want to use the index whenever real values are given for :loval and
:hival (if you expect narrow ranges, even ranges where :loval often equals
:hival), then you can rewrite the example in the following logically equivalent
form:
If you run EXPLAIN PLAN on the new query, then you seem to get both a
desirable and an undesirable execution plan. However, the first condition the
database evaluates for either half of the UNION ALL is the combined condition
on whether :hival and :loval are ALL. The database evaluates this
condition before actually getting any rows from the execution plan for that part
of the query.
When the condition comes back false for one part of the UNION ALL query, that
part is not evaluated further. Only the part of the execution plan that is optimum
for the values provided is actually carried out. Because the final conditions on
:hival and :loval are guaranteed to be mutually exclusive, only one half of
the UNION ALL actually returns rows. (The ALL in UNION ALL is logically valid
because of this exclusivity. It allows the plan to be carried out without an
expensive sort to rule out duplicate rows for the two halves of the query.)
Note :
You should verify the optimizer cost of the statement with the actual number of
resources used (BUFFER_GETS, DISK_READS, CPU_TIME from
V$SQLSTATS or V$SQLAREA). Situations such as data skew (without the use of
histograms) can adversely affect the optimizer's estimated cost for an operation.
You can influence the optimizer's choices by setting the optimizer approach and
goal, and by gathering representative statistics for the query optimizer.
Sometimes, the application designer, who has more information about a
particular application's data than is available to the optimizer, can choose a more
effective way to execute a SQL statement. You can use hints in SQL statements
to instruct the optimizer about how the statement should be executed.
Join order can have a significant effect on performance. The main objective of
SQL tuning is to avoid performing unnecessary work to access rows that do not
affect the result. This leads to three general rules:
Be careful when joining views, when performing outer joins to views, and when
reusing an existing view for a new purpose.
Beware of writing a view for one purpose and then using it for other purposes to
which it might be ill-suited. Querying from a view requires all tables from the
view to be accessed for the data to be returned. Before reusing a view,
determine whether all tables in the view need to be accessed to return the data.