SQL Tuning
SQL Tuning
It is pointless to try tuning SQL statements until you fully understand how to measure
performance. To facilitate this measurement, Oracle provides performance metrics that are
available through SQL views. These metrics exist in the form of counters (known
as statistics) and wait times (known as events). In Oracle9i, there are over 200 different
statistics and events. You can see a complete list of names using the following SQL:
The statistics are incremented continually from database startup, beginning at zero, and are
provided databasewide in the V$SYSSTAT view and for individual sessions in the
V$SESSTAT view. The special view V$MYSTAT can also be used to show the statistics for the
currently connected session. The V$SYSSTAT view includes the statistic name from
V$STATNAME, whereas the V$SESSTAT view doesn’t. Identifying statistics for the current
session can be performed using the following SQL:
select st.*,n.name
from v$sesstat st,v$statname n,v$session se
where st.statistic# = n.statistic#
and st.sid=se.sid
and se.audsid = (select userenv(‘sessionid’) from dual);
The wait times behave slightly differently and appear in V$SYSTEM_EVENT and
V$SESSION_EVENT. In order for the event times to appear, the parameter
TIMED_STATISTICS=TRUE must be in place. This can be set in the init.ora file or for
individual sessions using ALTER SESSION SET TIMED_STATISTICS=TRUE. The
recommendation is to always enable the setting at the database level. It incurs a small
performance overhead—one that is so small I’ve never been able to isolate it. Information
on events includes the number of waits as well as wait times. If an event never incurs a
wait, it won’t appear in the relevant view, unlike statistics, which are always present, even if
the value is zero. This SQL shows the wait information for the current session:
select ev.*
from v$session_event ev, v$session se
where ev.sid = se.sid
and se.audsid = (select userenv('sessionid') from dual);
Due to the huge number of metrics that Oracle makes available via SQL, it’s not surprising
that there is such a large number of Oracle performance management tools on the market.
Most tools sample the various statistics over time (and sometimes the wait events), save
the values, and plot graphs of the values over time. When the statistics are available, the
next stage is to understand what they mean, identify the ones that have the most effect on
performance, and take steps to reduce them.
If you do any tuning at all, writing SQL that minimizes or reduces the statistics in Table
9.1 will go a long way toward producing an efficient application that meets end-user
performance requirements with the lowest possible central processing unit (CPU) and I/O
cost. Note that blocks fetched in current mode are those modified by the current session.
For example, during a query, blocks are usually fetched in read-consistent mode. However,
if the current session has modified some of the blocks without a commit (via an insert,
update, or delete), then those blocks are fetched in current mode for the session that made
the changes. This list omits some other statistics that can be useful when analyzing SQL
performance. Some additional statistics are shown in Table 9.2.
Ultimately, the only way you won’t miss any information is to inspect all the statistics that
have changed after the execution of each SQL statement during development. In the same
spirit, Table 9.3 shows the most common event waits and their possible causes from a survey of
several large production databases of various sizes and application types.
Table 9.3: Common Event Waits
Name Cause
buffer busy waits Wait for a buffer to become available, due to a buffer being
read into the cache by another session or a buffer being
held in an incompatible mode because another session is
changing it.
change write item Elapsed redo write time for changes made to current-mode
blocks, in tens of milliseonds.
db file scattered read Wait for a multiblock read on a specified Oracle file and
block, which is often during a full table scan.
db file sequential read Wait for a single block read on a specified Oracle file and
block, which is often during an index lookup or table access
by ROWID.
direct path read Wait for a read that bypasses the buffer cache to complete,
which is often caused by a disk sort or character large
object (CLOB) read.
direct path write Wait for a write that bypasses the buffer cache to complete,
which is often caused by a disk sort.
enqueue Wait for an enqueue (lock) to free, which is sometimes due
to a row-level lock held by another session.
latch free Wait for a latch held by another process to become free
based on the given latch number. Latch names “cache
buffer lru chain” and “cache buffers chains” indicate a busy
buffer cache.
log buffer space Wait for space in log buffer because log writer process
(LGWR) can’t write redo to disk fast enough.
log file switch completion Wait for a log switch to complete.
log file sync Wait for session redo to flush to the redo log file during a
commit.
redo synch writes Elapsed time of all synchrnous writes that take place during
COMMIT operations, in tens of milliseconds.
Wait events have parameters that can provide more information on the nature of the wait.
For example, “latch-free” events identify the number of the latch waiting to be freed. The
related name of the latch can be identified from the V$LATCHNAME view. Enqueue events
can contain information about the object and session holding a row-level lock. Oracle ships
a script called catblock.sql (located in $ORACLE_HOME/rdbms/admin on UNIX systems) to
display a lock dependency tree for the sessions involved. DbCool provides a lock viewer
utility that does the same thing graphically. Oracle’s script requires the creation of
temporary tables to display the tree, and the Data Definition Language (DDL) can cause
further lock contention. DbCool’s lock viewer uses in-memory information only and isn’t
subject to the same restrictions. The parameter information for both the “db file scattered
read” and “db file sequential read” events contains the Oracle file and block that the read
request has waited for.
These file and block values can be decoded into a database object name, as shown in an
example later in the chapter in the section Detecting Full Table Scans. Some events indicate
idle sessions and can generally be ignored. These are shown in Table 9.4.
If a user logs onto a database via SQL*Plus (either locally or via a network connection) and
does nothing, the session remains in a “SQL*Net message from client” state. The view
V$SESSION_WAIT shows the event that each session is waiting for at the time the view was
queried. V$SESSION_WAIT is a good place to start looking for performance problems if
users report that the system is running slow. On a system under
stress, you might expect to see several sessions simultaneously in a non idle wait state.
These are usually waiting on one of the events listed in Table 9.3.