Sunteți pe pagina 1din 125

Handout: Oracle 10g PL/SQL

Performance Tuning
Version: 10gPERFTUNING/Handout/0708/1.0
Date: 09-07-08

Cognizant
500 Glen Pointe Center West
Teaneck, NJ 07666
Ph: 201-801-0233
www.cognizant.com
Handout – Oracle 10g PL/SQL Performance Tuning

TABLE OF CONTENTS

Introduction .....................................................................................................................................5 
About this Module .........................................................................................................................5 
Target Audience ...........................................................................................................................5 
Module Objectives ........................................................................................................................5 
Pre-requisites................................................................................................................................5 

Session 02: Performance Tuning Overview ................................................................................6 


Learning Objectives ......................................................................................................................6 
Introduction to Performance .........................................................................................................6 
What is Performance Tuning? ......................................................................................................7 
The Symptoms and the Problems ................................................................................................7 
When to Tune ...............................................................................................................................7 
Baselines ......................................................................................................................................8 
Oracle Performance Tuning .........................................................................................................8 
Performance Planning ..................................................................................................................9 
Oracle Instance Tuning ..............................................................................................................10 
SQL Tuning.................................................................................................................................12 
Oracle SQL Tuning Goals ..........................................................................................................13 
Difference in Performance Tuning Between 8i, 9i, and 10g .......................................................14 
Summary ....................................................................................................................................14 
Test Your Understanding............................................................................................................14 

Session 03: Performance Improvement Methods and SQL Parsing .......................................15 


Learning Objectives ....................................................................................................................15 
Introduction .................................................................................................................................15 
Steps in Oracle Performance Improvement Methods ................................................................16 
Top Ten Mistakes Found in Oracle Systems .............................................................................18 
SQL Parsing ...............................................................................................................................19 
Types of Parsing .........................................................................................................................19 
Parsing Process..........................................................................................................................19 
Identical Statements ...................................................................................................................20 
Reduce Hard Parsing .................................................................................................................20 
Summary ....................................................................................................................................21 
Test Your Understanding............................................................................................................22 

Session 04: SQL Performance Tuning .......................................................................................23 


Learning Objectives ....................................................................................................................23 

Page 2
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

What is SQL Tuning? .................................................................................................................23 


Steps in SQL Tuning ..................................................................................................................23 
Developing Efficient SQL Statements ........................................................................................24 
Using Index to Improve the Performance ...................................................................................32 
Oracle SQL Best Practices .........................................................................................................34 
SQL Performance Tuning Tips ...................................................................................................40 
Summary ....................................................................................................................................45 
Test Your Understanding............................................................................................................45 

Session 05: Query Optimizer ......................................................................................................46 


Learning Objectives ....................................................................................................................46 
Introduction .................................................................................................................................46 
Query Optimizer..........................................................................................................................47 
Optimizer Operations ..................................................................................................................47 
Available Optimizers ...................................................................................................................48 
Which Optimizer is best one to use and why? ...........................................................................50 
Optimizer Goal ............................................................................................................................50 
Types of Hints .............................................................................................................................58 
Summary ....................................................................................................................................60 
Test Your Understanding............................................................................................................61 

Session 06: PL/SQL Performance Tuning .................................................................................62 


Learning Objectives ....................................................................................................................62 
When to Tune .............................................................................................................................62 
Reasons for PL/SQL Performance Problems.............................................................................63 
Identifying PL/SQL Performance Problems ................................................................................66 
PL/SQL Features for Performance Tuning .................................................................................72 
PL/SQL Standards and Best Practices ......................................................................................78 
Summary ....................................................................................................................................88 
Test Your Understanding............................................................................................................88 

Session 07: Oracle Performance Tuning Tools ........................................................................89 


Learning Objectives ....................................................................................................................89 
Explain Plan ................................................................................................................................89 
SQL TRACE and TKPROF.........................................................................................................97 
Summary ..................................................................................................................................111 
Test Your Understanding..........................................................................................................112 

Session 08: Oracle 10g Features ..............................................................................................113 

Page 3
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

Learning Objectives ..................................................................................................................113 


Automatic Performance Diagnostics and Tuning Features ......................................................113 
Automatic Database Diagnostics Monitor ................................................................................113 
ADDM Analysis Results ............................................................................................................114 
Automatic SGA Management ...................................................................................................115 
Summary ..................................................................................................................................123 
Test Your Understanding..........................................................................................................123 

References ..................................................................................................................................124 
Websites ...................................................................................................................................124 
Books ........................................................................................................................................124 

STUDENT NOTES: ......................................................................................................................125 

Page 4
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

Introduction

About this Module


This module provides overview on Oracle performance tuning and the various ways
through which performance can be optimized. It also deals with how to identify when to do
performance tuning and how to measure performance.

Target Audience
This module is designed for entry level trainees.

Module Objectives
After completing this module, you will be able to:
‰ Explain the necessity of performance tuning
‰ Identify various symptoms and problems which leads to performance tuning
‰ Identify when the tuning has to be done
‰ List the types of performance tuning

Pre-requisites
This module is designed for the trainees who have a good knowledge in Oracle 10g and
Oracle 10g PL/SQL.

Page 5
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

Session 02: Performance Tuning Overview

Learning Objectives
After completing this session, you will be able to:
‰ Explain performance tuning
‰ State the types of performance tuning
‰ Identify various symptoms which leads to performance tuning
‰ List the goals of tuning

Introduction to Performance
The overall performance of an application is determined by these factors:
‰ How many resources are available?
‰ How many clients need the resource?
‰ How long must they wait for the resource?
‰ How long do they hold the resource?

The following concepts are fundamental to understanding performance:


‰ Response time: Response time is the amount of time between the submission of a
request and the receipt of the response. The response time is equal to the service
time plus the wait time for a task to complete. You can increase response time
performance by reducing the service time, the wait time, or both.
‰ System throughput: System throughput is the amount of work accomplished in a
given amount of time. You can increase throughput with a combination of reducing
service time and reducing the overall response time by increasing the amount of
scarce resources that are available. For example, if the system CPU is bound, then
adding CPU resources should improve performance.
‰ Wait time: While the service time for a task may stay the same, the wait time will
lengthen with increased contention. If many users are waiting for a service that takes
one second, the tenth user must wait nine seconds. Reducing contention should
improve performance.
‰ Critical resources: Resources such as CPU, memory, I/O capacity, and network
bandwidth are the keys to reducing service time. Adding resources increases
throughput and reduces response time.

As the number of requests rises, the time to service completion increases, if the number of
resources stays the same. To improve performance, you can either limit the demand rate to
maintain acceptable response times or you can add resources.

Page 6
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

What is Performance Tuning?


Performance must be built in as the performance tuning cannot be performed optimally after a
system is put into production. To achieve performance targets of response time, throughput, and
constraints you must tune application analysis, design, and implementation. So performance
tuning is all about achieving the performance targets by using a set of predefined techniques and
by following a set of best coding practices.

The Symptoms and the Problems


A common pitfall in performance tuning is to mistake the symptoms of a problem for the actual
problem itself. It is important to recognize that many performance statistics indicate the symptoms,
and that identifying the symptom is not sufficient data to implement a remedy. For example:
‰ Slow physical I/O: Generally, this is caused by poorly-configured disks. However, it
could also be caused by a significant amount of unnecessary physical I/O on those
disks issued by poorly-tuned SQL.
‰ Excessive CPU usage: Excessive CPU usage usually means that there is little idle
CPU on the system. This could be caused by an inadequately-sized system, by
untuned SQL statements, or by inefficient application programs.

When to Tune
There are two distinct types of tuning:
‰ Proactive Monitoring: Proactive monitoring usually occurs on a regularly scheduled
interval, where a number of performance statistics are examined to identify whether
the system behavior and resource usage has changed. Proactive monitoring can also
be considered as proactive tuning.
Usually, monitoring does not result in configuration changes to the system, unless the
monitoring exposes a serious problem. In some situations, experienced performance
engineers can identify potential problems through statistics alone, although
accompanying performance degradation is usual.
Experimenting with or tweaking a system when there is no apparent performance
degradation as a proactive action can be a dangerous activity, resulting in
unnecessary performance drops. Tweaking a system should be considered reactive
tuning, and the steps for reactive tuning should be followed. Monitoring is usually part
of a larger capacity planning exercise, where resource consumption is examined to
see changes in the way the application is being used, and the way the application is
using the database and host resources.
‰ Bottleneck Elimination: Tuning usually implies fixing a performance problem.
However, tuning should be part of the life cycle of an application—through the
analysis, design, coding, production, and maintenance stages. Oftentimes, the tuning
phase is left until the system is in production. At this time, tuning becomes a reactive
fire-fighting exercise, where the most important bottleneck is identified and fixed.
Usually, the purpose for tuning is to reduce resource consumption or to reduce the
elapsed time for an operation to complete. Either way, the goal is to improve the
effective use of a particular resource. In general, performance problems are caused by
the over-use of a particular resource. That resource is the bottleneck in the system.

Page 7
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

There are a number of distinct phases in identifying the bottleneck and the potential fixes.
Remember that the different forms of contention are symptoms that can be fixed by making
changes in the following places:
‰ Changes in the application or the way the application is used
‰ Changes in Oracle
‰ Changes in the host hardware configuration

Often, the most effective way of resolving a bottleneck is to change the application.

Baselines
The most effective way to tune is to have an established performance baseline that can be used
for comparison if a performance issue arises. Most database administrators (DBAs) know their
system well and can easily identify peak usage periods. For example, the peak periods could be
between 10.00 AM and 12.00 PM and also between 1.30 PM and 3.00 PM. This could include a
batch window of 12.00 AM midnight to 6.00 AM. It is important to identify these peak periods at the
site and install a monitoring tool that gathers performance data for those high-load times.
Optimally, data gathering should be configured from when the application is in its initial trial phase
during the QA cycle. Otherwise, this should be configured when the system is first in production.
Ideally, baseline data gathered should include the following:
‰ Application statistics (transaction volumes, response time)
‰ Database statistics
‰ Operating system statistics
‰ Disk I/O statistics
‰ Network statistics

Oracle Performance Tuning


No matter what version of Oracle you are using, the basics of performance tuning remain the
same. Problems can stem from a variety of causes; your job is to figure out the problems. For
example, poorly designed applications and database schemas can cause issues like excessive
CPU consumption due to too many logical I/Os, excessive disk reads due to missing indexes or
excessive contention for shared resources. Fighting the performance war needs to be done quickly
and decisively.

This section provides information on tuning an Oracle Database system for performance. Topics
discussed here include the following:
‰ Performance Planning
‰ Oracle Instance Tuning
‰ SQL Tuning

Page 8
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

Scope of Oracle Tuning:

Performance Planning
Based on years of designing and performance experience, Oracle has designed a performance
methodology. Optimal system performance begins with design and continues throughout the life of
your system. Carefully consider performance issues during the initial design phase, and it will be
easier to tune your system during production. This brief section explains clear and simple activities
that can dramatically improve system performance. It discusses the following topics:
‰ Understanding Investment Options: Performance improvement of a system can be
achieved by adding additional hardware. In many situations, new CPUs, memory, or
more disk drives can indeed provide an immediate performance improvement.
However, any performance increases achieved by adding hardware should be
considered a short-term relief to an immediate problem. If the demand and load rates
on the application continue to grow, then the chance that you will face the same
problem in the near future is very likely. Long-term, it is generally more valuable to
increase the efficiency of your application in terms of the number of physical resources
used for each business transaction.
‰ Understanding Scalability: Scalability is a system’s ability to process more workload,
with a proportional increase in system resource usage. In other words, in a scalable
system, if you double the workload, then the system would use twice as many system
resources. This sounds obvious, but due to conflicts within the system, the resource
usage might exceed twice the original workload. When building applications, designers
and architects should aim for as close to perfect scalability as possible. This is
sometimes called linear scalability, where system throughput is directly proportional to
the number of CPUs.
‰ System Architecture:There are two main parts to a system’s architecture:
o Hardware and Software Components: Today’s designers and architects are
responsible for sizing and capacity planning of hardware at each tier in a multitier
environment. It is the architect's responsibility to achieve a balanced design. The
same way computers have common hardware components, applications have
common functional components. By dividing software development into functional
components, it is possible to better comprehend the application design and
architecture.
o Configuring the right system architecture for your requirements: Configuring
the initial system architecture is a largely iterative process. Architects must satisfy
the system requirements within budget and schedule constraints. If the system
requires interactive users transacting business-making decisions based on the
contents of a database, then user requirements drive the architecture. If there are
few interactive users on the system, then the architecture is process-driven.

Page 9
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

‰ Application Design Principles: These are some of the design principles that are
involved in building applications:
o Simplicity in Application Design
o Data Modeling
o Table and Index Design
o Using Views
o SQL Execution Efficiency
o Implementing the Application
o Trends in Application Development
o Workload Testing, Modeling, and Implementation
o Database Design Principles

The initial design of the Oracle tables and indexes is the single most critical factor in overall
performance and unfortunately, the design can rarely be changed once the system is placed into
production use. So while the tuning techniques you will be discussing can help you maximize the
efficiency of your database engine, bear in mind that the initial design is the most important
performance factor.

When a database is initially analyzed, the designer will often apply the normalization rules
developed by E.F.Codd and C.J.Date. Their normalization study resulted in a set of table
definitions that made it easier to design tables with controlled redundancy.

In the 1970s, database redundancy was difficult and expensive. As a result, database designers
were taught to create databases in Third Normal Form (3NF), which prevented data duplication in
multiple tables. But although a 3NF database was totally free of redundancy, the database queries
could run very slowly because of the extra navigation required to access information. Over the
1980s and 1990s, database designers became more liberal with the introduction of redundant data
to speed database queries.

Oracle Instance Tuning


‰ Introduction to an Oracle Instance: Every running Oracle database is associated
with an Oracle instance. When a database is started on a database server (regardless
of the type of computer), Oracle allocates a memory area called the System Global
Area (SGA) and starts one or more Oracle processes. This combination of the SGA
and the Oracle processes is called an Oracle instance. The memory and processes of
an instance manage the associated database’s data efficiently and serve the one or
multiple users of the database.

Page 10
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

After starting an instance, Oracle associates the instance with the specified database. This is
called mounting the database. The database is then ready to be opened, which makes it
accessible to authorized users. Only the database administrator can start up an instance and open
the database. If a database is open, the database administrator can shut down the database so
that it is closed. When a database is closed, users cannot access the information that it contains.

Security for database startup and shutdown is controlled through connections to Oracle with
administrator privileges. Normal users do not have control over the current status of an Oracle
database.

Instance Tuning
This instance-tuning phase of Oracle tuning examines the overall database and the instance-wide
parameters that affect performance.

With many hundreds of Oracle initialization parameters, it is important to focus on those


parameters that have the most impact on the performance of the Oracle database. Oracle has a
huge number of parameters in the Oracle initialization files (init.ora) that control the overall
configuration of the Oracle instance. While there are dozens of init.ora parameters that affect
performance, these are some of the most important:
‰ shared_pool_size: The memory region allocated for the library cache and internal
control structures
‰ db_block_size: The size of each data block
‰ db_block_buffers: The number of data buffers to allocate for the instance
‰ sort_area_size: The amount of RAM reserved for each user to perform sorting
operations
‰ optimizer_mode: The default mode in which all SQL statements will be optimized for
an execution plan
‰ db_file_multiblock_read_count: The parameter that controls the number of blocks
that are read asynchronously in full-table scan operations

Page 11
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

You have to remember that all Oracle instances are generally constrained by I/O operations. I/O is
the single most dramatic component of Oracle performance, and any initialization parameters that
can be used in order to reduce I/O will improve the performance of the database.

For example, the db_block_size and db_block_buffers (later renamed db_cache_size,


db_nnk_cache_size, &c) initialization parameters are very important in terms of reducing I/O.
As a general rule, the larger the Oracle block size, the more the database can read in a single disk
I/O and there will be less I/O contention in the system.

SQL Tuning
An important facet of database system performance tuning is the tuning of SQL statements. SQL
tuning involves three basic steps:
‰ Identifying high load or top SQL statements that are responsible for a large share of
the application workload and system resources, by reviewing past SQL execution
history available in the system.
‰ Verifying that the execution plans produced by the query optimizer for these
statements perform reasonably.
‰ Implementing corrective actions to generate better execution plans for poorly
performing SQL statements.

These three steps are repeated until the system performance reaches a satisfactory level or no
more statements can be tuned.

Many client/server application programmers consider SQL a messaging language, because


queries are issued and data is returned. However, client tools often generate inefficient SQL
statements. Therefore, a good understanding of the database SQL processing engine is necessary
for writing optimal SQL. This is especially true for high transaction processing systems.

Typically, SQL statements issued by OLTP applications operate on relatively few rows at a time. If
an index can point to the exact rows that are required, then Oracle can construct an accurate plan
to access those rows efficiently through the shortest possible path. In decision support system
(DSS) environments, selectivity is less important, because they often access most of a table's
rows. In such situations, full table scans are common, and indexes are not even used.

Query Optimizer and Execution Plans


When a SQL statement is executed on an Oracle database, the Oracle query optimizer determines
the most efficient execution plan after considering many factors related to the objects referenced
and the conditions specified in the query. This determination is an important step in the processing
of any SQL statement and can greatly affect execution time.

During the evaluation process, the query optimizer reviews statistics gathered on the system to
determine the best data access path and other considerations. You can override the execution
plan of the query optimizer with hints inserted in SQL statement.

Page 12
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

Oracle SQL Tuning Goals


The objective of tuning a system is either to reduce the response time for end users of the system,
or to reduce the resources used to process the same work. You can accomplish both of these
objectives in several ways as follows:

Reduce the Workload: SQL tuning commonly involves finding more efficient ways to process the
same workload. It is possible to change the execution plan of the statement without altering the
functionality to reduce the resource consumption.

Two examples of how resource usage can be reduced are as follows:


‰ If a commonly executed query needs to access a small percentage of data in the
table, then it can be executed more efficiently by using an index. By creating such an
index, you reduce the amount of resources used.
‰ If a user is looking at the first twenty rows of the 10,000 rows returned in a specific sort
order, and if the query (and sort order) can be satisfied by an index, then the user
does not need to access and sort the 10,000 rows to see the first 20 rows.

Balance the Workload: Systems often tend to have peak usage in the daytime when real users
are connected to the system and low usage in the nighttime. If noncritical reports and batch jobs
can be scheduled to run in the nighttime and their concurrency during day time reduced, then it
frees up resources for the more critical programs in the day.

Parallelize the Workload: Queries that access large amounts of data (typical data warehouse
queries) often can be parallelized. This is extremely useful for reducing the response time in low
concurrency data warehouse. However, for OLTP environments, which tend to be high
concurrency, this can adversely, impact other users by increasing the overall resource usage of
the program.

The goals of SQL tuning focus on improving the execution plan to fetch the rows with the smallest
number of database "touches",
‰ Remove unnecessary large-table full-table scans: Unnecessary full-table scans
cause a huge amount of unnecessary I/O and can drag-down an entire database. The
tuning expert first evaluates the SQL based on the number of rows returned by the
query. If the query returns less than 40 percent of the table rows, it needs tuning. The
most common tuning remedy for unnecessary full-table scans is adding indexes.
Standard b-tree indexes can be added to tables, and bitmapped and function-based
indexes can also eliminate full-table scans. In some cases, an unnecessary full-table
scan can be forced to use an index by adding an index hint to the SQL statement.
‰ Cache small-table full-table scans: In cases where a full-table scan is the fastest
access method, the administrator should ensure that a dedicated data buffer is
available for the rows. In Oracle7, you can issue "alter table xxx cache". In Oracle8
and beyond, the small table can be cached by forcing it into the KEEP pool.
‰ Verify optimal index usage: This is especially important when using the rule-based
optimizer. Oracle sometimes has a choice of indexes, and the tuning professional
must examine each index and ensure that Oracle is using the proper index.

Page 13
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

‰ Materialize your aggregations and summaries for static tables: One features of
the Oracle 10g SQL Access advisor is recommendations for new indexes and
suggestions for materialized views. Materialized views pre-join tables and pre-
summarize data, a real silver bullet for data mart reporting databases where the data
is only updated daily.

Difference in Performance Tuning Between 8i, 9i, and 10g


Each release of Oracle has introduced features and behaviors that are intended to process SQL
more efficiently and to allow better control over performance. The basic principles, however,
remain the same: design to maximize scalability by reducing latching and locking to a minimum;
consider all options for object implementation; and compare test results for different approaches
before making a decision on production implementation.

Summary
‰ Oracle experts generally use a top-down approach for tuning.
‰ Performance tuning are of two types:
o Proactive monitoring
o Bottleneck elimination
‰ SQL tuning targeting factors are as follows:
o Reduce the workload
o Balance the workload
o Parallelize the workload

Test Your Understanding


1. What is performance tuning?
2. What are the performance tuning parameters?
3. What is response time?
4. What are the different types of tuning?
5. Explain the goals of tuning.

Page 14
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

Session 03: Performance Improvement Methods and SQL


Parsing

Learning Objectives
After completing this session, you will be able to:
‰ List various methods involved in performance improvement
‰ Identify top ten mistakes found in Oracle systems
‰ Define SQL parsing
‰ Explain the enforcing of soft parsing
‰ List the steps in the tuning process
‰ Identify the types of parsing.
‰ Explain the SQL parsing process
‰ State the tips for reducing hard parsing

Introduction
Oracle performance methodology helps you to pinpoint performance problems in your Oracle
system. This involves identifying bottlenecks and fixing them. Performance improvement, by its
nature, is iterative. For this reason, removing the first bottleneck might not lead to performance
improvement immediately, because another bottleneck might be revealed. Also, in some cases, if
serialization points move to a more inefficient sharing mechanism, then performance could
degrade. With experience, and by following a rigorous method of bottleneck elimination,
applications can be debugged and made scalable.

Performance problems generally result from either a lack of throughput, unacceptable user/job
response time, or both. The problem might be localized between application modules, or it might
be for the entire system. Before looking at any database or operating system statistics, it is crucial
to get feedback from the most important components of the system: the users of the system and
the people ultimately paying for the application.

Typical user feedback includes statements like the following:


‰ "The online performance is so bad that it prevents my staff from doing their jobs."
‰ "The billing run takes too long."
‰ "When I experience high amounts of Web traffic, the response time becomes
unacceptable, and I am losing customers."
‰ "I am currently performing 5000 trades a day, and the system is maxed out. Next
month, you roll out to all our users, and the number of trades is expected to
quadruple."

Page 15
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

The Oracle performance improvement method can be applied until performance goals are met. It
takes time and experience to develop the necessary skills to accurately pinpoint critical bottlenecks
in a timely manner. Today's systems are so different and complex that hard and fast rules for
performance analysis cannot be made. In essence, the Oracle performance improvement method
defines a way of working, but not a definitive set of rules. With bottleneck detection, the only rule is
that there are no rules! The best performance engineers use the data provided and think laterally
to determine performance problems.

Steps in Oracle Performance Improvement Methods


‰ Perform the following initial standard checks:
o Get feedback from users. Determine the performance project’s scope and
subsequent performance goals, as well as performance goals for the future. This
process is the key in future capacity planning.
o Get a full set of operating system, database, and application statistics from the
system when the performance is both good and bad. If these are not available,
then get whatever is available.
o Sanity-check the operating systems of all machines involved with user
performance. By sanity-checking the operating system, you look for hardware or
operating system resources that are fully utilized. List any over-used resources as
symptoms for analysis later. In addition, check that all hardware shows no errors
or diagnostics.
‰ Check for the top ten most common mistakes with Oracle, and determine if any of
these are likely to be the problem. List these as symptoms for later analysis.
‰ Build a conceptual model of what is happening on the system using the symptoms as
clues to understand what caused the performance problems.
‰ Propose a series of remedy actions and the anticipated behavior to the system, then
apply them in the order that can benefit the application the most. A golden rule in
performance work is that you only change one thing at a time and then measure the
differences. Unfortunately, system downtime requirements might prohibit such a
rigorous investigation method. If multiple changes are applied at the same time, then
try to ensure that they are isolated so that the effects of each change can be
independently validated.
‰ Validate that the changes made have had the desired effect, and see if the user's
perception of performance has improved. Otherwise, look for more bottlenecks, and
continue refining the conceptual model until your understanding of the application
becomes more accurate.
‰ Repeat the last three steps until performance goals are met or become impossible due
to other constraints.

This method identifies the biggest bottleneck and uses an objective approach to performance
improvement. The focus is on making large performance improvements by increasing application
efficiency and eliminating resource shortages and bottlenecks. In this process, it is anticipated that
minimal (less than 10%) performance gains are made from instance tuning, and large gains (100%
+) are made from isolating application inefficiencies.

Page 16
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

A sample decision process for performance conceptual modeling


Conceptual modeling is almost deterministic. However, as your performance tuning experience
increases, you will appreciate that there are no real rules to follow. A flexible heads-up approach is
required to interpret the various statistics and make good decisions. For a quick and easy
approach to performance tuning, use the Automatic Database Diagnostic Monitor (ADDM). ADDM
automatically monitors your Oracle system and provides recommendations for solving
performance problems should problems occur.

The Automatic Database Diagnostic Monitor (ADDM) analyzes data in the Automatic Workload
Repository (AWR) to identify potential performance bottlenecks. For each of the identified issues it
locates the root cause and provides recommendations for correcting the problem. An ADDM
analysis task is performed and its findings and recommendations stored in the database every
time an AWR snapshot is taken provided the STATISTICS_LEVEL parameter is set to TYPICAL
or ALL. The ADDM analysis includes the following:
‰ CPU load
‰ Memory usage
‰ I/O usage
‰ Resource intensive SQL
‰ Resource intensive PL/SQL and Java
‰ RAC issues
‰ Application issues
‰ Database configuration issues
‰ Concurrency issues
‰ Object contention

For example, suppose a DBA receives a call from a user complaining that the system is slow. The
DBA simply examines the latest ADDM report to see which of the recommendations should be
implemented to solve the problem. The following steps illustrate how a performance engineer
might look for bottlenecks without using automatic diagnostic features. These steps are only
intended as a guideline for the manual process.

With experience, performance engineers add to the steps involved. This analysis assumes that
statistics for both the operating system and the database have been gathered.
1. Is the response time/batch run time acceptable for a single user on an empty or lightly
loaded machine?

If it is not acceptable, then the application is probably not coded or designed optimally, and
it will never be acceptable in a multiple user situation when system resources are shared.
In this case, get application internal statistics, and get SQL Trace and SQL plan
information. Work with developers to investigate problems in data, index, transaction SQL
design, and potential deferral of work to batch/background processing.
2. Is all the CPU being utilized?

If the kernel utilization is over 40%, then investigate the operating system for network
transfers, paging, swapping, or process thrashing. Otherwise, move onto CPU utilization in
user space. Check to see if there is any non-database jobs consuming CPU on the
machine limiting the amount of shared CPU resources, such as backups, file transforms,
print queues, and so on. After determining that the database is using most of the CPU,

Page 17
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

investigate the top SQL by CPU utilization. These statements form the basis of all future
analysis. Check the SQL and the transactions submitting the SQL for optimal execution.
Oracle provides CPU statistics in V$SQL and V$SQLSTATS.
If the application is optimal and there are no inefficiencies in the SQL execution, consider
rescheduling some work to off-peak hours or using a bigger machine.
3. At this point, the system performance is unsatisfactory, yet the CPU resources are not fully
utilized.

In this case, you have serialization and unscalable behavior within the server. Get the
WAIT_EVENTS statistics from the server, and determine the biggest serialization point. If
there are no serialization points, then the problem is most likely outside the database, and
this should be the focus of investigation. Elimination of WAIT_EVENTS involves modifying
application SQL and tuning database parameters. This process is very iterative and
requires the ability to drill down on the WAIT_EVENTS systematically to eliminate
serialization points.

Top Ten Mistakes Found in Oracle Systems


This section lists the most common mistakes found in Oracle systems. By following the Oracle
performance improvement methodology, you should be able to avoid these mistakes altogether.
‰ Bad connection management: The application connects and disconnects for each
database interaction. This problem is common with stateless middleware in application
servers. It has over two orders of magnitude impact on performance, and is totally
unscalable.
‰ Bad use of cursors and the shared pool: Not using cursors results in repeated
parses. If bind variables are not used, then there is hard parsing of all SQL
statements. This has an order of magnitude impact in performance, and it is totally
unscalable. Use cursors with bind variables that open the cursor and execute it many
times. Be suspicious of applications generating dynamic SQL.
‰ Bad SQL: Bad SQL is SQL that uses more resources than appropriate for the
application requirement. This can be a decision support systems (DSS) query that
runs for more than 24 hours or a query from an online application that takes more than
a minute. SQL that consumes significant system resources should be investigated for
potential improvement. ADDM identifies high load SQL and the SQL tuning advisor
can be used to provide recommendations for improvement.
‰ Use of non-standard initialization parameters: These might have been
implemented based on poor advice or incorrect assumptions. Most systems will give
acceptable performance using only the set of basic parameters. In particular,
parameters associated with SPIN_COUNT on latches and undocumented optimizer
features can cause a great deal of problems that can require considerable
investigation.
Likewise, optimizer parameters set in the initialization parameter file can override
proven optimal execution plans. For these reasons, schemas, schema statistics, and
optimizer settings should be managed together as a group to ensure consistency of
performance.
‰ Getting database I/O Wrong: Many sites lay out their databases poorly over the
available disks. Other sites specify the number of disks incorrectly, because they
configure disks by disk space and not I/O bandwidth.

Page 18
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

‰ REDO log setup problems: Many sites run with too few redo logs that are too small.
Small redo logs cause system checkpoints to continuously put a high load on the
buffer cache and I/O system. If there are too few redo logs, then the archive cannot
keep up, and the database will wait for the archive process to catch up.
‰ Serialization of data blocks in the buffer cache due to lack of free lists, free list
groups, transaction slots (INITRANS), or shortage of rollback segments: This is
particularly common on INSERT-heavy applications, in applications that have raised
the block size above 8K, or in applications with large numbers of active users and few
rollback segments. Use automatic segment-space management (ASSM) to and
automatic undo management solves this problem.
‰ Long full table scans: Long full table scans for high-volume or interactive online
operations could indicate poor transaction design, missing indexes, or poor SQL
optimization. Long table scans, by nature, are I/O intensive and unscalable.
‰ High amounts of recursive (SYS) SQL: Large amounts of recursive SQL executed
by SYS could indicate space management activities, such as extent allocations, taking
place. This is unscalable and impacts user response time. Use locally managed
tablespaces to reduce recursive SQL due to extent allocation. Recursive SQL
executed under another user Id is probably SQL and PL/SQL, and this is not a
problem.
‰ Deployment and migration errors: In many cases, an application uses too many
resources because the schema owning the tables has not been successfully migrated
from the development environment or from an older implementation. Examples of this
are missing indexes or incorrect statistics. These errors can lead to sub-optimal
execution plans and poor interactive user performance.

SQL Parsing
Whenever a statement is executed, Oracle follows a methodology to evaluate the statement in
terms of syntax, validity of objects being referred and of course, privileges to the user. Apart from
this, Oracle also checks for identical statements that may have been fired, with the intention of
reducing processing overheads. All this takes place in a fraction of a second, even less, without
the user knowing what is happening to the statement that was fired. This process is known as
Parsing.

Types of Parsing
All statements, DDL or DML, are parsed whenever they are executed. The only key fact is that
whether it was a Soft (statement is already parsed and available in memory) or a Hard (all parsing
steps to be carried out) parse. Soft parse will considerably improve the system performance where
as frequent Hard parsing will affect the system. Reducing hard parsing will improve the resource
utilization and optimize the SQL code.

Parsing Process
Oracle internally does the following to arrive at the output of an SQL statement.
‰ Syntactical check. The query fired is checked for its syntax.
‰ Semantic check. Checks on the validity of the objects being referred in the statement
and the privileges available to the user firing the statement. This is a data dictionary
check.
‰ Allocation of private SQL area in the memory for the statement.

Page 19
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

‰ Generating a parsed representation of the statement and allocating Shared SQL area.
This involves finding an optimal execution path for the statement.

In point four, Oracle first checks if the same statement is already parsed and existing in the
memory. If found the parsed representation will be picked up and the statement executed
immediately (Soft parse). If not found, then the parsed representation is generated and stored in a
shared SQL area (Part of shared pool memory in SGA), the statement is then executed (Hard
parse). This step involves the optimization of the statement, the one that decides the performance.

Identical Statements
Oracle does the following to find identical statements to decide on a soft or a hard parse.
‰ When a new statement is fired, a hash value is generated for the text string. Oracle
checks if this new hash value matches with any existing hash value in the shared pool.
‰ Next, the text string of the new statement is compared with the hash value matching
statements. This includes comparison of case, blanks and comments present in the
statements.
‰ If a match is found, the objects referred in the new statement are compared with the
matching statement objects. Tables of the same name belonging to different a schema
will not account for a match.
‰ The bind variable types of the new statement should be of same type as the identified
matching statement.
‰ If all of the above is satisfied, Oracle re-uses the existing parse (soft). If a match is not
found, Oracle goes through the process of parsing the statement and putting it in the
shared pool (hard).

Reduce Hard Parsing


The shared pool memory can be increased when contention occurs, but more important is that
such issues should be addressed at the coding level. Following are some initiatives that can be
taken to reduce hard parsing.
‰ Make use of bind variables rather than hard-coding values in your statements.
‰ Write generic routines that can be called from different places. This will also eliminate
code repetition.
‰ Even with stringent checks, it may so happen that same statements are written in
different formats. Search the SQL area periodically to check on similar queries that are
being parsed separately. Change these statements to be look-alike or put them in a
common routine so that a single parse can take care of all calls to the statement
Writing efficient SQL statements requires experience. You can write a SQL query in many different
ways, each giving the same result, but one may be a hundred times slower than another. In this
topic, you discuss some tips and techniques that will help you write efficient SQL statements.
SELECT DEPTNO, AVG_SAL FROM EMP_AGG WHERE DEPTNO = 10;

Collection types and object types increase your productivity by allowing for realistic data modeling.
Complex real-world entities and relationships map directly into object types. A well-constructed
object model can improve application performance by eliminating table joins, reducing round trips,
and the like.
‰ %TYPE: For scalar structures

Page 20
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

‰ %rowtype: For composite structures

Identifying unnecessary parse calls at system level


select parse_calls, executions,
substr(sql_text, 1, 300)
from v$sqlarea
where command_type in (2, 3, 6, 7);

Check for statements with a lot of executions. It is bad to have the PARSE_CALLS value in the
above statement close to the EXECUTIONS value. The above query will fire only for DML
statements (to check on other types of statements use the appropriate command type number).
Also ignore Recursive calls (dictionary access), as it is internal to Oracle.

Identifying unnecessary parse calls at session level


select b.sid, a.name, b.value
from v$sesstat b, v$statname a
where a.name in ('parse count (hard)', 'execute count')
and b.statistic# = a.statistic#
order by sid;

Identify the sessions involved with a lot of re-parsing (VALUE column).


Query these sessions from V$SESSION and then locate the program that is being executed,
resulting in so much parsing.
select a.parse_calls, a.executions, substr(a.sql_text, 1, 300)
from v$sqlarea a, v$session b
where b.schema# = a.parsing_schema_id
and b.sid = <:sid>
order by 1 desc;

The earlier query will also show recursive SQL being fired internally by Oracle.

Summary
‰ Steps in performance tuning methods are as follows:
o Get feedback from users.
o Gather the complete statistics of the system.
o Sanity-check the operating systems of all machines involved.
o Check for the existence of Oracle top ten mistakes in your system.
o Build a conceptual model of the system depending on the symptoms.
‰ SQL parser is a component of SQL compiler. It checks for correctness of syntax for
the executed query.
‰ Three stages of processing an SQL query are as follows:
o Parsing
o Executing
o Fetching

Page 21
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

Test Your Understanding


1. What is performance improvement?
2. Explain the steps in performance improvement method.
3. What are the top mistakes found in oracle systems?
4. What is SQL Parsing?
5. What are the types of SQL parsing?
6. What are the ways of reducing hard parsing?

Page 22
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

Session 04: SQL Performance Tuning

Learning Objectives
After the completion of this session, you would be able to:
‰ Define SQL Tuning
‰ Write effective SQL statements
‰ List the best practices to be followed while writing SQL
‰ Identify Oracle SQL performance tuning tips

What is SQL Tuning?


SQL tuning is the process of tuning the SQL statements that access the database. These SQL
statements include database queries and transactional operations such as inserts, updates, and
deletes. The objective of SQL statement tuning is to formulate statements that most effectively
access the database in its current state, taking advantage of database and system resources and
indexes.

Steps in SQL Tuning


An important facet of database system performance tuning is the tuning of SQL statements. SQL
tuning involves three basic steps:
‰ Identifying high load or long running SQL statements that are responsible for a large
share of the application workload and system resources, by reviewing past SQL
execution history available in the system.
o Identify Bad SQL: Use the following SQL*Plus commands to identify statements
using, on average, more than 3,000 disk reads (10 seconds' worth) per execution:
column "Response" format 999,999,999.99;
column nl newline;

ttitle 'SQL With Disk Reads > 10 Seconds'

SELECT sql_text nl, 'Executions='||


executions nl,
'Expected Response Time in Seconds= ',
disk_reads / decode(executions, 0, 1,
executions) / 300
"Response"
FROM v$sql
WHERE disk_reads / decode(executions,0,1, executions)
/ 300 > 10
AND executions > 0
ORDER BY hash_value, child_number;

Page 23
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

Identify Long-Running SQL Statements

Oracle8i and later has a great feature that stores information on long-running queries currently
active in the V$SESSION_LONGOPS view.

The following example shows the results of a query against V$SESSION_LONGOPS:


SELECT username, sql_text, sofar, totalwork, units

FROM v$sql, v$session_longops

WHERE sql_address=address
AND sql_hash_value=hash_value
ORDER BY address, hash_value, child_number
‰ Verifying that the execution plans produced by the query optimizer for these
statements perform reasonably.
‰ Implementing corrective actions to generate better execution plans for poorly
performing SQL statements.

These three steps are repeated until the system performance reaches a satisfactory level or no
more statements can be tuned.

Developing Efficient SQL Statements


EXISTS is preferable to DISTINCT: The DISTINCT keyword used in a SELECT clause eliminates
duplicate rows in the result set. To eliminate those duplicates, Oracle performs a sort, and that sort
requires time and disk space. Therefore, avoid using DISTINCT if you can tolerate having
duplicate rows returned by a query. If you cannot tolerate the duplicate rows or your application
can not handle them, then use EXISTS in place of DISTINCT.

For example, assume you are trying to find the names of customers who have orders. Your query
has to be based on two tables: CUSTOMER and CUST_ORDER. Using DISTINCT, your query would
be written as follows:
SELECT DISTINCT C.CUST_NBR, C.NAME
FROM CUSTOMER C, CUST_ORDER O
WHERE C.CUST_NBR = O.CUST_NBR;

The corresponding execution plan for this query is as follows. Note the SORT operation, which is a
result of DISTINCT being used.

Query Plan
-----------------------------------------
SELECT STATEMENT Cost = 3056
SORT UNIQUE
MERGE JOIN
INDEX FULL SCAN IND_ORD_CUST_NBR
SORT JOIN

Page 24
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

TABLE ACCESS FULL CUSTOMER

To use EXISTS, the query needs to be rewritten as follows:


SELECT C.CUST_NBR, C.NAME
FROM CUSTOMER C
WHERE EXISTS (SELECT 1 FROM CUST_ORDER O WHERE C.CUST_NBR = O.CUST_NBR);

Here is the execution plan for the EXISTS version of the query. Look at the cost of this query
versus the earlier DISTINCT query, and notice the performance improvement.
Query Plan
---------------------------------------
SELECT STATEMENT Cost = 320
FILTER
TABLE ACCESS FULL CUSTOMER
INDEX RANGE SCAN IND_ORD_CUST_NBR

The version of the query using EXISTS is less than one-ninth as costly as the version using
DISTINCT. This is because the sort has been avoided.

EXISTS Versus IN
The following query uses IN to delete the orders for customers in region 5:

DELETE FROM CUST_ORDER


WHERE CUST_NBR IN
(SELECT CUST_NBR FROM CUSTOMER
WHERE REGION_ID = 5);

The execution plan for this query is as follows:


Query Plan
------------------------------------
DELETE STATEMENT Cost = 3
DELETE CUST_ORDER
HASH JOIN
TABLE ACCESS FULL CUST_ORDER
TABLE ACCESS FULL CUSTOMER

Now, let's look at that same query, written using EXISTS:


DELETE FROM CUST_ORDER
WHERE EXISTS
(SELECT CUST_NBR FROM CUSTOMER
WHERE CUST_ORDER.CUST_NBR = CUSTOMER.CUST_NBR
AND REGION_ID = 5);

Page 25
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

The execution plan for the EXISTS version of the query is as follows:

Query Plan
--------------------------------------------
DELETE STATEMENT Cost = 1
DELETE CUST_ORDER
FILTER
TABLE ACCESS FULL CUST_ORDER
TABLE ACCESS BY INDEX ROWID CUSTOMER
INDEX UNIQUE SCAN CUSTOMER_PK

Notice the cost difference between the two queries. The IN version of the query has a cost of 3,
while the EXISTS version of the query has a cost of only 1. When the EXISTS clause is used, the
execution plan is driven by the outer table, whereas when the IN clause is used, the execution plan
is driven by the table in the subquery. The EXISTS query will almost always be faster than the IN
query, except for cases when the table in the subquery has very few rows as compared to the
outer table.

WHERE versus HAVING


When writing a GROUP BY query, you have a condition that you can specify in either the WHERE
clause or the HAVING clause. In situations where you have a choice, you will always get better
performance if you specify the condition in the WHERE clause. The reason is that it's less expensive
to eliminate rows before they are summarized than it is to eliminate results after summarization.

Let's look at an example illustrating the advantage of WHERE over HAVING. Here is a query with the
HAVING clause that reports the number of orders in the year 2000:
SELECT YEAR, COUNT(*) FROM ORDERS
GROUP BY YEAR HAVING YEAR = 2000;

YEAR COUNT(*)
------ --------
2000 720

The execution plan for this query is as follows:


Query Plan
-------------------------------------------
SELECT STATEMENT Cost = 6
FILTER
SORT GROUP BY
INDEX FAST FULL SCAN ORDERS_PK

Page 26
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

Now, look at that same query, but with the year restriction in the WHERE clause:
SELECT YEAR, COUNT(*) FROM ORDERS
WHERE YEAR = 2000 GROUP BY YEAR;

YEAR COUNT(*)
----- --------
2000 720

The execution plan for this version of the query is as follows:


Query Plan
-------------------------------------
SELECT STATEMENT Cost = 2
SORT GROUP BY NOSORT
INDEX FAST FULL SCAN ORDERS_PK

With the HAVING clause, the query performs the group operation first, and then filters the groups
for the condition specified. The WHERE clause version of the query filters the rows before
performing the group operation. The result of filtering with the WHERE clause is that there are fewer
rows to summarize, and consequently the query performs better.

However, you should note that not all types of filtering can be achieved using the WHERE clause.
Sometimes, you may need to summarize the data first, and then filter the summarized data based
upon the summarized values. In such situations, you have to filter using the HAVING clause,
because only the HAVING clause can "see" summarized values. Moreover, there are situations
when you may need to use the WHERE clause and the HAVING clause together in a query to filter
the results the way you want.

UNION versus UNION ALL


UNION ALL combines the results of two SELECT statements. UNION combines the results of two
SELECT statements, and then returns only distinct rows from the combination; duplicates are
eliminated. It is, therefore, obvious that to remove the duplicates, UNION performs one extra step
than UNION ALL. This extra step is a sort, which is costly in terms of performance. Therefore,
whenever your application can handle duplicates or you are certain that no duplicates will result,
consider using UNION ALL instead of UNION.

Let's look an example to understand this issue better. The following query uses UNION to return a
list of orders where the sale price exceeds $50.00 or where the customer is located in region 5:
SELECT ORDER_NBR, CUST_NBR FROM CUST_ORDER WHERE SALE_PRICE > 50
UNION
SELECT ORDER_NBR, CUST_NBR FROM CUST_ORDER
WHERE CUST_NBR IN
(SELECT CUST_NBR FROM CUSTOMER WHERE REGION_ID = 5);

Page 27
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

ORDER_NBR CUST_NBR
----------------- ----------------
1000 1
1001 1
1002 5
1003 4
1004 4
1005 8
1006 1
1007 5
1008 5
1009 1

10 rows selected.

The execution plan for this UNION query is as follows:


Query Plan
--------------------------------------------------------------------
SELECT STATEMENT Cost = 8
SORT UNIQUE
UNION-ALL
TABLE ACCESS FULL CUST_ORDER
HASH JOIN
TABLE ACCESS FULL CUSTOMER
TABLE ACCESS FULL CUST_ORDER

The following query uses UNION ALL instead of UNION to get the same information:
SELECT ORDER_NBR, CUST_NBR FROM CUST_ORDER WHERE SALE_PRICE > 50
UNION ALL
SELECT ORDER_NBR, CUST_NBR FROM CUST_ORDER
WHERE CUST_NBR IN
(SELECT CUST_NBR FROM CUSTOMER WHERE REGION_ID = 5);

ORDER_NBR CUST_NBR
-------------------- ------------------
1001 1
1003 4
1005 8
1009 1
1012 1
1017 4
1021 8
1029 1
1001 1

Page 28
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

1000 1
1002 5
1003 4
1004 4
1006 1
1007 5
1008 5

16 rows selected.

Note the duplicate rows in the output. However, note also that UNION ALL performs better than
UNION, as you can see from the following execution plan:
Query Plan
------------------------------------------------------------------------
SELECT STATEMENT Cost = 4
UNION-ALL
TABLE ACCESS FULL CUST_ORDER
HASH JOIN
TABLE ACCESS FULL CUSTOMER
TABLE ACCESS FULL CUST_ORDER

Compare this execution plan with its cost of 4 with the previous plan and its cost of 8. You can see
that the extra operation (SORT UNIQUE) in the UNION makes it run slower than UNION ALL.

Using Bind Variables


When multiple users use an application, they actually execute the same set of SQL statements
over and over, but with different data values. For example, one customer service representative
may be executing the following statement:
SELECT * FROM CUSTOMER WHERE CUST_NBR = 121;

While another customer service representative will be executing:


SELECT * FROM CUSTOMER WHERE CUST_NBR = 328;

These two statements are similar, but not "identical"—the customer ID numbers are different,
therefore Oracle has to parse twice.

As the only difference between these statements is the value used for the customer number, this
application could be rewritten to use bind variables. In that case, the SQL statement in question
could be as follows:
SELECT * FROM CUSTOMER WHERE CUST_NBR = :X;
Oracle needs to parse this statement only once. The actual customer numbers would be supplied
after parsing for each execution of the statement. Multiple, concurrently executing programs could
share the same copy of this SQL statement while at the same time supplying different customer
number values.

Page 29
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

In a multi-user application, situations such as the one described here are very common, and
overall performance can be significantly improved by using bind variables, thereby reducing
unnecessary parsing.

Using Table Aliases


The use of table aliases can help to improve the performance of your SQL statements. Before
getting into the performance aspects of table aliases, let's quickly review what table aliases are
and how they are used.

When you select data from two or more tables, you should specify which table each column
belongs to. Otherwise, if the two tables have columns with the same name, you will end up with an
error:
SELECT CUST_NBR, NAME, ORDER_NBR
FROM CUSTOMER, CUST_ORDER;

SELECT CUST_NBR, NAME, ORDER_NBR


*
ERROR at line 1:
ORA-00918: column ambiguously defined

The error in this case occurs because both the CUSTOMER and CUST_ORDER tables have columns
named CUST_NBR. Oracle cannot tell which CUST_NBR column you are referring to. To fix this
problem, you could rewrite this statement as follows:
SELECT CUSTOMER.CUST_NBR, CUSTOMER.NAME, CUST_ORDER.ORDER_NBR
FROM CUSTOMER, CUST_ORDER
WHERE CUSTOMER.CUST_NBR = CUST_ORDER.CUST_NBR;

CUST_NBR NAME ORDER_NBR


------------------------- ------------------
1 Cooper Industries 1001
1 Cooper Industries 1000
5 Gentech Industries 1002

3 rows selected.

Note the use of the table name to qualify each column name. This eliminates any ambiguity as to
which CUST_NBR column the query is referring to.
Instead of qualifying column names with full table names, you can use table aliases, as in the
following example:
SELECT C.CUST_NBR, C.NAME, O.ORDER_NBR
FROM CUSTOMER C, CUST_ORDER O
WHERE C.CUST_NBR = O.CUST_NBR;

Page 30
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

CUST_NBR NAME ORDER_NBR


-------------------------- -----------------
1 Cooper Industries 1001
1 Cooper Industries 1000
5 Gentech Industries 1002

3 rows selected.

The letters "C" and "O" in this example are table aliases. You can specify these aliases following
their respective table names in the FROM clause, and they can be used everywhere else in the
query in place of the table name. Table aliases provide a convenient shorthand notation, allowing
your queries to be more readable and concise.

An important thing to remember while using table aliases is that if you define aliases in the FROM
clause, you must use only those aliases, and not the actual table names, in the rest of the query. If
you alias a table and then use the actual table name in a query, you will encounter errors. For
example:
SELECT C.CUST_NBR, C.NAME, O.ORDER_NBR
FROM CUSTOMER C, CUST_ORDER O
WHERE CUSTOMER.CUST_NBR = CUST_ORDER.CUST_NBR;

WHERE CUSTOMER.CUST_NBR = CUST_ORDER.CUST_NBR


*
ERROR at line 3:
ORA-00904: invalid column name
The column CUST_NBR appears in both the CUSTOMER and CUST_ORDER tables. Without proper
qualification, this column is said to be "ambiguously defined" in the query. Therefore, you must
qualify the CUST_NBR column with a table alias (or a full table name, if you are not using aliases).
However, the other two columns used in the query are not ambiguous. Therefore, the following
statement, which only qualifies the CUST_NBR column, is valid:
SELECT C.CUST_NBR, NAME, ORDER_NBR
FROM CUSTOMER C, CUST_ORDER O
WHERE C.CUST_NBR = O.CUST_NBR;

CUST_NBR NAME ORDER_NBR


---------------------------- -----------------
1 Cooper Industries 1001
1 Cooper Industries 1000
5 Gentech Industries 1002

3 rows selected.

This is where the performance aspect of using table aliases comes into play. Since the query
doesn't qualify the columns NAME and ORDER_NBR, Oracle has to search both the CUSTOMER
and CUST_ORDER tables while parsing this statement to find which table each of these columns
belongs to. The time required for this search may be negligible for one query, but it does add up if

Page 31
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

you have a number of such queries to parse. It is good programming practice to qualify all columns
in a query with table aliases, even those that are not ambiguous, so that Oracle can avoid this
extra search when parsing the statement.

Modifying or Disabling Triggers and Constraints


Using triggers consumes system resources. If you use too many triggers, then you can find that
performance is adversely affected and you might need to modify or disable them.

Using Index to Improve the Performance


What is an Index?
An index is a pointer to the data in the table. An index in a database is very similar to the index in
the back side of the book. For example, if you want to reference all the pages in the book, you first
refer to the index, where you will find all the topics alphabetically and it refers you to one or more
specific page numbers. An index in a database works the same way in that a query is pointed to
the exact physical location of the data in a table. You are actually being directed to the data’s
location in an underlying file of the database. But as far as you are concerned you are referring to
a table.

An index is typically stored separately from the table for which the index was created. An index’s
main purpose is to improve the performance of the data retrieval. Indexes can created or dropped
with no effect on the data. However, after the index is dropped the performance of the data
retrieval might be slowed. Indexes do take physical space and sometimes they may take more
space than the table itself. Therefore, they need to be considered when estimating the size of the
database.

How do indexes work?


When an index is created, it records the location of values in a table that ate associated with the
column that is indexed. Entries are added to the index when new data is added to the table. When
a query is executed against the database and a condition is specified on a column in the where
clause that is indexed, the index is first searched for the values specified in the where clause. If the
value is found in the index, the index returns the exact location of the searched data in the table.

Suppose the following query was issued:


Select * from TABLE_NAME where name = ‘SMITH’

Page 32
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

Figure displaying table access using an index

As shown in the figure, the NAME index is reference to resolve the location of all names equal to
’SMITH’. After the location is determined; the data can retrieved quickly from the table. A full
table scan would occur if there was no index on the table and the same query was executed,
which means that every row of data would be read to retrieve the information pertaining to all the
individuals with the name ‘SMITH’.

Restructuring the Indexes


Often, there is a beneficial impact on performance by restructuring indexes. This can involve the
following:
‰ Remove non-selective indexes to speed the DML.
‰ Index performance-critical access paths.
‰ Consider reordering columns in existing concatenated indexes.
‰ Add columns to the index to improve selectivity.

Do not use indexes as a remedy for all. Application developers sometimes think that performance
will improve if they create more indexes. If a single programmer creates an appropriate index, then
this might indeed improve the application's performance. However, if 50 programmers each create
an index, then application performance will probably be hampered.

When indexes should be avoided?


Although the indexes are used to improve performance, there are some times they should be
avoided. The following guidelines indicate when the use of indexes needs to be reconsidered.
‰ Indexes should not be used on small tables
‰ Indexes should not be used on columns that return a high percentage of data rows
when used as a filter condition in a query’s where condition.
‰ Tables that have frequent, large batch update jobs run can be indexed. However, the
batch jobs performance is slowed considerably by the index. The conflict of having an
index on a table that is frequently loaded or manipulated by a large batch process can
be corrected by dropping the index before the batch job run and then re-creating again
after the job has completed. This is because the indexes are also updated as the data
is inserted, causing additional overhead.
‰ Indexes should not be used on columns that contain a higher number of NULL values.

Page 33
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

‰ Columns that are frequently manipulated should not be indexed. Maintenance on the
index can become expensive.

Oracle SQL Best Practices


There are a few good habits to adopt when you write SQL statements. Keep the following list of
suggestions in mind when diagnosing performance problems, writing or rewriting SQL statements.
‰ Oracle processes SQL in two steps: parsing and execution.
‰ Tuning may speed up your SQL by reducing parsing, execution or both. Note: tuning
SQL should only be done after your code is working correctly. Be aware that there is
an inevitable tug-of-war between writing efficient SQL and understandable SQL.

TIP 1 (Best Tip): SQL cannot be shared within Oracle unless it is absolutely identical. Statements
must have match exactly in case, white space and underlying schema objects to be shared within
Oracle's memory. Oracle avoids the parsing step for each subsequent use of an identical
statement.

sql> SELECT NAME FROM S_CUSTOMER WHERE ID = 212; statement to match

sql> SELECT NAME FROM s_customer WHERE ID = 212; lower case

sql> SELECT NAME FROM S_CUSTOMER WHERE ID=212; white space

sql> SELECT NAME white space


FROM S_CUSTOMER
WHERE ID=212;

‰ Use SQL standards within an application: Rules like the following are easy to
implement and will allow more sharing within Oracle's memory.
o Using a single case for all SQL verbs
o Beginning all SQL verbs on a new line
o Right or left aligning verbs within the initial SQL verb
o Separating all words with a single space
‰ Use bind variables: The values of bind variables do not need to be the same for two
statements to be considered identical. Bind variables are not substituted until a
statement has been successfully parsed.

Sharable SQL SELECT * FROM emp WHERE emp_no = :B1; Bind value: 123

SELECT * FROM emp WHERE emp_no = :B1; Bind value: 987

Non-sharable SQL SELECT * FROM emp WHERE emp_no = 123;

SELECT * FROM emp WHERE emp_no = 987;

‰ Use a standard approach to table aliases: If two identical SQL statements vary
because an identical table has two different aliases, then the SQL is different and will
not be shared.

Page 34
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

‰ Use table aliases and prefix all column names by their aliases when more than one
table is involved in a query. This reduces parse time AND prevents future syntax
errors if someone adds a column to one of the tables with the same name as a column
in another table. (ORA-00918: COLUMN AMBIGUOUSLY DEFINED)

TIP 2: Beware of WHERE clauses which do not use indexes at all. Even if there is an index over a
column that is referenced by a WHERE clause included in this section, Oracle will ignore the index.
All of these WHERE clauses can be re-written to use an index while returning the same values. In
other words, do not perform operations on database objects referenced in the WHERE clause.

Do Not Use Use


SELECT account_name, trans_date,
SELECT account_name, trans_date,
amount
amount
FROM transaction
FROM transaction
WHERE SUBSTR(account_name,1,7) =
WHERE account_name LIKE 'CAPITAL%';
'CAPITAL';
SELECT account_name, trans_date, SELECT account_name, trans_date,
amount amount
FROM transaction FROM transaction
WHERE account_name = NVL ( WHERE account_name LIKE NVL (
:acc_name, account_name); :acc_name, '%');
SELECT account_name, trans_date,
SELECT account_name, trans_date,
amount
amount
FROM transaction
FROM transaction
WHERE trans_date BETWEEN TRUNC
WHERE TRUNC (trans_date) = TRUNC
(SYSDATE) AND TRUNC (SYSDATE) +
(SYSDATE);
.99999;
SELECT account_name, trans_date, SELECT account_name, trans_date,
amount amount
FROM transaction FROM transaction
WHERE account_name || WHERE account_name = 'AMEX'
account_type = 'AMEXA'; AND account_type = 'A';
SELECT account_name, trans_date, SELECT account_name, trans_date,
amount amount
FROM transaction FROM transaction
WHERE amount + 3000 < 5000; WHERE amount < 2000;

SELECT account_name, trans_date, SELECT account_name, trans_date,


amount amount
FROM transaction FROM transaction
WHERE amount != 0; WHERE amount > 0;

Page 35
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

Do Not Use Use


SELECT account_name, trans_date, SELECT account_name, trans_date,
amount amount
FROM transaction FROM transaction
WHERE amount NOT = 0; WHERE amount > 0;

TIP 3: Do not forget to tune views. Views are SELECT statements and can be tuned in just the
same way as any other type of SELECT statement can be. All tuning applicable to any SQL
statement are equally applicable to views.

TIP 4: Avoid including a HAVING clause in SELECT statements. The HAVING clause filters
selected rows only after all rows have been fetched. Using a WHERE clause helps reduce
overheads in sorting, summing, etc. HAVING clauses should only be used when columns with
summary operations applied to them are restricted by the clause.

Do Not Use Use


SELECT region, AVG (loc_size)
SELECT region, AVG (loc_size)
FROM location
FROM location
GROUP BY region WHERE region != 'SYDNEY'
HAVING region != 'SYDNEY' AND region != 'PERTH';
AND region != 'PERTH'; GROUP BY region;

TIP 5: Minimize the number of table lookups (subquery blocks) in queries, particularly if your
statements include subquery SELECTs or multicolumn UPDATEs.

SELECT emp_name
FROM emp
WHERE emp_cat = (SELECT MAX (category)
Separate
FROM emp_categories)
Subqueries
AND emp_range = (SELECT MAX (sal_range)
FROM emp_categories)
AND emp_dept = 0020;
SELECT emp_name
FROM emp
Combined WHERE (emp_cat, sal_range)
Subqueries = (SELECT MAX (category), MAX (sal_range)
FROM emp_categories)
AND emp_dept = 0020;

TIP 6: Consider the alternatives EXISTS, IN and table joins when doing multiple table joins.
None of these are consistently faster; it depends on your data. If there is a poor performer here, it

Page 36
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

is likely the IN clause.

(Note, this query returns the employee names from each department in department category 'A'.)

SELECT emp_name
FROM emp E
WHERE EXISTS ( SELECT 'X'
FROM dept
WHERE dept_no = E.dept_no
AND dept_cat = 'A');
SELECT emp_name
FROM emp E
WHERE dept_no IN ( SELECT dept_no
FROM dept
WHERE dept_no = E.dept_no
AND dept_cat = 'A');

SELECT emp_name
FROM dept D, emp E
WHERE E.dept_no = D.dept_no
AND D.dept_cat = 'A';

TIP 7: Avoid joins that require the DISTINCT qualifier on the SELECT list in queries which are
used to determine information at the owner end of a one-to-many relationship. The DISTINCT
operator causes Oracle to fetch all rows satisfying the table join and then sort and filter out
duplicate values. EXISTS is a faster alternative, because the Oracle optimizer realizes when the
subquery has been satisfied once, there is no need to proceed further and the next matching row
can be fetched.

(Note: This query returns all department numbers and names which have at least one employee.)
Do Not Use Use
SELECT DISTINCT dept_no, SELECT dept_no, dept_name
dept_name FROM dept D
FROM dept D, WHERE EXISTS (
emp E SELECT 'X'
WHERE D.dept_no = E.dept_no; FROM emp E
WHERE E.dept_no = D.dept_no);

TIP 8: Consider whether a UNION ALL will suffice in place of a UNION. The UNION clause forces
all rows returned by each portion of the UNION to be sorted and merged and duplicates to be

Page 37
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

filtered before the first row is returned. A UNION ALL simply returns all rows including duplicates
and does not have to perform any sort, merge or filter. If your tables are mutually exclusive
(include no duplicate records), or you don't care if duplicates are returned, the UNION ALL is
much more efficient.

UNION UNION ALL


SELECT acct_num, balance_amt SELECT acct_num, balance_amt
FROM debit_transactions FROM debit_transactions
WHERE tran_date = '31-DEC-95' WHERE tran_date = '31-DEC-95'
UNION UNION ALL
SELECT acct_num, balance_amt SELECT acct_num, balance_amt
FROM credit_transactions FROM credit_transactions
WHERE tran_date = '31-DEC-95'; WHERE tran_date = '31-DEC-95';

TIP 9: Consider using DECODE to avoid having to scan the same rows repetitively or join the same
table repetitively. Note, DECODE is not necessarily faster as it depends on your data and the
complexity of the resulting query. Also, using DECODE requires you to change your code when new
values are allowed in the field.

SELECT COUNT(*)
FROM emp
WHERE status = 'Y'
AND emp_name LIKE 'SMITH%';
----------
SELECT COUNT(*)
FROM emp
WHERE status = 'N'
AND emp_name LIKE 'SMITH%';
SELECT COUNT(DECODE(status, 'Y', 'X', NULL)) Y_count,
COUNT(DECODE(status, 'N', 'X', NULL)) N_count
FROM emp
WHERE emp_name LIKE 'SMITH%';

TIP 10: Oracle automatically performs simple column type conversions (or casting) when it
compares columns of different types. Depending on the type of conversion, indexes may not be
used. Make sure you declare your program variables as the same type as your Oracle columns, if
the type is supported in the programming language you are using.

Page 38
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

Data type
of
Index
field in Your Query After Implicit Conversion
Used?
where
clause
SELECT ...
emp_no SELECT ...
FROM emp
indexed FROM emp YES
WHERE emp_no = WHERE emp_no =
numeric
'123'; TO_NUMBER('123');
SELECT ...
emp_type SELECT ...
FROM emp NO!
indexed FROM emp
WHERE emp_type WHERE TO_NUMBER (emp_type) =
varchar2
= 123; 123;

Tip 11: Avoid the LIKE predicate = Always replace a "like" with equality, wherever appropriate

Tip 12: Use of OR Instead of UNION: The OR EXISTS subquery takes long time to execute.

Consider the following example:


select .....
from ps_jrnl_header a
where jrnl_hdr_status ='E'

or exists

(select 'x'
from ps_jrnl_header
where business_unit_iu=a.business_unit_iu
and journal_id= a.journal_id
and journal_date=a.journal_date
and unpost_seq= a.unpost_seq
and jrnl_hdr_status='E')

Runtime: 4 Minute 16 seconds

Notice the long runtime for the statement. It would not it be nice to make the statement go faster?
Luckily, the fix is simple. If you have the access to change the code (that is, you are not running a
third-party package), then use a UNION statement to implement the OR in the WHERE clause as two
separate queries:

select ...........
from ps_jrnl_header a
where jrnl_hdr_status ='E'

Page 39
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

UNION
select .....
from ps_jrnl_header a, ps_jrnl_header b
where b.business_unit_iu
=a.business_unit_iu
and b.journal_id=a.journal_id
and b.journal_date=a.journal_date
and b.unpost_seq=a.unpost_seq
and a.jrnl_hdr_status='E'
and b.jrnl_hdr_status != 'E';

Runtime: 0.02 seconds

The reason for the performance improvement is that the UNION allows the optimizer to perform
two simple operations to return the rows, whereas the more complex OR construct has confused
the optimizer into using a less optimal execution plan.

SQL Performance Tuning Tips


Some of the tips used for SQL tuning are as follows
‰ Identify incorrect driving table and fix it: If the table driving a join is not optimal,
then there can be a significant increase in the amount of time required to execute a
query. Consider the following example, which illustrates the potential difference in
runtimes:
SELECT COUNT(*) FROM acct a, trans b WHERE b.cost_center =
'MASS' AND a.acct_name = 'MGA' AND a.acct_name =
b.acct_name;

In this example, if ACCT_NAME represents a unique key index and COST_CENTER represents a
single column non-unique index, the unique key index would make the ACCT table the driving
table.
If both COST_CENTER and ACCT_NAME were single column, non-unique indexes, the rule-based
optimizer would select the TRANS table as the driving table, because it is listed last in the FROM
clause. Having the TRANS table as the driving table would likely mean a longer response time for a
query, because there is usually only one ACCT row for a selected account name but there are likely
to be many transactions for a given cost center.

With the rule-based optimizer, if the index rankings are identical for both tables, Oracle simply
executes the statement in the order in which the tables are parsed. As the parser processes table
names from right to left, the table name that is specified last (For example, DEPT in the earlier
example is actually the first table processed that is, the driving table).

SELECT COUNT(*) FROM acct a, trans b WHERE b.cost_center =


'MASS' AND a.acct_name = 'MGA' AND a.acct_name =
b.acct_name;
Response = 19.722 seconds

Page 40
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

The response time following the re-ordering of the tables in the FROM clause is as follows:
SELECT COUNT(*) FROM trans b, acct a WHERE b.cost_center=
'MASS' AND a.acct_name = 'MGA' AND a.acct_name =
b.acct_name;

Response = 1.904 seconds

It is important that the table that is listed last in the FROM clause is going to return the fewest
number of rows.
‰ Identify incorrect driving Index and fix it: The way you specify conditions in the
WHERE clauses of your SELECT statements has a major impact on the performance of
your SQL, because the order in which you specify conditions impacts the indexes the
optimizer choose to use. The effect is very similar to that from the ordering of tables in
the FROM clause. Consider the following example:
SELECT COUNT(*)
FROM trans
WHERE cost_center = 'MASS'
AND bmark_id = 9;

Response Time = 4.255 seconds

The index that has the column that is listed first in the WHERE CLAUSE will drive the query. In this
statement, the indexed entries for COST_CENTER = `MASS' will return significantly more rows
than those for BMARK_ID=9, which will return at most only one or two rows.

The following query reverses the order of the conditions in the WHERE clause, resulting in a much
faster execution time.
SELECT COUNT(*)
FROM trans
WHERE bmark_id = 9
AND cost_center = 'MASS';

Response Time = 1.044 seconds

‰ Analyze tables periodically to improve the performance: Imagine that you are
consulting at a site with a table TRANS that has a column called STATUS. The column
has two possible values: `O' for Open Transactions that have not been posted and `C'
for closed transactions that have already been posted and that require no further
action. There are over one million rows that have a status of `C', but only 100 rows
that have a status of `O' at any point in time.

Page 41
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

The site has the following SQL statement that runs many hundreds of times daily. The response
time is dismal, and you have been called in to "make it go faster."

SELECT acct_no, customer, product, trans_date, amt


FROM trans
WHERE status='O';

Response time = 16.308 seconds


In this example, the cost-based optimizer decides that Oracle should perform a full table scan. This
is because the cost-based optimizer is aware of how many distinct values there are for the status
column, but is unaware of how many rows exist for each of those values. Consequently, the
optimizer assumes a 50/50 spread of data for each of the two values, `O' and `C'. Given this
assumption, Oracle has decided to perform a full table scan to retrieve open transactions.

If you inform Oracle of the data skewness by specifying the option FOR ALL INDEXED COLUMNS
when you run the ANALYZE command or when you invoke the DBMS_STATS package, Oracle will
be made aware of the skewness of the data; that is, the number of rows that exist for each value
for each indexed column. In our scenario, the STATUS column is indexed.

The following command is used to analyze the table:


ANALYZE TABLE TRANS COMPUTE STATISTICS
FOR ALL INDEXED COLUMNS

After analyzing the table and computing statistics for all indexed columns, the cost-based optimizer
is aware that there are only 100 or so rows with a status of `O', and it will accordingly use the index
on that column. Use of the index on the STATUS column results in the following, much faster,
query response:

Response Time: 0.259 seconds

Typically the cost-based optimizer will perform a full table scan if the value selected for a column
has over 12% of the rows in the table, and will use the index if the value specified has less than
12% of the rows. The cost-based optimizer selections are not quite as firm as this, but as a rule of
thumb this is the typical behavior that the cost-based optimizer will follow.

Note: Re-analyzing tables and indexes can be almost as dangerous as adjusting your indexing,
and should ideally be tested in a copy of the production database prior to being applied to the
production database.
‰ Tables and indexes with many deletes: Oracle is similar to many other databases in
that there are performance issues with deletes. Oracle has a high water mark, which
represents the highest number of rows ever inserted into the table. This high-water
mark can have an impact on performance.
Consider the following example, which takes 5.378 seconds to read a table with
151,070 rows:
SELECT COUNT(*) FROM YYYY;
151070
real: 5378

Page 42
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

It just happens that all 150,000 rows have the STATE column set to `VIC', and that the table has an
index on the STATE column. If you use a WHERE clause to force the count to use the index on the
STATE, then it takes 16.884 seconds:
SELECT COUNT(*) FROM YYYY WHERE STATE='VIC';
---------
151070

real: 16884

The index scan took about three times longer than the full table scan. Now let's delete all of the
rows, so that the result is an empty table:
DELETE FROM YYYY;
real: 55277

Now that you have an empty table, let's count all the rows again:
SELECT COUNT(*) FROM YYYY;
---------
0
real: 5117

Notice that it takes the same amount of time to count zero rows as it took to count from the table
when it was completely populated. This is because, when performing a full table scan, Oracle
reads as far as the table's high-water mark, and the high-water mark has not changed.

Let's count the rows again using the index:


SELECT COUNT(*) FROM YYYY WHERE STATE='VIC';
0
real: 16029

Just as before, it takes the same amount of time to count zero rows as it took to count the original
150,000. This is because the index entries are logically deleted, but still exist physically.

To avoid the types of performance problems rebuild a table, and its indexes, whenever the table
has undergone many deletes. If index columns are frequently updated, you should also re-build
the indexes, because an update forces a logical delete in the index followed by an insert of the
new, updated entry.

To detect which tables have many deletes and updates, you can run the following SELECT
statement:
SELECT sql_text, executions
FROM v$sqlarea
WHERE UPPER(sql_text) LIKE 'DELETE%'
OR
UPPER(sql_text) LIKE 'UPDATE%';

Page 43
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

‰ Full-table scans may at times be more efficient than the use of indexes if the table is
relatively small in size, as Oracle can read all the data with one I/O operation.

Note: A full table scan is typically able to read over 100 rows of table information per block. Added
to this, the DB_FILE_MULTIBLOCK_READ_COUNT parameter allows Oracle to read many blocks
with one physical disk read. You may be reading 800 rows with each physical read from disk. In
comparison, an index will potentially perform one physical read for each row returned from the
table.
‰ Functions applied to indexed columns in the WHERE clause do not take advantage of
the index unless you use the MIN or MAX function. In the following example, the TRUNC
function disables the index.

Do not use:
SELECT account_name, trans_date, amount
FROM transaction
WHERE TRUNC(trans_date) = TRUNC(SYSDATE);

Use:
SELECT account_name, trans_date, amount
FROM transaction
WHERE trans_date BETWEEN TRUNC(SYSDATE)
AND TRUNC(SYSDATE) + .99999;

‰ Use analytical functions where possible instead of multiple SQL statements as it


simplifies the query writing and requires only a single pass through the table.
‰ If your queries involve aggregates and joins against large tables, then you can use
materialized views to pre-store results and refresh them at set intervals. Oracle has a
set of advisor procedures that help you design and evaluate the benefits of
materialized views.
‰ Make sure you did not forget the joining criteria so as to avoid the building of a
Cartesian product.
‰ Consider replacing the NOT IN operator with the NOT EXISTS operator and eliminate
as many rows as possible in the outer query of a correlated subquery.
‰ Review the result of the execution plan carefully to determine the cause of any
performance problem; examine execution steps involving a large number of rows or
high cost. Use hints to tune the statement and make sure the hints are valid. Do not
use hints that have no effect, such as a FIRST_ROWS hint on a statement with an
ORDER BY clause because the ORDER BY sort operation needs to be processed first
before any rows are returned.
‰ Use the CASE expression to avoid visiting tables multiple times. For example, if you
need to aggregate rows that have different WHERE conditions within the same table,
you can use the CASE expression to aggregate only those rows that satisfy the
necessary condition.

Page 44
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

Summary
‰ SQL tuning is the process of tuning the SQL statements that access the database.
‰ Follow a standard approach to write your SQL statements:
o Use a single case for all SQL verbs
o Begin all SQL verbs on a new line
o Right or left aligning verbs within the initial SQL verbs
‰ SQL performance tuning tips are as follows:
o Identify incorrect driving table and fix it
o Identify incorrect driving index and fix it
o Analyze tables and indexes periodically
o Identify tables and indexes with many deletes
o Watch out for table records before creating indexes

Test Your Understanding


1. What is SQL tuning?
2. Explain some best practices in writing oracle SQL statements.

Page 45
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

Session 05: Query Optimizer

Learning Objectives
After completing this session, you will be able to:
‰ Define an optimizer
‰ Identify the types of optimizer
‰ Analyze execution plan
‰ Apply optimizer hints to override CBO

Introduction
The SQL processing architecture contains the following main components:
‰ Parser
‰ Optimizer
‰ Row Source Generator
‰ SQL Execution Engine

The parser, the optimizer and the row source generator form the SQL Compiler. The SQL
Compiler compiles the SQL statements into a shared cursor, which is associated with the
execution plan.

Page 46
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

Parser
The parser performs two functions:
‰ Syntax analysis: Checks SQL statements for correct syntax
‰ Semantic analysis: Checks that current database objects and object attributes
references are correct

Optimizer
The optimizer uses internal rules or costing methods to determine the most efficient way of
producing the result of the query. The output from the optimizer is a plan that describes an
optimum method of execution. The Oracle server provides two methods of optimization: cost-
based optimizer (CBO) and rule-based optimizer (RBO).

Row Source Generator


The row source generator receives the optimal plan from the optimizer. It outputs the execution
plan for the SQL statement. The execution plan is a collection of row sources structured in the
form of a tree. Each row source returns a set of rows for that step.

SQL Execution Engine


The SQL execution engine is the component that operates on the execution plan associated with a
SQL statement. It then produces the results of the query. Each row source produced by the row
source generator is executed by the SQL execution engine.

Query Optimizer
A SQL statement can be executed in many different ways, such as full table scans, index scans,
nested loops, and hash joins. The query optimizer determines the most efficient way to execute a
SQL statement after considering many factors related to the objects referenced and the conditions
specified in the query. This determination is an important step in the processing of any SQL
statement and can greatly affect execution time. The optimizer might not make the same decisions
from one version of Oracle to the next. In recent versions, the optimizer might make different
decisions, because better information is available.

Optimizer Operations
The output from the optimizer component is a plan (Execution Plan) that describes an optimum
method of execution. For any SQL statement processed by Oracle, the optimizer performs the
operations listed as follows:
Operation Description

Evaluation of The optimizer first evaluates expressions and conditions containing


expressions and constants as fully as possible.
conditions

Statement For complex statements involving, for example, correlated subqueries or


transformation views, the optimizer might transform the original statement into an
equivalent join statement

Choice of optimizer The optimizer determines the goal of optimization.


goals

Page 47
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

Operation Description

Choice of access paths For each table accessed by the statement, the optimizer chooses one or
more of the available access paths to obtain table data.

Choice of join orders For a join statement that joins more than two tables, the optimizer
chooses which pair of tables is joined first, and then which table is joined
to the result, and so on.

Available Optimizers
Oracle has two modes for Optimizer to decide on the best execution plan, Rule based and Cost
based.

Rule Based Optimizer (RBO)


RBO follows a simple ranking methodology. Fifteen ranking points are designed in this optimizer.
When a query is received, the optimizer evaluates the number of points that are satisfied. The
execution path with the best rank (lowest number) is then chosen for executing the query. The
fifteen-point ranking is mentioned as follows:
1. Single row by ROWID
2. Single row by cluster join
3. Single row by hash cluster with unique or primary key
4. Single row by unique or primary key
5. Cluster join
6. Hash cluster key
7. Indexed cluster key
8. Composite key
9. Single column indexes
10. Bounded range on index columns
11. Unbounded range on indexed columns
12. Sort merge join
13. MAX or MIN on indexed column
14. ORDER BY on indexed columns
15. Full table scan
For example, If I fire a query on a table that has two columns that are searched for exact match
(equal-to) in the where clause condition, one being the primary key and the other column has a
non-unique key, RBO will prefer the primary key (rank 4) to the non-unique key (rank 9).

When more than one table is accessed in a query, the optimizer needs to decide which should be
the driving table. The RBO generates a set of join orders, each with a different table as the first
table. Then the most optimal plan is chosen from the resulting set of execution plans.

The optimizer evaluates the execution plans for various conditions such as (fewest nested-loop,
fewest sort-merge joins, table with the best ranking access path, etc.). If there is still a tie, the
optimizer chooses the execution plan for which the first table appears later in the query's FROM
clause. Hence, it is a conventional coding practice to put the driving table at the extreme right,
followed by other tables in order of access in the FROM clause, i.e., the ordering of tables based
on their access is from right to left.

Page 48
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

Please note that the operators being used for searching the columns also play a role in deciding
the ranking. Sometimes even the age of an index is considered for ranking!

RBO was the preferred choice for most setups in earlier releases of oracle as the execution paths
were consistent and uniform. Queries would behave the same way if run on different databases of
the same application.

Cost based optimizer (CBO)


CBO follows Expense calculation methodology. All execution plans are tagged with a cost, the one
with the lowest cost will be chosen. The higher the cost the more resources will be used by the
execution plan, the lower the cost, the more efficient the query is.

CBO uses all available information-statistics and histograms stored in the dictionary, user provided
hints and supplied parameter settings to arrive at the cost. CBO generates all possible
permutations of access methods and then chooses what fits best. The number of permutations
depends on the number of tables present in the query and can sometimes be around 80,000
permutations or even more!

CBO may also perform operations such as query transformation, view merging, OR
transformation, push join predicates, etc. that would change the original statement and alter
existing or add new predicates, all with the aim of deriving new access plans that could be better
than the existing ones. Note that transformation does not affect the data that is returned, only the
execution path.

Page 49
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

Which Optimizer is best one to use and why?


Oracle 9i release 2 is the last version that officially supported RBO. Oracle has recommended all
partners and customers to certify their applications with CBO before this version (RBO) is no
longer supported.

As per a published Oracle note, the existence of RBO prevents Oracle from making key
enhancements to its query-processing engine. Its removal will permit Oracle to improve
performance and reliability of the query-processing components of the database engine.

The Rule Based Optimizer (RBO) is now obsolete in Oracle 10g. The functionality is still present
but no new functionality has been included in it and it is no longer supported by Oracle. It is only
present to provide backwards compatibility during the migration to the query optimizer (Cost Based
Optimizer).

Optimizer Goal
By default, the goal of the query optimizer is the best throughput. This means that it chooses the
least amount of resources necessary to process all rows accessed by the statement. Oracle can
also optimize a statement with the goal of best response time. This means that it uses the least
amount of resources necessary to process the first row accessed by a SQL statement.
‰ Choose a goal for the optimizer based on the needs of your application:
‰ For applications performed in batch, such as Oracle Reports applications, optimize for
best throughput. Usually, throughput is more important in batch applications, because
the user initiating the application is only concerned with the time necessary for the
application to complete. Response time is less important, because the user does not
examine the results of individual statements while the application is running.
‰ For interactive applications, such as Oracle Forms applications or SQL*Plus queries,
optimize for best response time. Usually, response time is important in interactive
applications, because the interactive user is waiting to see the first row or first few
rows accessed by the statement.

Query Optimizer – Components


‰ The query optimizer operations include:
‰ Transforming Queries
‰ Estimating
‰ Generating Plans

Page 50
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

Figure displaying components of Query Optimizer

Transforming Queries
The input to the query transformer is a parsed query, which is represented by a set of query
blocks. The query blocks are nested or interrelated to each other. The form of the query
determines how the query blocks are interrelated to each other. The main objective of the query
transformer is to determine if it is advantageous to change the form of the query so that it enables
generation of a better query plan. Several different query transformation techniques are employed
by the query transformer, including:

View Merging: The simplest form of query transformation is view merging. For queries containing
views, the reference to the view can often be removed entirely from the query by ‘merging’ the
view definition with the query.
CREATE VIEW TEST_VIEW AS
SELECT ENAME, DNAME, SAL FROM EMP E, DEPT D
WHERE E.DEPTNO = D.DEPTNO;
SELECT ENAME, DNAME FROM TEST_VIEW WHERE SAL > 10000;

Without any query transformations, the only way to process this query is to join all of the rows of
EMP to all of the rows of the DEPT table, and then filter the rows with the appropriate values for
SAL.

With view merging, the earlier query can be transformed into:


SELECT ENAME, DNAME FROM EMP E, DEPT D
WHERE E.DEPTNO = D.DEPTNO
AND E.SAL > 10000;
When processing the transformed query, the predicate ‘SAL>10000’ can be applied before the join
of the EMP and the DEPT tables. This transformation can vastly improve query performance by
reducing the amount of data to be joined.

Predicate Pushing: A complex query may contain multiple views and subqueries, with many
predicates that are applied to these views and subqueries. Oracle can move predicates into and
out of views in order to generate new, better performing queries.

Page 51
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

A single-table view can be used to illustrate predicate push-down:


CREATE VIEW EMP_AGG AS
SELECT
DEPTNO,
AVG(SAL) AVG_SAL,
FROM EMP
GROUP BY DEPTNO;
Now suppose the following query is executed:

Oracle will ‘push’ the predicate DEPTNO=10 into the view, and transform the query into the
following SQL:
SELECT DEPTNO, AVG(SAL)5 FROM EMP WHERE DEPTNO = 10
GROUP BY DEPTNO;

The advantage of this transformed query is that the DEPTNO=10 predicate is applied before the
GROUP-BY operation, and this could vastly reduce the amount of data to be aggregated.

Subquery Unnesting: Oracle has a variety of transformations that convert various types of
subqueries into joins, semi-joins, or anti-joins. As an example of the techniques in this area,
consider the following query, which selects those departments that have employees that make
more than 10000:
SELECT D.DNAME FROM DEPT D WHERE D.DEPTNO IN
(SELECT E.DEPTNO FROM EMP E WHERE E.SAL > 10000)

There are a variety of possible execution plans that could be optimal for this query. Oracle will
consider the different possible transformations, and select the best plan based on cost.

Without any transformations, the execution plan for this query would be similar to:

With this execution plan, the all of the EMP records satisfying the subquery’s conditions will be
scanned for every single row in the DEPT table. In general, this is not an efficient execution
strategy. However, query transformations can enable much more efficient plans.

The optimizer could determine that the DEPT table should be the inner table of the join. In that
case, it will execute the query as a regular join, but perform a unique sort of the EMP table in order
to eliminate duplicate department numbers:

Page 52
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

The transformed SQL for this statement would be as follows:


SELECT D.DNAME FROM (SELECT DISTINCT DEPTNO FROM EMP) E, DEPT D
WHERE E.DEPTNO = D.DEPTNO
AND E.SAL > 10000;

Query Rewrite with Materialized Views: Pre-computing and storing commonly-used data in the
form of a materialized view can greatly speed up query processing. Oracle can transform SQL
queries so that one or more tables referenced in a query can be replaced by a reference to a
materialized view. If the materialized view is smaller than the original table or tables, or has better
available access paths, the transformed SQL statement could be executed much faster than the
original one.

For example, consider the following materialized view:


CREATE MATERIALIZED VIEW SALES_SUMMARY
AS SELECT SALES.CUST_ID, TIME.MONTH, SUM(SALES_AMOUNT) AMT
FROM SALES, TIME
WHERE SALES.TIME_ID = TIME.TIME_ID
GROUP BY SALES.CUST_ID, TIME.MONTH;

This materialized view can be used to optimize the following query:


SELECT CUSTOMER.CUST_NAME, TIME.MONTH, SUM(SALES.SALES_AMOUNT)
FROM SALES, CUSTOMER, TIME
WHERE SALES.CUST_ID = CUST.CUST_ID
AND SALES.TIME_ID = TIME.TIME_ID
GROUP BY CUSTOMER.CUST_NAME, TIME.MONTH;

The rewritten query would be as follows:


SELECT CUSTOMER.CUST_NAME, SALES_SUMMARY.MONTH, SALES_SUMMARY.AMT
FROM CUSTOMER, SALES_SUMMARY
WHERE CUSTOMER.CUST_ID = SALES_SUMMARY.CUST_ID;
In this example, the transformed query is likely much faster for several reasons:the
sales_summary table is likely much smaller than the sales table and the transformed query
requires one less join and no aggregation.

Oracle has a very robust set of rewrite techniques for materialized views, in order to allow each
materialized view to be used for as broad a set of queries as possible.

OR-expansion: This technique converts a query with ORs in the WHERE-clause into a UNION
ALL of several queries without ORs. It can be highly beneficial when the Ors refer to restrictions of
different tables. Consider the following query to find all the shipments that went either from or to
Oakland.
SELECT * FROM SHIPMENT, PORT P1, PORT P2
WHERE SHIPMENT.SOURCE_PORT_ID = P1.PORT_ID
AND SHIPMENT.DESTINATION_PORT_ID = P2.PORT_ID
AND (P1.PORT_NAME = 'OAKLAND' OR P2.PORT_NAME = 'OAKLAND')

Page 53
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

The query can be transformed into the following:


SELECT * FROM SHIPMENT, PORT P1, PORT P2
WHERE SHIPMENT.SOURCE_PORT_ID = P1.PORT_ID
AND SHIPMENT.DESTINATION_PORT_ID = P2.PORT_ID
AND P1.PORT_NAME = 'OAKLAND'
UNION ALL
SELECT * FROM SHIPMENT, PORT P1, PORT P2
WHERE SHIPMENT.SOURCE_PORT_ID = P1.PORT_ID
AND SHIPMENT.DESTINATION_PORT_ID = P2.PORT_ID
AND P2.PORT_NAME = 'OAKLAND' AND P1.PORT_NAME <> 'OAKLAND'

Note that each UNION ALL branch can have different optimal join orders. In the first branch,
Oracle could take advantage of the restriction on P1 and drive the join from that table. In the
second branch, Oracle could drive from P2 instead.
‰ Any combination of these transformations can be applied to a given query.

Estimating
The estimator generates three different types of measures:
‰ Selectivity
‰ Cardinality
‰ Cost
These measures are related to each other, and one is derived from another. The end goal of the
estimator is to estimate the overall cost of a given plan. If statistics are available, then the
estimator uses them to compute the measures. The statistics improve the degree of accuracy of
the measures.

‰ Selectivity: Selectivity represents a fraction of rows from a row set. The row set can
be a base table, a view, or the result of a join or a GROUP BY operator. The selectivity
is tied to a query predicate, such as last_name = 'Smith', or a combination of
predicates, such as last_name = 'Smith' AND job_type = 'Clerk'. A predicate acts as a
filter that filters a certain number of rows from a row set. Therefore, the selectivity of a
predicate indicates how many rows from a row set will pass the predicate test.
Selectivity lies in a value range from 0.0 to 1.0. A selectivity of 0.0 means that no rows
will be selected from a row set, and a selectivity of 1.0 means that all rows will be
selected.
‰ Cardinality: Cardinality represents the number of rows in a row set. Here, the row set
can be a base table, a view, or the result of a join or GROUP BY operator.
‰ Cost: The cost represents units of work or resource used. The query optimizer uses
disk I/O, CPU usage, and memory usage as units of work. So, the cost used by the
query optimizer represents an estimate of the number of disk I/Os and the amount of
CPU and memory used in performing an operation.

The access path determines the number of units of work required to get data from a base table.
The access path can be a table scan, a fast full index scan, or an index scan. During table scan or
fast full index scan, multiple blocks are read from the disk in a single I/O operation. Therefore, the
cost of a table scan or a fast full index scan depends on the number of blocks to be scanned and
the multi-block read count value.

Page 54
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

The join cost represents the combination of the individual access costs of the two row sets being
joined, plus the cost of the join operation.

Generating Plans
The main function of the plan generator is to try out different possible plans for a given query and
pick the one that has the lowest cost. Many different plans are possible because of the various
combinations of different access paths, join methods, and join orders that can be used to access
and process data in different ways and produce the same result.

Explain Plan
Whenever you read or write data in Oracle, you do so by issuing an SQL statement. One of
Oracle's tasks when it receives such a statement is to build a query execution plan. An execution
plan defines how Oracle finds or writes the data. For example, an important decision that Oracle
has to take is if it uses indexes or not. And if there are more indexes, which of these is used. All
this is contained in an execution plan.

If one wants to explore such an execution plan, Oracle provides the SQL statement EXPLAIN
PLAN to determine this

Running an Explain Plan


Explain plan for a statement can be generated by issuing the following statement:
EXPLAIN PLAN
SET STATEMENT_ID = <<identifier>> FOR
<<SQL Statement>>

EXPLAIN PLAN
INTO my_plan_table
SET STATEMENT_ID = 'bad1' FOR
SELECT name FROM emp;

If you do an EXPLAIN PLAN, then Oracle will analyze the statement and fill in the results into Plan
table. Plan table will hold the execution plan for a SQL statement. The most important fields
within the plan table are operation, option, object_name, id, and parent_id.

Displaying the execution plan


The following statement is used to display the execution plan:
SELECT lpad(' ',level-1)||operation||' '||options||' '||
object_name "Plan"
FROM plan_table
CONNECT BY prior id = parent_id
AND prior statement_id = statement_id
START WITH id = 0 AND statement_id = '&1'
ORDER BY id;

Page 55
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

Understanding Execution Plan


EXPLAIN PLAN Example 1
EXPLAIN PLAN SET statement_id = 'example1' FOR
SELECT full_name FROM per_all_people_f
WHERE UPPER(full_name) LIKE 'Pe%' ;

Plan
---------------------------------------------
SELECT STATEMENT
TABLE ACCESS FULL PER_ALL_PEOPLE_F

This plan shows execution of a SELECT statement. The table PER_ALL_PEOPLE_F is accessed
using a full table scan.
‰ Every row in the table PER_ALL_PEOPLE_F is accessed, and the WHERE clause
criteria is evaluated for every row.
‰ The SELECT statement returns the rows meeting the WHERE clause criteria.
‰ Even though there is index in table PER_ALL_PEOPLE_F it is not used because a
function is used in the column in where criteria.

EXPLAIN PLAN Example 2


EXPLAIN PLAN SET statement_id = 'example2' FOR
SELECT full_name FROM per_all_people_f
WHERE full_name LIKE 'Pe%' ;

Plan
---------------------------------------------
SELECT STATEMENT
TABLE ACCESS BY INDEX ROWID PER_ALL_PEOPLE_F
INDEX RANGE SCAN PER_PEOPLE_F_N54

This plan shows execution of a SELECT statement.


‰ Index PER_PEOPLE_F_N54 is used in a range scan operation.
‰ The table PER_ALL_PEOPLE_F is accessed through ROWID. ROWIDs are obtained
from the index in the previous step for keys that meet the WHERE clause criteria. When
the table is accessed, any additional WHERE clause conditions that could not be
evaluated during the range scan (because the column is present in the table and not in
the index) are also evaluated.
‰ The SELECT statement returns rows satisfying the WHERE clause conditions
(evaluated in previous steps).

Minimizing Throw-Away
Examining an explain plan lets you look for throw-away in cases such as the following:
‰ Full scans
‰ Unselective range scans
‰ Late predicate filters

Page 56
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

‰ Wrong join order


‰ Late filter operations

For example, in the following explain plan, the last step is a very unselective range scan that is
executed 76563 times, accesses 11432983 rows, throws away 99% of them, and retains 76563
rows. Why access 11432983 rows to realize that only 76563 rows are needed?

Example 12-1 Looking for Throw-Away in an Explain Plan


Rows Execution Plan
---------- -----------------------------

12 SORT AGGREGATE
2 SORT GROUP BY
76563 NESTED LOOPS
76575 NESTED LOOPS
19 TABLE ACCESS FULL CN_PAYRUNS_ALL
76570 TABLE ACCESS BY INDEX ROWID CN_POSTING_DETAILS_ALL
76570 INDEX RANGE SCAN (object id 178321)
76563 TABLE ACCESS BY INDEX ROWID CN_PAYMENT_WORKSHEETS_ALL
11432983 INDEX RANGE SCAN (object id 186024)

Optimizer Hints
Optimizer hints can be used with SQL statements to alter execution plans. Hints provide a
mechanism to instruct the optimizer to choose a certain query execution plan based on the specific
criteria.
‰ For example, you might know that a certain index is more selective for certain queries.
Based on this information, you might be able to choose a more efficient execution plan
than the optimizer. In such a case, use hints to instruct the optimizer to use the optimal
execution plan.

You can use hints to specify the following:


‰ The optimization approach for a SQL statement
‰ The goal of the cost-based optimizer for a SQL statement
‰ The access path for a table accessed by the statement
‰ The join order for a join statement
‰ A join operation in a join statement

Example 1: In the following example, including /*+ RULE */ inside the SELECT statement
instructs the optimizer to use the rule-based optimizer rather than the cost-based optimizer:
SELECT /*+ RULE */ . . . .
FROM emp, dept
WHERE . . .

Page 57
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

Example 2: The hint in this case is FULL(dept); it tells Oracle to do a full table scan of the dept
table. Oracle will honor this hint and perform a full table scan of dept when joining the tables, even
if it appears that doing so will degrade performance
SELECT /*+ FULL(dept) */
empno, ename, dname
FROM emp, dept
WHERE emp.deptno = dept.deptno;

Example 3: Note that the table emp has an alias e. The hint for the table uses the same alias, and
is specified as FULL(e). Whenever an alias is used, the alias name must be used in any hints for
the table:
SELECT /*+ FULL(e) do a full tablescan on the emp table, because
most employees do have billing rates < 4000. */
empno, ename
FROM emp e
WHERE sal < 4000;

Example 4: When subqueries are used, they are allowed to have their own hints. The hint for a
subquery follows the keyword that starts the query, as shown in the following:
SELECT /*+ FIRST_ROWS */ empno, ename
FROM emp
WHERE NOT EXISTS (
SELECT /*+ FULL(dept) */ *
FROM dept
WHERE emp.deptno = dept.deptno
AND dept.loc IN ('NEW YORK', 'BOSTON', 'CHICAGO'));

Types of Hints
Oracle hints can be divided loosely into the following categories:
‰ Optimizer goal hints
‰ Access method hints
‰ Join order hints
‰ Join operation hints
‰ Parallel execution hints
‰ Other hints

Optimizer goal hints


Optimizer goal hints allow you to influence the optimizer's overall goal when formulating an
execution plan.

Page 58
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

Optimizer Goal Hints


Hint Description
ALL_ROWS Tells the optimizer to produce an execution plan that minimizes resource
consumption.
FIRST_ROWS Tells the optimizer to produce an execution plan with the goal of getting to the first
row as quickly as possible.
CHOOSE Allows the optimizer to choose between the rule-based and the cost-based mode. If
statistics are present for tables in the query, the cost-based approach will be taken.
RULE Forces the optimizer to use a rule-based approach for the statement.

Access method hints


Access method hints allow control of how data is accessed. For example, Oracle can be directed
to perform a full table scan or to use an index when accessing a table, and the name of the
specific index to be used can be specified.

Some access method hints are index-related and allow identification of indexes to be used. In
many cases, such as with the INDEX hint, the index name may or may not be specified.

The following hint tells Oracle to perform an index scan on the EMP table, but that it is up to Oracle
to pick the index:
/*+ INDEX(emp) */
Hint Description
FULL(table_name) Requests a full table scan of the specified table, regardless of any
indexes that may exist.
ROWID(table_name) Tells Oracle to perform a scan of the specified table based on
ROWIDs.
CLUSTER(table_name) Tells Oracle to do a cluster scan of the specified table. This hint is
ignored if the table is not clustered
HASH(table_name) Tells Oracle to perform a hash scan of the specified table. This hint
is ignored if the table is not clustered.
INDEX(table_name Tells Oracle to access the specified table via an index scan. You
[index_name...]) may specify which index to use; otherwise Oracle chooses the
index. You may also specify a list of indexes to choose from, and
Oracle will choose from that list.

Join order hints


Join order hints allow control over the order in which Oracle joins tables. There are only three of
these hints.

Page 59
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

Join Order Hints


Hint Description
ORDERED Tells Oracle to join tables from left to right, in the same order in which
they are listed in the FROM clause.
STAR Tells Oracle to use a star query execution plan, if at all possible. This
step can only work if at least three tables are joined, and the largest
table has a concatenated index on columns that reference the two
smaller tables. The two smaller tables are joined first, then a nested-loop
join is used to retrieve the required rows from the largest table.
STAR_TRANSFORMATION Tells Oracle to transform the query into a star query, if possible, and
then use the best plan for that query.

Summary
‰ Optimizer uses internal rules and available statistics to determine most efficient way of
producing result set of the query.
‰ There are two types of optimizer like rule based optimizer (RBO) and cost based
optimizer (CBO).
‰ Optimizer has the following components:
o Transforming Queries
o Estimating
o Generating Plans
‰ Explain plan is a provision through which you can explore the execution plan selected
by optimizer.
‰ Optimizer hints can be used with SQL statements to alter execution plans.

Page 60
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

Test Your Understanding


1. What is optimizer?
2. Which type of Optimizer is not recommended by Oracle in latest versions and why?
3. What is the input for Row source generator component?
4. Which optimizer goal should be opted for batch applications why?
5. What is an cost of executing a query ?
6. How do you look at execution plan selected by oracle for a specified query?

Page 61
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

Session 06: PL/SQL Performance Tuning

Learning Objectives
After the completing of this session, you would be able to:
‰ List the reasons for the PL/SQL performance issues
‰ Identify the PL/SQL performance issues
‰ List PL/SQL features for performance tuning
‰ State the standards and best practices in PL/SQL

When to Tune
Over time, even the performance of well-designed applications can degrade. So, periodic tuning is
an important part of application maintenance. You can make small adjustments that can drastically
improve performance. Consider tuning your PL/SQL code in the following scenarios:
‰ Programs that do a lot of mathematical calculations. You will want to investigate
the data types PLS_INTEGER, BINARY_FLOAT, and BINARY_DOUBLE.
‰ Functions that are called from PL/SQL queries, where the functions might be
executed millions of times. You will want to look at all performance features to make
the function as efficient as possible, and perhaps a function-based index to
precompute the results for each row and save on query time.
‰ Programs that spend a lot of time processing INSERT, UPDATE, or DELETE
statements, or looping through query results. You will want to investigate the FORALL
statement for issuing DML, and the BULK COLLECT INTO and RETURNING BULK
COLLECT INTO clauses for queries.
‰ Older code that does not take advantage of recent PL/SQL language features.
With the many performance improvements in Oracle Database 10g, any code from
earlier releases is a candidate for tuning.
‰ Any program that spends a lot of time doing PL/SQL processing, as opposed to
issuing DDL statements like CREATE TABLE that are just passed directly to SQL. You
will want to investigate native compilation. Because many built-in database features
use PL/SQL, you can apply this tuning feature to an entire database to improve
performance in many areas, not just your own code.

Before starting any tuning effort, benchmark the current system and measure how long particular
subprograms take. PL/SQL performance tuning can be achieved by following aspects.
1. Understanding the reasons for PL/SQL Performance Problems
2. Identifying PL/SQL Performance Problems
3. PL/SQL Features for Performance Tuning

Page 62
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

Reasons for PL/SQL Performance Problems


When a PL/SQL-based application performs poorly, it is often due to badly written SQL
statements, poor programming practices, inattention to PL/SQL basics, or misuse of shared
memory.

Badly Written SQL Statements


If a program contains many badly written SQL statements, no number of well-written PL/SQL
statements will help. If badly written SQL statements are slowing down your program, analyze their
execution plans and performance using the methods listed below. Then, rewrite the SQL
statements. For example, hints to the query optimizer can eliminate problems such as
unnecessary full-table scans.
‰ EXPLAIN PLAN statement
‰ SQL Trace facility with TKPROF utility
‰ Oracle Trace facility

Poor Programming Practices


Often, poor programming practices are a side effect of schedule crunches. In such circumstances,
even experienced programmers might write code that hampers performance.

No matter how suitable a programming language is for a given task, badly written subprograms
(for example, a slow sort or search function) can ruin performance. Suppose the subprogram
called most often by an application is a lookup function with hundreds of possible targets. If that
function could be written as a hash or a binary search but, instead, is written as a linear search,
overall performance suffers.

Other poor practices include declaring variables that are never used, passing unneeded
parameters to functions and procedures, placing initializations or computations inside a loop
needlessly, and so on.

Not Using Built-in Functions


PL/SQL provides many highly optimized functions such as REPLACE, TRANSLATE, SUBSTR,
INSTR, RPAD, and LTRIM. Do not hand code your own versions. Built-in functions are more
efficient. Even when a built-in function has more power than you need, use it rather than hand-
coding a subset of its functionality.

Inefficient Conditional Control Statements


When evaluating a logical expression, PL/SQL uses short-circuit evaluation. That is, PL/SQL stops
evaluating the expression as soon as the result can be determined. For example, in the following
OR expression, when the value of sal is less than 1500, the left operand yields TRUE, so PL/SQL
need not evaluate the right operand (because OR returns TRUE if either of its operands is true):
IF (salary < 1500) OR (commission IS NULL) THEN
...
END IF;

Page 63
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

Now, consider the following AND expression:


IF credit_ok(customer_id) AND (loan < 5000) THEN
...
END IF;

The Boolean function credit_ok is always called. However, if you switch the operands of AND
as follows
IF (loan < 5000) AND credit_ok(customer_id) THEN
...
END IF;
The function is called only when the expression loan < 5000 is true (because AND returns TRUE
only if both its operands are true). The same idea applies to EXIT-WHEN statements.

Implicit data type Conversions


At run time, PL/SQL converts between structurally different data types implicitly. For instance,
assigning a PLS_INTEGER variable to a NUMBER variable results in a conversion because their
internal representations are different.

Avoiding implicit conversions can improve performance. Look at the example below. The integer
literal 15 is represented internally as a signed 4-byte quantity, so PL/SQL must convert it to an
Oracle number before the addition. However, the floating-point literal 15.0 is represented as a 22-
byte Oracle number, so no conversion is necessary.
DECLARE
Count NUMBER;
BEGIN
Count := Count + 15; -- converted
Count := Count + 15.0; -- not converted
...
END;

Here is another example:


DECLARE
Count CHAR(5);
BEGIN
Count := 25; -- converted
Count := '25'; -- not converted
...
END;

Inappropriate declarations for numeric data types


The data type NUMBER and its subtypes are 22-byte, database-format numbers, designed for
portability and arbitrary scale/precision, not performance. When you need to declare an integer
variable, use the data type PLS_INTEGER, which is the most efficient numeric type. That is
because PLS_INTEGER values require less storage than INTEGER or NUMBER values. Also,
PLS_INTEGER operations use machine arithmetic, so they are faster than BINARY_INTEGER,
INTEGER, or NUMBER operations, which use library arithmetic.

Page 64
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

Unnecessary NOT NULL Constraints


In PL/SQL, using the NOT NULL constraint incurs a performance cost.
Consider the following example:
PROCEDURE Calculate_Total IS
Total NUMBER NOT NULL := 0;
Product1 NUMBER;
Product2 NUMBER;
BEGIN
...
Total := Product1 + Product2;
...
END;

As m is constrained by NOT NULL, the value of the expression a + b is assigned to a temporary


variable, which is then tested for nullity. If the variable is not null, its value is assigned to m.
Otherwise, an exception is raised. However, if m were not constrained, the value would be
assigned to m directly.

The more efficient way to write the last example follows:


PROCEDURE Calculate_Total IS
Total NUMBER; -- no constraint
Product1 NUMBER;
Product2 NUMBER;
BEGIN
...
Total := Product1 + Product2;
IF Total IS NULL THEN -- enforce constraint programmatically
...
END IF;
END;

Misuse of Shared Memory in a PL/SQL Program


PL/SQL is an interpretative language. The source code is “partially compiled” into an intermediate
form (“p-code”). The p-code is loaded into the shared pool when any element of that code
(package or stand-alone program) is referenced. The partially-compiled code is shared among all
users who have EXECUTE authority on the program/package.

Page 65
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

Subsequent calls to related subprograms in the package require no disk I/O, and your code
executes faster. However, if the package is aged out of memory, it must be reloaded if you
reference it again. You can improve performance by sizing the shared memory pool correctly.
Make sure it is large enough to hold all frequently used packages but not so large that memory is
wasted.

Identifying PL/SQL Performance Problems


As you develop larger and larger PL/SQL applications, it becomes more difficult to isolate
performance problems. So, PL/SQL provides a Profiler API to profile run-time behavior and to help
you identify performance bottlenecks. PL/SQL also provides a Trace API for tracing the execution
of programs on the server. You can use Trace to trace the execution by subprogram or exception.

The Profiler API:


The Profiler API is implemented as PL/SQL package DBMS_PROFILER, which provides services
for gathering and saving run-time statistics. The information is stored in database tables, which
you can query later. For example, you can learn how much time was spent executing each
PL/SQL line and subprogram.

To use the Profiler, you start the profiling session, run your application long enough to get
adequate code coverage; flush the collected data to the database, then stop the profiling session.
In a typical session, you take the following steps:
1. Start by calling the procedure start_profiler in package DBMS_PROFILER and
associating a comment with the Profiler session.
2. Run the application to be profiled.
3. Call the procedure flush_data repeatedly to save incremental data and free memory
allocated for data structures.
4. Stop by calling the procedure stop_profiler.

Page 66
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

The Profiler traces the execution of your program, computing the time spent at each line and in
each subprogram. You can use the collected data to improve performance. For instance, you
might focus on subprograms that run slowly.

Analyzing the Collected Performance Data


The next step is to determine why more time was spent executing certain code segments or
accessing certain data structures. Find the problem areas by querying the performance data.
Focus on the subprograms and packages that use up the most execution time, inspecting possible
performance bottlenecks such as SQL statements, loops, and recursive functions.

Using Trace Data to Improve Performance


Use the results of your analysis to rework slow algorithms. For example, due to an exponential
growth in data, you might need to replace a linear search with a binary search. Also, look for
inefficiencies caused by inappropriate data structures, and, if necessary, replace those data
structures.

Using Profiler
The first step is to install the DBMS_PROFILER package:
CONNECT sys/password@service AS SYSDBA
@$ORACLE_HOME/rdbms/admin/profload.sql

CREATE USER profiler IDENTIFIED BY profiler DEFAULT TABLESPACE users


QUOTA UNLIMITED ON users;
GRANT connect TO profiler;

CREATE PUBLIC SYNONYM plsql_profiler_runs FOR


profiler.plsql_profiler_runs;
CREATE PUBLIC SYNONYM plsql_profiler_units FOR
profiler.plsql_profiler_units;
CREATE PUBLIC SYNONYM plsql_profiler_data FOR
profiler.plsql_profiler_data;
CREATE PUBLIC SYNONYM plsql_profiler_runnumber FOR
profiler.plsql_profiler_runnumber;

CONNECT profiler/profiler@service
@$ORACLE_HOME/rdbms/admin/proftab.sql
GRANT SELECT ON plsql_profiler_runnumber TO PUBLIC;
GRANT SELECT, INSERT, UPDATE, DELETE ON plsql_profiler_data TO PUBLIC;
GRANT SELECT, INSERT, UPDATE, DELETE ON plsql_profiler_units TO PUBLIC;
GRANT SELECT, INSERT, UPDATE, DELETE ON plsql_profiler_runs TO PUBLIC;

Page 67
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

Next you create a dummy procedure to profile:


CREATE OR REPLACE PROCEDURE do_something (p_times IN NUMBER) AS
l_dummy NUMBER;
BEGIN
FOR i IN 1 .. p_times LOOP
SELECT l_dummy + 1
INTO l_dummy
FROM dual;
END LOOP;
END;
/

Next you start the profiler, run our procedure and stop the profiler:
DECLARE
l_result BINARY_INTEGER;
BEGIN
l_result := DBMS_PROFILER.start_profiler(run_comment => 'do_something:
' || SYSDATE);
do_something(p_times => 100);
l_result := DBMS_PROFILER.stop_profiler;
END;
/

With the profile complete you can analyze the data to see which bits of the process took the most
time, with all times presented in nanoseconds. First you check out which runs you have:
SET LINESIZE 200
SET TRIMOUT ON

COLUMN runid FORMAT 99999


COLUMN run_comment FORMAT A50
SELECT runid,
run_date,
run_comment,
run_total_time
FROM plsql_profiler_runs
ORDER BY runid;

RUNID RUN_DATE RUN_COMMENT RUN_TOTAL_TIME


----- --------- ---------------------------------- --------------
1 21-AUG-03 do_something: 21-AUG-2003 14:51:54 131072000

Page 68
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

You can then use the appropriate RUNID value in the following query:
COLUMN runid FORMAT 99999
COLUMN unit_number FORMAT 99999
COLUMN unit_type FORMAT A20
COLUMN unit_owner FORMAT A20

SELECT u.runid,
u.unit_number,
u.unit_type,
u.unit_owner,
u.unit_name,
d.line#,
d.total_occur,
d.total_time,
d.min_time,
d.max_time
FROM plsql_profiler_units u
JOIN plsql_profiler_data d ON u.runid = d.runid AND u.unit_number
= d.unit_number
WHERE u.runid = 1
ORDER BY u.unit_number, d.line#;

RUNID UNIT_NU UNIT_TYPE UNIT_OWNER UNIT_NAME LINE# TOTAL_OCCUR TOTAL_TIME MIN_TIME MAX_TIME

----- ------- --------------- ----------- ------------ ----- ----------- ---------- -------- --------

1 1 ANONYMOUS BLOCK <anonymous> <anonymous> 4 1 0 0 0

1 1 ANONYMOUS BLOCK <anonymous> <anonymous> 5 1 0 0 0

1 1 ANONYMOUS BLOCK <anonymous> <anonymous> 6 1 0 0 0

1 2 PROCEDURE MY_SCHEMA DO_SOMETHING 4 101 0 0 0

1 2 PROCEDURE MY_SCHEMA DO_SOMETHING 5 100 17408000 0 2048000

5 rows selected.

The results of this query show that line 4 of the DO_SOMETHING procedure ran 101 times but took
very little time, while line 5 ran 100 times and took proportionately more time. You can check the
line numbers of the source using the following query:
SELECT line || ' : ' || text
FROM all_source
WHERE owner = 'MY_SCHEMA'
AND type = 'PROCEDURE'
AND name = 'DO_SOMETHING';

LINE||':'||TEXT
---------------------------------------------------
1 : PROCEDURE do_something (p_times IN NUMBER) AS

Page 69
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

2 : l_dummy NUMBER;
3 : BEGIN
4 : FOR i IN 1 .. p_times LOOP
5 : SELECT l_dummy + 1
6 : INTO l_dummy
7 : FROM dual;
8 : END LOOP;
9 : END;

As expected, the query took proportionately more time than the procedural loop

The Trace API: Package DBMS_TRACE


With large, complex applications, it becomes difficult to keep track of calls between subprograms.
By tracing your code with the Trace API, you can see the order in which subprograms execute.
The Trace API is implemented as PL/SQL package DBMS_TRACE, which provides services for
tracing execution by subprogram or exception.

To use Trace, you start the tracing session, run your application, then stop the tracing session. As
the program executes, trace data is collected and stored in database tables. In a typical session,
you take the following steps:
1. Optionally, select specific subprograms for trace data collection.
2. Start by calling the procedure set_plsql_trace in package DBMS_TRACE.
3. Run the application to be traced.
4. Stop by calling the procedure clear_plsql_trace.

Controlling the Trace


Tracing large applications can produce huge amounts of data that are difficult to manage. Before
starting Trace, you can optionally limit the volume of data collected by selecting specific
subprograms for trace data collection.

In addition, you can choose a tracing level. For example, you can choose to trace all subprograms
and exceptions, or you can choose to trace selected subprograms and exceptions.

Using DBMS_Trace
The first step is to install the tables which will hold the trace data:
CONNECT sys/password@service AS SYSDBA
@$ORACLE_HOME/rdbms/admin/tracetab.sql

CREATE PUBLIC SYNONYM plsql_trace_runs FOR plsql_trace_runs;


CREATE PUBLIC SYNONYM plsql_trace_events FOR plsql_trace_events;
CREATE PUBLIC SYNONYM plsql_trace_runnumber FOR plsql_trace_runnumber;
GRANT SELECT, INSERT, UPDATE, DELETE ON plsql_trace_runs TO PUBLIC;
GRANT SELECT, INSERT, UPDATE, DELETE ON plsql_trace_events TO PUBLIC;
GRANT SELECT ON plsql_trace_runnumber TO PUBLIC;
Next you create a dummy procedure to trace:

Page 70
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

CREATE OR REPLACE PROCEDURE do_something (p_times IN NUMBER) AS


l_dummy NUMBER;
BEGIN
FOR i IN 1 .. p_times LOOP
SELECT l_dummy + 1
INTO l_dummy
FROM dual;
END LOOP;
END;
/

Next you run your procedure three times with different tracing levels:
DECLARE
l_result BINARY_INTEGER;
BEGIN
DBMS_TRACE.set_plsql_trace (DBMS_TRACE.trace_all_calls);
do_something(p_times => 100);
DBMS_TRACE.clear_plsql_trace;

DBMS_TRACE.set_plsql_trace (DBMS_TRACE.trace_all_sql);
do_something(p_times => 100);
DBMS_TRACE.clear_plsql_trace;

DBMS_TRACE.set_plsql_trace (DBMS_TRACE.trace_all_lines);
do_something(p_times => 100);
DBMS_TRACE.clear_plsql_trace;
END;
/

With the tracing complete you can identify the available RUNIDs using the following query:
SELECT r.runid,
TO_CHAR(r.run_date, 'DD-MON-YYYY HH24:MI:SS') AS run_date,
r.run_owner
FROM plsql_trace_runs r
ORDER BY r.runid;

RUNID RUN_DATE RUN_OWNER


---------- -------------------- -------------------------------
1 22-AUG-2003 08:27:18 TIM_HALL
2 22-AUG-2003 08:27:18 TIM_HALL
3 22-AUG-2003 08:27:18 TIM_HALL

Page 71
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

You can then use the appropriate RUNID in the following query to look at the trace:
SET LINESIZE 200
SET TRIMOUT ON

COLUMN runid FORMAT 99999


COLUMN event_seq FORMAT 99999
COLUMN event_unit_owner FORMAT A20
COLUMN event_unit FORMAT A20
COLUMN event_unit_kind FORMAT A20
COLUMN event_comment FORMAT A30

SELECT e.runid,
e.event_seq,
TO_CHAR(e.event_time, 'DD-MON-YYYY HH24:MI:SS') AS event_time,
e.event_unit_owner,
e.event_unit,
e.event_unit_kind,
e.proc_line,
e.event_comment
FROM plsql_trace_events e
WHERE e.runid = 1
ORDER BY e.runid, e.event_seq

PL/SQL Features for Performance Tuning


After correcting the flaws that slow down an application, you can use the following PL/SQL
features and techniques:
‰ Tuning PL/SQL performance with native dynamic SQL
‰ Tuning PL/SQL performance with bulk binds
‰ Tuning PL/SQL performance with the NOCOPY compiler hint
‰ Tuning PL/SQL performance with the RETURNING clause
‰ Tuning PL/SQL performance with external routines
‰ Improving PL/SQL performance with object types and collections
‰ Using optimizer settings to improve the performance

Tuning with Native Dynamic SQL


The SQL statements which do not change from execution to execution and the full SQL text is
known at the compile time are called Static SQL statements. Some programs must build and
process a variety of SQL statements at run time. For example, a general-purpose report writer
must build different SELECT statements for the various reports it generates. In this case, the full
text of the statement is unknown until run time. Such statements can, and probably will, change
from execution to execution. So, they are called dynamic SQL statements.

Page 72
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

Dynamic SQL statements are stored in character strings built by your program at run time. Such
strings must contain the text of a valid SQL statement or PL/SQL block. They can also contain
placeholders for bind arguments. A placeholder is an undeclared identifier, so its name, to which
you must prefix a colon, does not matter.

For example, PL/SQL makes no distinction between the following strings:


'DELETE FROM emp WHERE sal > :my_sal AND comm < :my_comm'
'DELETE FROM emp WHERE sal > :s AND comm < :c'

You need dynamic SQL in the following situations:


‰ You want to execute a SQL data definition statement (such as CREATE), a data control
statement (such as GRANT), or a session control statement (such as ALTER
SESSION). In PL/SQL, such statements cannot be executed statically.
‰ You want more flexibility. For example, you might want to defer your choice of schema
objects until run time. Or, you might want your program to build different search
conditions for the WHERE clause of a SELECT statement. A more complex program
might choose from various SQL operations, clauses, and so on.
‰ You use package DBMS_SQL to execute SQL statements dynamically, but you want
better performance, something easier to use, or functionality that DBMS_SQL lacks
such as support for objects and collections.

For improving the performance see the example below, Oracle opens a different cursor for each
distinct value of emp_id. This can lead to resource contention and poor performance.
CREATE PROCEDURE fire_employee (emp_id NUMBER) AS
BEGIN
EXECUTE IMMEDIATE
'DELETE FROM emp WHERE empno = ' || TO_CHAR(emp_id);
END;

You can improve performance by using a bind variable, as shown below. This allows Oracle to
reuse the same cursor for different values of emp_id.
CREATE PROCEDURE fire_employee (emp_id NUMBER) AS
BEGIN
EXECUTE IMMEDIATE
'DELETE FROM emp WHERE empno = :num' USING emp_id;
END;

Tuning PL/SQL Performance with Bulk Binds


When SQL statements execute inside a loop using collection elements as bind variables, context
switching between the PL/SQL and SQL engines can slow down execution. For example, the
following UPDATE statement is sent to the SQL engine with each iteration of the FOR loop:
DECLARE
TYPE NumList IS VARRAY(20) OF NUMBER;
depts NumList := NumList(10, 30, 70, ...); -- department numbers
BEGIN

Page 73
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

...
FOR i IN depts.FIRST..depts.LAST LOOP
...
UPDATE emp SET salary = salary * 1.10 WHERE deptno = depts(i);
END LOOP;
END;

In such cases, if the SQL statement affects four or more database rows, the use of bulk binds can
improve performance considerably. For example, the following UPDATE statement is sent to the
SQL engine just once, with the entire nested table:
FORALL i IN depts.FIRST..depts.LAST
UPDATE emp SET salary = salary * 1.10 WHERE deptno = depts(i);

If the SQL statement affects four or more database rows, the use of bulk binds can improve
performance considerably.

How do bulk binds improve performance?


The assigning of values to PL/SQL variables in SQL statements is called binding. PL/SQL binding
operations fall into three categories:
‰ In-bind When a PL/SQL variable or host variable is stored in the database by an
INSERT or UPDATE statement.
‰ Out-bind When a database value is assigned to a PL/SQL variable or a host variable
by the RETURNING clause of an INSERT, UPDATE, or DELETE statement.
‰ Define When a database value is assigned to a PL/SQL variable or a host variable by
a SELECT or FETCH statement.

A DML statement can transfer all the elements of a collection in a single operation, a process
known as bulk binding. If the collection has 20 elements, bulk binding lets you perform the
equivalent of 20 SELECT, INSERT, UPDATE, or DELETE statements using a single operation. This
technique improves performance by minimizing the number of context switches between the
PL/SQL and SQL engines. With bulk binds, entire collections, not just individual elements, are
passed back and forth.

To do bulk binds with INSERT, UPDATE, and DELETE statements, you enclose the SQL statement
within a PL/SQL FORALL statement. To do bulk binds with SELECT statements, you include the
BULK COLLECT clause in the SELECT statement instead of using INTO.

Example: Performing a Bulk Bind with DELETE


The following DELETE statement is sent to the SQL engine just once, even though it performs
three DELETE operations:
DECLARE
TYPE NumList IS VARRAY(20) OF NUMBER;
depts NumList := NumList(10, 30, 70); -- department numbers
BEGIN
FORALL i IN depts.FIRST..depts.LAST

Page 74
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

DELETE FROM emp WHERE deptno = depts(i);


END;

Tuning PL/SQL Performance with the NOCOPY Compiler Hint


By default, OUT and IN OUT parameters are passed by value. That is, the value of an IN OUT
actual parameter is copied into the corresponding formal parameter. Then, if the subprogram exits
normally, the values assigned to OUT and IN OUT formal parameters are copied into the
corresponding actual parameters.

When the parameters hold large data structures such as collections, records, and instances of
object types, all this copying slows down execution and uses up memory. To prevent that, you can
specify the NOCOPY hint, which allows the PL/SQL compiler to pass OUT and IN OUT parameters
by reference. In the following example, you ask the compiler to pass IN OUT parameter my_unit
by reference instead of by value:
DECLARE
TYPE Platoon IS VARRAY(200) OF Soldier;
PROCEDURE reorganize (my_unit IN OUT NOCOPY Platoon) IS ...
BEGIN
...
END;

Tuning PL/SQL Performance with the RETURNING Clause


Often, applications need information about the row affected by a SQL operation, for example, to
generate a report or take a subsequent action. The INSERT, UPDATE, and DELETE statements
can include a RETURNING clause, which returns column values from the affected row into PL/SQL
variables or host variables. This eliminates the need to SELECT the row after an insert or update,
or before a delete. As a result, fewer network round trips, less server CPU time, fewer cursors, and
less server memory are required.

In the following example, you update the salary of an employee and at the same time retrieve the
employee's name and new salary into PL/SQL variables.
PROCEDURE update_salary (emp_id NUMBER) IS
name VARCHAR2(15);
new_sal NUMBER;
BEGIN
UPDATE emp SET sal = sal * 1.1
WHERE empno = emp_id
RETURNING ename, sal INTO name, new_sal;
-- Now do computations involving name and new_sal
END;

Improving PL/SQL performance with object types and collections


Objects and collections are more efficient to store and retrieve because they can be manipulated
as a whole. Also, object support is integrated with the database architecture, so it can take
advantage of the many scalability and performance improvements built into each Oracle release.

Page 75
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

Collection: A collection is an ordered group of elements, all of the same type. It is a general
concept that encompasses lists, arrays, and other familiar data types. PL / SQL offer the following
collection type
‰ Associate Arrays (index- by tables)
‰ Nested Tables
‰ Varrays

Varrays Example:
In SQL*Plus, suppose you define object type Project, as follows:
SQL> CREATE TYPE Project AS OBJECT (
2 project_no NUMBER(2),
3 title VARCHAR2(35),
4 cost NUMBER(7,2));

Next, you define VARRAY type ProjectList, which stores Project objects:
SQL> CREATE TYPE ProjectList AS VARRAY(50) OF Project;

Finally, you create relational table department, which has a column of type ProjectList, as
follows:
SQL> CREATE TABLE department (
2 dept_id NUMBER(2),
3 name VARCHAR2(15),
4 budget NUMBER(11,2),
5 projects ProjectList);

Each item in column projects is a varray that will store the projects scheduled for a given
department.
Now, you are ready to populate relational table department. In the following example, notice how
varray constructor ProjectList() provides values for column projects:
BEGIN
INSERT INTO department
VALUES(30, 'Accounting', 1205700,
ProjectList(Project(1, 'Design New Expense Report', 3250),
Project(2, 'Outsource Payroll', 12350),
Project(3, 'Evaluate Merger Proposal', 2750),
Project(4, 'Audit Accounts Payable', 1425)));
INSERT INTO department
VALUES(50, 'Maintenance', 925300,
ProjectList(Project(1, 'Repair Leak in Roof', 2850),
Project(2, 'Install New Door Locks', 1700),
Project(3, 'Wash Front Windows', 975),
Project(4, 'Repair Faulty Wiring', 1350),
Project(5, 'Winterize Cooling System', 1125)));
INSERT INTO department

Page 76
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

VALUES(60, 'Security', 750400,


ProjectList(Project(1, 'Issue New Employee Badges', 13500),
Project(2, 'Find Missing IC Chips', 2750),
Project(3, 'Upgrade Alarm System', 3350),
Project(4, 'Inspect Emergency Exits', 1900)));
END;

In the following example, you update the list of projects assigned to the Security Department:
DECLARE
new_projects ProjectList :=
ProjectList(Project(1, 'Issue New Employee Badges', 13500),
Project(2, 'Develop New Patrol Plan', 1250),
Project(3, 'Inspect Emergency Exits', 1900),
Project(4, 'Upgrade Alarm System', 3350),
Project(5, 'Analyze Local Crime Stats', 825));
BEGIN
UPDATE department
SET projects = new_projects WHERE dept_id = 60;
END;

In the next example, you retrieve all the projects for the Accounting Department into a local varray:
DECLARE
my_projects ProjectList;
BEGIN
SELECT projects INTO my_projects FROM department
WHERE dept_id = 30;
END;

In the final example, you delete the Accounting Department and its project list from table
department:
BEGIN
DELETE FROM department WHERE dept_id = 30;
END;

Performing INSERT, UPDATE, and DELETE Operations on a Varray with SQL


Currently, you cannot reference the individual elements of a varray in an INSERT, UPDATE, or
DELETE statement. You must retrieve the entire varray, use PL/SQL procedural statements to add,
delete, or update its elements, and then store the changed varray back in the database table.

In the following example, stored procedure ADD_PROJECT inserts a new project into a
department's project list at a given position:
CREATE PROCEDURE add_project (
dept_no IN NUMBER,
new_project IN Project,

Page 77
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

position IN NUMBER) AS
my_projects ProjectList;
BEGIN
SELECT projects INTO my_projects FROM department
WHERE dept_no = dept_id FOR UPDATE OF projects;
my_projects.EXTEND; -- make room for new project
/* Move varray elements forward. */
FOR i IN REVERSE position..my_projects.LAST - 1 LOOP
my_projects(i + 1) := my_projects(i);
END LOOP;
my_projects(position) := new_project; -- add new project
UPDATE department SET projects = my_projects
WHERE dept_no = dept_id;
END add_project;

Optimizer settings to improve performance


In Oracle releases prior to 10g, the PL/SQL compiler translated your code to machine code without
applying many changes for performance. Now, PL/SQL uses an optimizing compiler that can
rearrange code for better performance.

Now the PL/SQL optimizing compiler will transform the query to a better performing query based
on the transformation rules defined. PLSQL optimizing compiler will behave similar to SQL
compiler. To enable the PLSQL optimizing compiler to give you better performances you need to
assign the following value to the initialization parameter “plsql_optimization_level“ . Following are
the possible values and related behaviors.
‰ 2: Most aggressive, maximum possible code transformations, biggest impact on
compile time while compiling large applications.
‰ 1: Smaller scale change, less impact on compile times.
‰ 0: Pre-10g compilation without any optimization

Use the following statement to alter the plsql_optimization_level parameter for a session.
Alter session set PLSQL_OPTIMIZE_LEVEL=0;

PL/SQL Standards and Best Practices


Most of the PL/SQL code performs poorly because of the worst coding practices followed.
Following are the lists of best coding practices which will help you in getting a PLSQL application
which will have better performance.

Make Function calls as efficient as possible


Badly written subprograms (for example, a slow sort or search function) can harm performance.
Avoid unnecessary calls to subprograms, and optimize their code:
BEGIN
-- Inefficient, calls function for every row
FOR item IN (SELECT DISTINCT(SQRT(department_id)) col_alias FROM
employees)

Page 78
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

LOOP
DBMS_OUTPUT.PUT_LINE(item.col_alias);
END LOOP;
-- Efficient, only calls function once for each distinct value.
FOR item IN
( SELECT SQRT(department_id) col_alias FROM
( SELECT DISTINCT department_id FROM employees)
)
LOOP
DBMS_OUTPUT.PUT_LINE(item.col_alias);
END LOOP;
END;

Reorder conditional tests to put the least expensive first


PL/SQL stops evaluating a logical expression as soon as the result can be determined. This
functionality is known as short-circuit evaluation. When evaluating multiple conditions separated by
AND or OR, put the least expensive ones first. For example, check the values of PL/SQL variables
before testing function return values, because PL/SQL might be able to skip calling the functions.

Reducing Loop Overhead for DML statements


Use FORALL Statement: The keyword FORALL lets you run multiple DML statements very
efficiently. It can only repeat a single DML statement, unlike a general-purpose FOR loop. Instead
of context switching from PLSQL Engine to SQL Engine for every statement value when you used
FORALL statement context switching will happen only once from PLSQL runtime engine to SQL
Engine.

In the following example PLSQL engine sends the all three delete statements to SQL engine at
once.
CREATE TABLE employees_temp AS SELECT * FROM employees;
DECLARE
TYPE NumList IS VARRAY(20) OF NUMBER;
depts NumList := NumList(10, 30, 70); -- department numbers
BEGIN
FORALL i IN depts.FIRST..depts.LAST
DELETE FROM employees_temp WHERE department_id = depts(i);
COMMIT;
END;

Use FORALL and BULK COLLECT together: Bulk collect clause can be used along with FORALL
statement to increase the performance.
CREATE TABLE emp_temp AS SELECT * FROM employees;
DECLARE
TYPE NumList IS TABLE OF NUMBER;
depts NumList := NumList(10,20,30);
TYPE enum_t IS TABLE OF employees.employee_id%TYPE;

Page 79
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

TYPE dept_t IS TABLE OF employees.department_id%TYPE;


e_ids enum_t;
d_ids dept_t;
BEGIN
FORALL j IN depts.FIRST..depts.LAST
DELETE FROM emp_temp WHERE department_id = depts(j)
RETURNING employee_id, department_id BULK COLLECT INTO e_ids,
d_ids;
DBMS_OUTPUT.PUT_LINE('Deleted ' || SQL%ROWCOUNT || ' rows:');
FOR i IN e_ids.FIRST .. e_ids.LAST
LOOP
DBMS_OUTPUT.PUT_LINE('Employee #' || e_ids(i) || ' from dept #' ||
d_ids(i));
END LOOP;
END;

Always fetch into Cursor Records


Always fetch the values into the cursor records instead of fetching it into individual variables. This
also avoids changing the variable data type in case of table column data type changes.

Use Anchored Declarations:


As Oracle 10G gains more ground, a term that you will all hear repeatedly is 'self-managing'.
Oracle has incorporated features in this version that would reduce DBA intervention to manage it.
It would be nice to introduce some 'self-management' features into our PL/SQL code as well.

Developers and support personnel alike are faced, quite often, with a situation where the
definitions of the tables have to be altered from one data type to another. In an ideal world nothing
else would need modification. Realistically, this can break all the PL/SQL code that is based on
this table. Modifying all this code can be a daunting task. Using anchored declarations can bring
our ideal world a step closer to us.

Page 80
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

Wherever possible use anchored declarations rather than explicit data type references as given
below.

Let's assume you have a table called ITEMS, defined as follows:


Name Null? Type
--------------- ------------ --------
ITEM_ID NUMBER
ITM_DESCRIPTION VARCHAR2(60)
PRICE NUMBER(5,2)
QTY NUMBER

Also, suppose there is a stored procedure that prints out an alert message when the quantity of an
item in stock falls below a certain limit.
CREATE OR REPLACE PROCEDURE inventory_update (item_id_in IN NUMBER) IS
v_qty NUMBER;
BEGIN
SELECT qty into v_qty FROM items WHERE item_id = item_id_in;

IF (v_qty < 10 ) THEN


DBMS_OUTPUT.PUT_LINE ('Warning: Stock low...');
END IF;
END inventory_update;
What happens if you later decide to change the definition for the item_id field from NUMBER to
VARCHAR2(20)? The code above will fail. In order to write the code in a way that it remains un-
effected in the face of the changing data type of a column, replace the definition for the parameter
item_id_in from NUMBER to an anchored data type items.item_cd%TYPE like this:
CREATE OR REPLACE PROCEDURE inventory_update(item_id_in IN
items.item_id%TYPE) IS

Doing this will cause the code to have the same data type as that of the column in the table. Your
code will work without any modification.

Use Bind Variables:


A key to improved code performance is the use of bind variables. It is a simple technique yet
powerful enough to improve performance of the PL/SQL code by several orders of magnitude,
depending on the type and size of data. The reason for that lies in the manner DML statements are
handled in Oracle. When an Oracle SQL statement is issued, the statement is parsed and saved in

Page 81
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

a shared memory area so that when the same statement is issued again by the program, the
system can skip the parsing step, thus saving processing time and resources.

The following code is given for the purpose of demonstration and comparison only and may not
reflect real-life situation.
DECLARE
BEGIN
FOR i IN 1 .. 1000 LOOP
EXECUTE IMMEDIATE
'SELECT item_id, qty FROM items WHERE qty = ' || i;
END LOOP;
END;
Every iteration of the loop produces the following statements:
SELECT item_id, qty FROM items WHERE qty = 1;
SELECT item_id, qty FROM items WHERE qty = 2;
SELECT item_id, qty FROM items WHERE qty = 3;
and so on.

When the system checks the shared memory area (shared pool) it considers each statement to be
unique and fails to make use of the parsed information already available. You, however, know that
the statements are almost identical. Bind variables can help remedy this situation. Consider the
following code:
DECLARE
BEGIN
FOR i IN 1 .. 1000 LOOP
EXECUTE IMMEDIATE
'SELECT item_id, qty FROM items WHERE qty = :x' using i;
END LOOP;
END;

In this case the parser will get exactly the same information in every loop iteration and would not
have to re-parse the SQL statement.

Not only that the code is faster with the use of the bind variables, it is also less CPU intensive and
allows better sharing of resources by decreasing the number of latches resulting in not just better
performing code but a better performing system as a whole.

As is evident from the code examples above, bind variables are applicable in situations where
dynamic SQL is being used. Since today's graphical user interface programming makes very
heavy use of dynamic SQL, there are more opportunities of realizing the advantage of bind
variables.

Use BULK Collects:


Performance tuning falls under the realm of DBA duties more than developers. However,
developers have an equal stake in the performance and there is a lot that can be done at the code-
level to achieve this goal. One of these is the use of bulk collects.

Page 82
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

By using bulk collects, you can load multiple rows into the collections rather than one at a time
thus reducing strain on database resources by reducing the pass to the database.
CREATE OR replace PROCEDURE no_bulk_proc is
CURSOR item_cur IS
SELECT items.item_id, qty FROM items;

item_rec item_cur%ROWTYPE;
BEGIN
OPEN item_cur;
LOOP
FETCH item_cur INTO item_rec;
EXIT WHEN item_cur%notfound;
dbms_output.put_line(item_rec.item_id);
dbms_output.put_line(item_rec.qty);
END LOOP;
END no_bulk_proc;
Without using BULK collects

CREATE OR REPLACE PROCEDURE bulk_proc IS


CURSOR item_cur IS
SELECT item_id, qty FROM items;

TYPE t_item IS TABLE OF ITEMS.item_id%TYPE INDEX BY BINARY_INTEGER;


TYPE t_qty IS TABLE OF ITEMS.qty%TYPE INDEX BY BINARY_INTEGER;

v_item t_item;
v_qty t_qty;
BEGIN
OPEN item_cur;
FETCH item_cur bulk collect INTO v_item, v_qty limit 100;

FOR i IN v_item.first .. v_item.last LOOP


dbms_output.put_line(v_item(i));
dbms_output.put_line(v_qty(i));
END LOOP;

CLOSE item_cur;
END bulk_proc;
Using BULK collects

Here the 'limit 100' loads only 100 records into memory for processing which provides an added
benefit that you have reduced the risk of running out of main memory as opposed to the code in
figure which may run into memory issues.
Write SQL Efficiently in PL/SQL Programs

Page 83
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

When you write SQL statements inside PL/SQL programs make sure it is more efficient and it does
not use hard parsing when you call it repeatedly with different values. For example when you want
to delete the employee records from a table based on the passed value. Make sure the emp_id
which is supplied in the where criteria of the delete statement is passed through a bind variable
rather than using a local variable and assigning to it. Other tips for writing efficient SQL Statements
in PL/SQL is given as follows
‰ Use native SQL whenever possible: Find below the comparison between the native
SQL and the dynamic SQL. When native SQL is used the code become dramatically
less at the same time it increases the performance also
.
Dynamic SQL Native SQL
CREATE OR REPLACE PROCEDURE CREATE OR REPLACE PROCEDURE
showemps ( showemps (
where_in IN VARCHAR2 := NULL) where_in IN VARCHAR2 := NULL)
IS IS
cur INTEGER := TYPE cv_typ IS REF CURSOR;
DBMS_SQL.OPEN_CURSOR; cv cv_typ;
rec employee%ROWTYPE; v_id employee.employee_id%TYPE;
fdbk INTEGER; v_nm employee.last_name%TYPE;
BEGIN BEGIN
DBMS_SQL.PARSE OPEN cv FOR
(cur, 'SELECT employee_id,
'SELECT employee_id, last_name
last_name FROM employee
FROM employee WHERE ' || NVL (where_in,
WHERE ' || NVL (where_in, '1=1');
'1=1'), LOOP
DBMS_SQL.NATIVE); FETCH cv INTO v_id, v_nm;
EXIT WHEN cv%NOTFOUND;
DBMS_SQL.DEFINE_COLUMN (cur, 1, DBMS_OUTPUT.PUT_LINE (
1); TO_CHAR (v_id) || '=' ||
DBMS_SQL.DEFINE_COLUMN (cur, 2, v_nm);
user, 30); END LOOP;
CLOSE cv;
fdbk := DBMS_SQL.EXECUTE (cur); END;
LOOP
/* Fetch next row. Exit when
done. */
EXIT WHEN DBMS_SQL.FETCH_ROWS
(cur) = 0;
DBMS_SQL.COLUMN_VALUE (cur,
1, rec.employee_id);
DBMS_SQL.COLUMN_VALUE (cur,
2, rec.last_name);
DBMS_OUTPUT.PUT_LINE (
TO_CHAR (rec.employee_id)

Page 84
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

Dynamic SQL Native SQL


|| '=' ||
rec.last_name);
END LOOP;
DBMS_SQL.CLOSE_CURSOR (cur);
END;

‰ Use PL/SQL to replace IO-intensive SQL. Make use of PL/SQL to avoid intensive /
big SQL statements An example of this is given as follows:

‰ Use the RETURNING Clause: Use Returning clause to collect the recently updated/
deleted values that is processed by a statement. An example is given below for better
understanding.

Instead of the first block use the approach in second block

‰ Use WHERE CURRENT OF: When using SELECT FOR UPDATE, use the WHERE
CURRENT OF clause in UPDATE and DELETE to avoid coding a possibly complex and
slower WHERE clause.

Page 85
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

‰ Never put the variable and other data structures in package specification:
Mostly try to have the variables and bulky data structures in the package body instead
of the package specifications
‰ Avoid Multiple returns in the functions: Multiple RETURNs in the executable section
make it error-prone and difficult to maintain.

Avoid Repetitive Code


Avoid writing repetitive code inside your package bodies. This is a particular danger when you
overload multiple programs with the same name. Often the implementation of each of these
programs is very similar. You will be tempted to simply cut and paste and then make the
necessary changes. However, you will be much better off if you take the time to create a private
program in the package which incorporates all common elements, and then have each overloaded
program call that program.

Page 86
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

Other Best Practices


Once you get beyond the "big ticket" best practices, there are many very concrete
recommendations for how to write specific lines of code and constructs. Many of these
suggestions have been around for years and apply to all programming languages. So if you took a
good programming class in college, then do not throw away those books! The specific syntax may
change, but the fundamental common sense motivation for what you have learned in the past will
certainly work with PL/SQL as well.

Without a doubt, if you can follow these guidelines, you are sure to end up with programs which
are easier to maintain and enhance:
‰ Never exit from a FOR loop (numeric or cursor) with an EXIT or RETURN statement. A
FOR loop is a promise: my code will iterate from the starting to the ending value and
will then stop execution.
‰ Never exit from a WHILE loop with an EXIT or RETURN statement. Rely solely on the
WHILE loop condition to terminate the loop.
‰ Ensure that a function has a single successful RETURN statement as the last line of the
executable section. Normally, each exception handler in a function would also return a
value.
‰ Don't let functions have OUT or IN OUT parameters. The function should only return
values through the RETURN clause.
‰ Make sure that the name of a function describes the value being returned (noun
structure, as in "total_compensation"). The name of a procedure should describe
the actions taken (verb-noun structure, as in "calculate_totals").
‰ Never declare the FOR loop index (either an integer or a record). This is done for you
implicitly by the PL/SQL runtime engine.
‰ Do not use exceptions to perform branching logic. When you define your own
exceptions, these should describe error situations only.
‰ When you use the ELSIF statement, make sure that each of the clauses is mutually
exclusive. Watch out especially for logic like "sal BETWEEN 1 and 10000" and
"sal BETWEEN 10000 and 20000."
‰ Remove all hardcoded "magic values" from your programs and replace them with
named constants or functions defined in packages.
‰ Do not "SELECT COUNT(*)" from a table unless you really need to know the total
number of "hits." If you only need to know whether there is more than one match,
simply fetch twice with an explicit cursor.
‰ Do not use the names of tables or columns for variable names. This can cause
compile errors. It can also result in unpredictable behavior inside SQL statements in
your PL/SQL code. Once did a global search and replace of :GLOBAL.regcd to
regcd (a local variable declared as VARCHAR2(10) but also, unfortunately, the name
of a column). Our Q&A procedures were very weak and we ended up rolling out into
production a program with a DELETE statement containing a WHERE clause that looked
like this:
WHERE regcd = regcd

Needless to say, this caused many headaches. If you had simply changed the global reference to
v_regcd, you would have avoided all such problems.

Page 87
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

Summary
‰ Following are the reasons for PL/SQL performance problems:
o Badly written SQL statements
o Poor programming practices
o Not using the build-in features present in Oracle
o Inefficient conditional control statements
‰ Some poor programming practices are as follows:
o Declaring variables that are never used
o Passing unneeded parameters to functions and procedures
o PL/SQL provides a profiler API to profile run-time behavior to find the performance
barriers.
‰ PL/SQL provides a profiler API to profile run-time behavior to find the performance
barriers.

Test Your Understanding


1. You would like to do an update on a set of values based on criteria and collect the updated
records into a table. How do you do it efficiently?
2. Why PL/SQL programs offers more performance advantages while compared to SQL
queries?

Page 88
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

Session 07: Oracle Performance Tuning Tools

Learning Objectives
After completing this session, you will be able to:
‰ Explain the Execute Plan
‰ Generate Explain Plan
‰ Explain SQL Trace
‰ Identify TKPROF utilities
‰ State the steps in using SQL Trace and TKPROF utility
‰ Describe the TKPROF results

Explain Plan
The EXPLAIN PLAN is a statement used for displaying the execution plans chosen by the Oracle
optimizer for SELECT, UPDATE, INSERT, and DELETE statements. A statement's execution plan is
the sequence of operations Oracle performs to run the statement. When an SQL statement is
passed to the server the Cost Based Optimizer (CBO) uses database statistics to create an
execution plan which it uses to navigate through the data. Once you've highlighted a problem
query the first thing you should do is EXPLAIN the statement to check the execution plan that the
CBO has created. This will often reveal that the query is not using the relevant indexes, or indexes
to support the query are missing.

An Overview of EXPLAIN PLAN


Before the database server can execute a SQL statement, Oracle must first parse the statement
and develop an execution plan. The execution plan is a task list of sorts that decomposes a
potentially complex SQL operation into a series of basic data access operations. For example, a
query against the dept table might have an execution plan that consists of an index lookup on the
deptno index, followed by a table access by ROWID.

The EXPLAIN PLAN statement allows you to submit a SQL statement to Oracle and have the
database prepare the execution plan for the statement without actually executing it. The execution
plan is made available to you in the form of rows inserted into a special table called a plan table.
You may query the rows in the plan table using ordinary SELECT statements in order to see the
steps of the execution plan for the statement you explained. You may keep multiple execution
plans in the plan table by assigning each a unique statement_id. Or you may choose to delete the
rows from the plan table after you are finished looking at the execution plan. You can also roll back
an EXPLAIN PLAN statement in order to remove the execution plan from the plan table.

The EXPLAIN PLAN statement runs very quickly, even if the statement being explained is a query
that might run for hours. This is because the statement is simply parsed and its execution plan
saved into the plan table. The actual statement is never executed by EXPLAIN PLAN. Along these
same lines, if the statement being explained includes bind variables, the variables never need to
actually be bound. The values that would be bound are not relevant since the statement is not
actually executed.

Page 89
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

You do not need any special system privileges in order to use the EXPLAIN PLAN statement.
However, you do need to have INSERT privileges on the plan table, and you must have sufficient
privileges to execute the statement you are trying to explain. The one difference is that in order to
explain a statement that involves views, you must have privileges on all of the tables that make up
the view. If you do not, you will get an “ORA-01039: insufficient privileges on underlying objects of
the view” error.

Understanding Execution Plans


With the query optimizer, execution plans can and do change as the underlying optimizer inputs
change. EXPLAIN PLAN output shows how Oracle runs the SQL statement when the statement
was explained. This can differ from the plan during actual execution for a SQL statement, because
of differences in the execution environment and explain plan environment.

Execution plans can differ due to the following:


‰ Different Schemas
‰ Different Costs

Different Schemas
‰ The execution and explain plan happen on different databases.
‰ The user explaining the statement is different from the user running the statement.
Two users might be pointing to different objects in the same database, resulting in
different execution plans.
‰ Schema changes (usually changes in indexes) between the two operations.

Different Costs
Even if the schemas are the same, the optimizer can choose different execution plans if the costs
are different. Some factors that affect the costs include the following:
‰ Data volume and statistics
‰ Bind variable types and values
‰ Initialization parameters: Set globally or at session level

Examining an explain plan lets you look for throw-away in cases such as the following:
‰ Full scans
‰ Unselective range scans
‰ Late predicate filters
‰ Wrong join order
‰ Late filter operations

For example, in the following explain plan, the last step is a very unselective range scan that is
executed 76563 times, accesses 11432983 rows, throws away 99% of them, and retains 76563
rows. Why access 11432983 rows to realize that only 76563 rows are needed?

Page 90
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

Example: Looking for Throw-Away in an Explain Plan

Rows Execution Plan


-------- ----------------------
12 SORT AGGREGATE
2 SORT GROUP BY
76563 NESTED LOOPS
76575 NESTED LOOPS
19 TABLE ACCESS FULL CN_PAYRUNS_ALL
76570 TABLE ACCESS BY INDEX ROWID CN_POSTING_DETAILS_ALL
76570 INDEX RANGE SCAN (object id 178321)
76563 TABLE ACCESS BY INDEX ROWID CN_PAYMENT_WORKSHEETS_ALL
11432983 INDEX RANGE SCAN (object id 186024)

Using the EXPLAIN PLAN Statement


‰ Before you can use the EXPLAIN PLAN statement, you must have INSERT privileges
on a plan table. The plan table can have any name you like, but the names and data
types of the columns are not flexible. You will find a script called utlxplan.sql in
$ORACLE_HOME/rdbms/admin that creates a plan table with the name plan_table in
the local schema. If you use this script to create your plan table, you can be assured
that the table will have the right definition for use with EXPLAIN PLAN.
‰ Once you have access to a plan table, you are ready to run the EXPLAIN PLAN
statement. The syntax is as follows:

EXPLAIN PLAN [SET STATEMENT_ID = <string in single


quotes>]
[INTO <plan table name>]
FOR <SQL statement>;

If you do not specify the INTO clause, then Oracle assumes the name of the plan table is
plan_table. You can use the SET clause to assign a name to the execution plan. This is useful if
you want to be able to have multiple execution plans stored in the plan table at once giving each
execution plan a distinct name enables you to determine which rows in the plan table belong to
which execution plan.

The EXPLAIN PLAN statement runs quickly because all Oracle has to do is parse the SQL
statement being explained and store the execution plan in the plan table. The SQL statement can
include bind variables, although the variables will not get bound and the values of the bind
variables will be irrelevant.

If you issue the EXPLAIN PLAN statement from SQL*Plus, you will get back the feedback
message “Explained.” At this point the execution plan for the explained SQL statement has been
inserted into the plan table, and you can now query the plan table to examine the execution plan.

Execution plans are a hierarchical arrangement of simple data access operations. As of the
hierarchy, you need to use a CONNECT BY clause in your query from the plan table. Using the
LPAD function, you can cause the output to be formatted in such a way that the indenting helps

Page 91
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

you traverse the hierarchy. There are many different ways to format the data retrieved from the
plan table. No one query is the best, because the plan table holds a lot of detailed information.
Different DBAs will find different aspects more useful in different situations.

A simple SQL*Plus script to retrieve an execution plan from the plan table is as follows:
REM
REM explain.sql
REM

SET VERIFY OFF


SET PAGESIZE 100

ACCEPT stmt_id CHAR PROMPT "Enter statement_id: "

COL id FORMAT 999


COL parent_id FORMAT 999 HEADING "PARENT"
COL operation FORMAT a35 TRUNCATE
COL object_name FORMAT a30

SELECT id, parent_id, LPAD (' ', LEVEL - 1) || operation || '


' ||
options operation, object_name
FROM plan_table
WHERE statement_id = '&stmt_id'
START WITH id = 0
AND statement_id = '&stmt_id'
CONNECT BY PRIOR
id = parent_id
AND statement_id = '&stmt_id';

‰ You have a simple query that you will use in a few examples. You will call this “the
invoice item query.” The query is as follows:

SELECT a.customer_name, a.customer_number,


b.invoice_number,
b.invoice_type, b.invoice_date, b.total_amount,
c.line_number,
c.part_number, c.quantity, c.unit_cost
FROM customers a, invoices b, invoice_items c
WHERE c.invoice_id = :b1
AND c.line_number = :b2
AND b.invoice_id = c.invoice_id
AND a.customer_id = b.customer_id;

Page 92
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

The explain.sql SQL*Plus script above displays the execution plan for the invoice item query as
follows:

ID PARENT OPERATION OBJECT_NAME


---- ------ ----------------------------------- ---------------
0 SELECT STATEMENT
1 0 NESTED LOOPS
2 1 NESTED LOOPS
3 2 TABLE ACCESS BY INDEX ROWID INVOICE_ITEMS
4 3 INDEX UNIQUE SCAN
INVOICE_ITEMS_PK
5 2 TABLE ACCESS BY INDEX ROWID INVOICES
6 5 INDEX UNIQUE SCAN INVOICES_PK
7 1 TABLE ACCESS BY INDEX ROWID CUSTOMERS
8 7 INDEX UNIQUE SCAN CUSTOMERS_PK

‰ The execution plan shows that Oracle is using nested loops joins to join three tables,
and that accesses from all three tables are by unique index lookup. This is probably a
very efficient query.
‰ When you no longer need an execution plan, you should delete it from the plan table.
You can do this by rolling back the EXPLAIN PLAN statement (if you have not
committed yet) or by deleting rows from the plan table. If you have multiple execution
plans in the plan table, then you should delete selectively by statement_id. Note that if
you explain two SQL statements and assign both the same statement_id, you will get
an ugly cartesian product when you query the plan table!

Explain Plan: Execution


‰ An execution plan is a hierarchical structure somewhat like an inverted tree. The SQL
statement being examined can be thought of as the root of the tree. This will be the
first line on an execution plan listing, the line that is least indented. This statement can
be thought of as the result of one or more subordinate operations. Each of these
subordinate operations can possibly be decomposed further. This decomposition
process continues repeatedly until eventually even the most complex SQL statement
is broken down into a set of basic data access operations.
‰ Consider the following simple query and execution plan:

SELECT customer_id, customer_number, customer_name


FROM customers
WHERE UPPER (customer_name) LIKE 'ACME%'
ORDER BY customer_name;

ID PARENT OPERATION OBJECT_NAME


---- ------ ----------------------------------- ---------------
0 SELECT STATEMENT
1 0 SORT ORDER BY
2 1 TABLE ACCESS FULL CUSTOMERS

Page 93
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

‰ The root operation which you explained is a SELECT statement. The output of the
statement will be the results of a sort operation (for the purposes of satisfying the
ORDER BY clause). The input to the sort will be the results of a full table scan of the
customers table. Stated more clearly, the database server will execute this query by
checking every row in the customers table for a criteria match and sorting the results.
Perhaps the developer expected Oracle to use an index on the customer_name
column to avoid a full table scan, but the use of the UPPER function defeated the
index. (A function-based index could be deployed to make this query more efficient.)

Consider the following query and execution plan:

SELECT a.customer_name, b.invoice_number, b.invoice_date


FROM customers a, invoices b
WHERE b.invoice_date > TRUNC (SYSDATE - 1)
AND a.customer_id = b.customer_id;

ID PARENT OPERATION OBJECT_NAME


---- ------ ----------------------------------- -----------------------
-------
0 SELECT STATEMENT
1 0 NESTED LOOPS
2 1 TABLE ACCESS BY INDEX ROWID INVOICES
3 2 INDEX RANGE SCAN INVOICES_DATE
4 1 TABLE ACCESS BY INDEX ROWID CUSTOMERS
5 4 INDEX UNIQUE SCAN CUSTOMERS_PK

‰ Again, the root operation is a SELECT statement. This time, the SELECT statement
gets its input from the results of a nested loops join operation. The nested loops
operation takes as input the results of accesses to the invoices and customers tables.
(You can tell from the indenting that accesses to both tables feed directly into the
nested loops operation.) The invoices table is accessed by a range scan of the
invoices_date index, while the customers table is accessed by a unique scan of
the customers_pk index.
‰ In plainer language, here is how Oracle will execute this query: Oracle will perform a
range scan on the invoices_date index to find the ROWIDs of all rows in the
invoices table that have an invoice date matching the query criteria. For each ROWID
found, Oracle will fetch the corresponding row from the invoices table, look up the
customer_id from the invoices record in the customers_pk index, and use the
ROWID found in the customers_pk index entry to fetch the correct customer record.
This, in effect, joins the rows fetched from the invoices table with their corresponding
matches in the customers table. The results of the nested loops join operation are
returned as the query results.

Page 94
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

Consider the following query and execution plan:


SELECT a.customer_name, COUNT (DISTINCT b.invoice_id) "Open Invoices",
COUNT (c.invoice_id) "Open Invoice Items"
FROM customers a, invoices b, invoice_items c
WHERE b.invoice_status = 'OPEN'
AND a.customer_id = b.customer_id
AND c.invoice_id (+) = b.invoice_id
GROUP BY a.customer_name;

ID PARENT OPERATION OBJECT_NAME


---- ------ ----------------------------------- -----------------------------
-
0 SELECT STATEMENT
1 0 SORT GROUP BY
2 1 NESTED LOOPS OUTER
3 2 HASH JOIN
4 3 TABLE ACCESS BY INDEX ROWID INVOICES
5 4 INDEX RANGE SCAN INVOICES_STATUS
6 3 TABLE ACCESS FULL CUSTOMERS
7 2 INDEX RANGE SCAN INVOICE_ITEMS_PK
‰ This execution plan is more complex than the previous two, and here you can start to
get a feel for the way in which complex operations get broken down into simpler
subordinate operations. To execute this query, the database server will do the
following: First Oracle will perform a range scan on the invoices_status index to
get the ROWIDs of all rows in the invoices table with the desired status. For each
ROWID found, the record from the invoices table will be fetched.
‰ This set of invoice records will be set aside for a moment while the focus turns to the
customers table. Here, Oracle will fetch all customers records with a full table scan. To
perform a hash join between the invoices and customers tables, Oracle will build a
hash from the customer records and use the invoice records to probe the customer
hash.
‰ Next, a nested loops join will be performed between the results of the hash join and
the invoice_items_pk index. For each row resulting from the hash join, Oracle will
perform a unique scan of the invoice_items_pk index to find index entries for
matching invoice items. Note that Oracle gets everything it needs from the index and
doesn’t even need to access the invoice_items table at all. Also note that the
nested loops operation is an outer join. A sort operation for the purposes of grouping is
performed on the results of the nested loops operation in order to complete the
SELECT statement.

It is interesting to note that Oracle chose to use a hash join and a full table scan on the customers
table instead of the more traditional nested loops join. In this database there are many invoices
and a relatively small number of customers, making a full table scan of the customers table less
expensive than repeated index lookups on the customers_pk index. But suppose the customers
table was enormous and the relative number of invoices was quite small. In that scenario a nested
loop join might be better than a hash join. Examining the execution plan allows you to see which
join method Oracle is using. You could then apply optimizer hints to coerce Oracle to use alternate
methods and compare the performance.

Page 95
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

Other Columns in the Plan Table


‰ Although the plan table contains 24 columns, so far you have only been using six of
them in our execution plan listings. These six will get you very far in the tuning
process, but some of the other columns can be mildly interesting at times. Still other
columns can be very relevant in specific situations.
‰ The optimizer column in the plan table shows the mode (such as RULE or CHOOSE)
used by the optimizer to generate the execution plan. The timestamp column shows
the date and time that the execution plan was generated. The remarks column is an
80 byte field where you may put your own comments about each step of the execution
plan. You can populate the remarks column by using an ordinary UPDATE statement
against the plan table.
‰ The object_owner, object_node, and object_instance columns can help you
further distinguish the database object involved in the operation. You might look at the
object_owner column, for example, if objects in multiple schemas have the same
name and you are not sure which one is being referenced in the execution plan. The
object_node is relevant in distributed queries or transactions. It indicates the
database link name to the object if the object resides in a remote database. The
object_instance column is helpful in situations such as a self-join where multiple
instances of the same object are used in one SQL statement.
‰ The partition_start, partition_stop, and partition_id columns offer
additional information when a partitioned table is involved in the execution plan. The
distribution column gives information about how the multiple Oracle processes
involved in a parallel query or parallel DML operation interact with each other.
‰ The cost, cardinality, and bytes columns show estimates made by the cost-based
optimizer as to how expensive an operation will be. Remember that the execution plan
is inserted into the plan table without actually executing the SQL statement. Therefore,
these columns reflect Oracle’s estimates and not the actual resources used. While it
can be amusing to look at the optimizer’s predictions, sometimes you need to take
them with a grain of salt. Later you will see that TKPROF reports can include specific
information about actual resources used at each step of the execution plan.

The “other” column in the plan table is a wild card where Oracle can store any sort of textual
information about each step of an execution plan. The other_tag column gives an indication of
what has been placed in the “other” column. This column will contain valuable information during
parallel queries and distributed operations.

Page 96
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

SQL TRACE and TKPROF


SQL Trace facility and TKPROF are two basic performance diagnostic tools that can help you
monitor and tune applications running against the Oracle Server.

Understanding SQL Trace and TKPROF


SQL Trace facility and TKPROF let you accurately assess the efficiency of the SQL statements an
application runs. For best results, use these tools with EXPLAIN PLAN rather than using EXPLAIN
PLAN alone.

Understanding the SQL Trace facility


The SQL Trace facility provides performance information on individual SQL statements. It
generates the following statistics for each statement:
‰ Parse, execute, and fetch counts
‰ CPU and elapsed times
‰ Physical reads and logical reads
‰ Number of rows processed
‰ Misses on the library cache
‰ Username under which each parse occurred
‰ Each commit and rollback

You can enable the SQL Trace facility for a session or for an instance. When the SQL Trace
facility is enabled, performance statistics for all SQL statements executed in a user session or in
the instance are placed into trace files.

The additional overhead of running the SQL Trace facility against an application with performance
problems is normally insignificant compared with the inherent overhead caused by the
application's inefficiency.

Understanding TKPROF
You can run the TKPROF program to format the contents of the trace file and place the output into
a readable output file. Optionally, TKPROF can also:
‰ Determine the execution plans of SQL statements
‰ Create a SQL script that stores the statistics in the database

TKPROF reports each statement executed with the resources it has consumed, the number of
times it was called, and the number of rows which it processed. This information lets you easily
locate those statements that are using the greatest resource

Page 97
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

Using SQL Trace Facility and TKPROF


Follow these steps to use the SQL Trace facility and TKPROF:

Step 1: Setting Initialization Parameters for Trace File Management


When the SQL Trace facility is enabled for a session, Oracle generates a trace file containing
statistics for traced SQL statements for that session. When the SQL Trace facility is enabled for an
instance, Oracle creates a separate trace file for each process.

Check the settings of the TIMED_STATISTICS, MAX_DUMP_FILE_SIZE, and USER_DUMP_DEST


initialization parameters.

Parameter Description

TIMED_STATISTICS This enables and disables the collection of timed statistics, such as CPU
and elapsed times, by the SQL Trace facility, as well as the collection of
various statistics in the dynamic performance tables. The default value of
false disables timing. A value of true enables timing. Enabling timing
causes extra timing calls for low-level operations. This is a dynamic
parameter. It is also a session parameter.

MAX_DUMP_FILE_SIZE When the SQL Trace facility is enabled at the instance level, every call to
the server produces a text line in a file in the operating system's file
format. The maximum size of these files (in operating system blocks) is
limited by this initialization parameter. The default is 500. If you find that
the trace output is truncated, then increase the value of this parameter
before generating another trace file. This is a dynamic parameter. It is
also a session parameter.

USER_DUMP_DEST This must fully specify the destination for the trace file according to the
conventions of the operating system. The default value is the default
destination for system dumps on the operating system.This value can be
modified with ALTER SYSTEM SET USER_DUMP_DEST= newdir. This
is a dynamic parameter. It is also a session parameter.

Issue the following syntax to set the Timed_statistics initialization parameter to true
ALTER SYSTEM SET TIMED_STATISTICS = TRUE;

After the above step you need to make sure how to distinguish the trace files by name. Oracle
writes trace files to the user dump destination specified by USER_DUMP_DEST. However, this
directory can soon contain many hundreds of files, usually with generated names. It might be
difficult to match trace files back to the session or process that created them. You can tag trace
files by including in your programs a statement like SELECT program_name FROM DUAL.

Step 2: Enabling the SQL Trace facility


Enable the SQL Trace facility for the session by using one of the following:
‰ DBMS_SESSION.SET_SQL_TRACE procedure
ALTER SESSION SET SQL_TRACE = TRUE;
You can enable SQL Trace in another session by using the
DBMS_SYSTEM.SET_SQL_TRACE_IN_SESSION procedure.

Page 98
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

To disable the SQL Trace facility for the session, enter:


ALTER SESSION SET SQL_TRACE = FALSE;

The SQL Trace facility is automatically disabled for the session when the application disconnects
from Oracle.

You can enable the SQL Trace facility for an instance by setting the value of the SQL_TRACE
initialization parameter to TRUE in the initialization file.
SQL_TRACE = TRUE

Note: Running the SQL Trace facility increases system overhead, enable it only when tuning SQL
statements, and disable it when you are finished.

Step 3: Formatting Trace Files with TKPROF


TKPROF accepts as input a trace file produced by the SQL Trace facility, and it produces a
formatted output file. TKPROF can also be used to generate execution plans.

After the SQL Trace facility has generated a number of trace files, you can:
‰ Run TKPROF on each individual trace file, producing a number of formatted output
files, one for each session.
‰ Concatenate the trace files, and then run TKPROF on the result to produce a
formatted output file for the entire instance.
TKPROF does not report COMMITs and ROLLBACKs that are recorded in the trace file.

Sample TKPROF Output


Sample output from TKPROF is as follows:
SELECT * FROM emp, dept
WHERE emp.deptno = dept.deptno;

call count cpu elapsed disk query current rows


---- ------- ------- --------- -------- -------- ------- ------
Parse 1 0.16 0.29 3 13 0 0
Execute 1 0.00 0.00 0 0 0 0
Fetch 1 0.03 0.26 2 2 4 14

Misses in library cache during parse: 1


Parsing user id: (8) SCOTT

Rows Execution Plan


------- ---------------------------------------------------
14 MERGE JOIN
4 SORT JOIN
4 TABLE ACCESS (FULL) OF 'DEPT'
14 SORT JOIN
14 TABLE ACCESS (FULL) OF 'EMP'

Page 99
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

For this statement, TKPROF output includes the following information:


‰ The text of the SQL statement
‰ The SQL Trace statistics in tabular form
‰ The number of library cache misses for the parsing and execution of the statement.
‰ The user initially parsing the statement.
‰ The execution plan generated by EXPLAIN PLAN.

TKPROF also provides a summary of user level statements and recursive SQL calls for the trace
file.

Step 4: Interpreting TKPROF Output


While TKPROF provides a very useful analysis, the most accurate measure of efficiency is the
actual performance of the application in question. At the end of the TKPROF output is a summary
of the work done in the database engine by the process during the period that the trace was
running.

Tabular Statistics in TKPROF


TKPROF lists the statistics for a SQL statement returned by the SQL Trace facility in rows and
columns. Each row corresponds to one of three steps of SQL statement processing.

CALL Column Values


CALL
Meaning
Value

PARSE Translates the SQL statement into an execution plan, including checks for proper
security authorization and checks for the existence of tables, columns, and other
referenced objects.

EXECUTE Actual execution of the statement by Oracle. For INSERT, UPDATE, and DELETE
statements, this modifies the data. For SELECT statements, this identifies the selected
rows.

FETCH Retrieves rows returned by a query. Fetches are only performed for SELECT
statements.

SQL Trace Statistics for Parses, Executes, and Fetches


SQL Trace
Meaning
Statistic

COUNT Number of times a statement was parsed, executed, or fetched.

CPU Total CPU time in seconds for all parse, execute, or fetch calls for the statement.
This value is zero (0) if TIMED_STATISTICS is not turned on.

ELAPSED Total elapsed time in seconds for all parse, execute, or fetch calls for the
statement. This value is zero (0) if TIMED_STATISTICS is not turned on.

Page 100
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

SQL Trace
Meaning
Statistic

DISK Total number of data blocks physically read from the datafiles on disk for all parse,
execute, or fetch calls.

QUERY Total number of buffers retrieved in consistent mode for all parse, execute, or fetch
calls. Usually, buffers are retrieved in consistent mode for queries.

CURRENT Total number of buffers retrieved in current mode. Buffers are retrieved in current
mode for statements such as INSERT, UPDATE, and DELETE.
Statistics about the processed rows appear in the ROWS column

SQL Trace Statistics for the ROWS Column


SQL Trace
Meaning
Statistic

ROWS Total number of rows processed by the SQL statement. This total does not
include rows processed by subqueries of the SQL statement.

For SELECT statements, the number of rows returned appears for the fetch step. For UPDATE,
DELETE, and INSERT statements, the number of rows processed appears for the execute step.

The following listing shows TKPROF output for one SQL statement as it appears in the output file:
SELECT *
FROM emp, dept
WHERE emp.deptno = dept.deptno;

call count cpu elapsed disk query current rows


---- ------- ------- --------- -------- -------- ------- ------
Parse 11 0.08 0.18 0 0 0 0
Execute 11 0.23 0.66 0 3 6 0
Fetch 35 6.70 6.83 100 12326 2 824
------------------------------------------------------------------
total 57 7.01 7.67 100 12329 8 826

Misses in library cache during parse: 0

If it is acceptable to have 7.01 CPU seconds and to retrieve 826 rows, then you need not look any
further at this trace output. In fact, a major use of TKPROF reports in a tuning exercise is to
eliminate processes from the detailed tuning phase.

Page 101
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

Sample TKPROF Output


This section provides an extensive example of TKPROF output. Portions have been edited out for
the sake of brevity.

Sample TKPROF Header


Copyright (c) Oracle Corporation 1979, 1999. All rights reserved.
Trace file: v80_ora_2758.trc
Sort options: default
************************************************************************
********
count = number of times OCI procedure was executed
cpu = cpu time in seconds executing
elapsed = elapsed time in seconds executing
disk = number of physical reads of buffers from disk
query = number of buffers gotten for consistent read
current = number of buffers gotten in current mode (usually for update)
rows = number of rows processed by the fetch or execute call
************************************************************************
********
The following statement encountered a error during parse:
select deptno, avg(sal) from emp e group by deptno
having exists (select deptno from dept
where dept.deptno = e.deptno
and dept.budget > avg(e.sal)) order by 1
Error encountered: ORA-00904
************************************************************************
********

Sample TKPROF Body


ALTER SESSION SET SQL_TRACE = true
call count cpu elapsed disk query current
rows
------- ------ -------- ---------- ---------- ---------- ---------- --
--------
Parse 0 0.00 0.00 0 0 0
0
Execute 1 0.00 0.10 0 0 0
0
Fetch 0 0.00 0.00 0 0 0
0
------- ------ -------- ---------- ---------- ---------- ---------- --
--------
total 1 0.00 0.10 0 0 0
0
Misses in library cache during parse: 0
Misses in library cache during execute: 1

Page 102
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

Optimizer goal: CHOOSE


Parsing user id: 02 (USER02)
************************************************************************
********
SELECT emp.ename, dept.dname
FROM emp, dept
WHERE emp.deptno = dept.deptno

call count cpu elapsed disk query current


rows
------- ------ -------- ---------- ---------- ---------- ---------- --
--------
Parse 1 0.11 0.13 2 0 1
0
Execute 1 0.00 0.00 0 0 0
0
Fetch 1 0.00 0.00 2 2 4
14
------- ------ -------- ---------- ---------- ---------- ---------- --
--------
total 3 0.11 0.13 4 2 5
14

Misses in library cache during parse: 1


Optimizer goal: CHOOSE
Parsing user id: 02 (USER02)
Rows Execution Plan
------- ---------------------------------------------------
0 SELECT STATEMENT GOAL: CHOOSE
14 MERGE JOIN
4 SORT (JOIN)
4 TABLE ACCESS (FULL) OF 'DEPT'
14 SORT (JOIN)
14 TABLE ACCESS (FULL) OF 'EMP'

************************************************************************
********
SELECT a.ename name, b.ename manager
FROM emp a, emp b
WHERE a.mgr = b.empno(+)

call count cpu elapsed disk query current


rows
------- ------ -------- ---------- ---------- ---------- ---------- --
--------

Page 103
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

Parse 1 0.01 0.01 0 0 0


0
Execute 1 0.00 0.00 0 0 0
0
Fetch 1 0.01 0.01 1 50 2
14
------- ------ -------- ---------- ---------- ---------- ---------- --
--------
total 3 0.02 0.02 1 50 2
14

Misses in library cache during parse: 1


Optimizer goal: CHOOSE
Parsing user id: 01 (USER01)
Rows Execution Plan
------- ---------------------------------------------------
0 SELECT STATEMENT GOAL: CHOOSE
13 NESTED LOOPS (OUTER)
14 TABLE ACCESS (FULL) OF 'EMP'
13 TABLE ACCESS (BY ROWID) OF 'EMP'
26 INDEX (RANGE SCAN) OF 'EMP_IND' (NON-UNIQUE)
************************************************************************
********
SELECT ename, job, sal
FROM emp
WHERE sal =
(SELECT max(sal)
FROM emp)

call count cpu elapsed disk query current


rows
------- ------ -------- ---------- ---------- ---------- ---------- --
--------
Parse 1 0.00 0.00 0 0 0
0
Execute 1 0.00 0.00 0 0 0
0
Fetch 1 0.00 0.00 0 12 4
1
------- ------ -------- ---------- ---------- ---------- ---------- --
--------
total 3 0.00 0.00 0 12 4
1

Misses in library cache during parse: 1


Optimizer goal: CHOOSE

Page 104
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

Parsing user id: 01 (USER01)


Rows Execution Plan
------- ---------------------------------------------------
0 SELECT STATEMENT GOAL: CHOOSE
14 FILTER
14 TABLE ACCESS (FULL) OF 'EMP'
14 SORT (AGGREGATE)
14 TABLE ACCESS (FULL) OF 'EMP'
************************************************************************
********
SELECT deptno
FROM emp
WHERE job = 'clerk'
GROUP BY deptno
HAVING COUNT(*) >= 2

call count cpu elapsed disk query current


rows
------- ------ -------- ---------- ---------- ---------- ---------- --
--------
Parse 1 0.00 0.00 0 0 0
0
Execute 1 0.00 0.00 0 0 0
0
Fetch 1 0.00 0.00 0 1 1
0
------- ------ -------- ---------- ---------- ---------- ---------- --
--------
total 3 0.00 0.00 0 1 1
0

Misses in library cache during parse: 13


Optimizer goal: CHOOSE
Parsing user id: 01 (USER01)
Rows Execution Plan
------- ---------------------------------------------------
0 SELECT STATEMENT GOAL: CHOOSE
0 FILTER
0 SORT (GROUP BY)
14 TABLE ACCESS (FULL) OF 'EMP'
************************************************************************
********
SELECT dept.deptno, dname, job, ename
FROM dept,emp
WHERE dept.deptno = emp.deptno(+)
ORDER BY dept.deptno

Page 105
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

call count cpu elapsed disk query current


rows
------- ------ -------- ---------- ---------- ---------- ---------- --
--------
Parse 1 0.00 0.00 0 0 0
0
Execute 1 0.00 0.00 0 0 0
0
Fetch 1 0.00 0.00 0 3 3
10
------- ------ -------- ---------- ---------- ---------- ---------- --
--------
total 3 0.00 0.00 0 3 3
10

Misses in library cache during parse: 1


Optimizer goal: CHOOSE
Parsing user id: 01 (USER01)
Rows Execution Plan
------- ---------------------------------------------------
0 SELECT STATEMENT GOAL: CHOOSE
14 MERGE JOIN (OUTER)
4 SORT (JOIN)
4 TABLE ACCESS (FULL) OF 'DEPT'
14 SORT (JOIN)
14 TABLE ACCESS (FULL) OF 'EMP'
************************************************************************
********
SELECT grade, job, ename, sal
FROM emp, salgrade
WHERE sal BETWEEN losal AND hisal
ORDER BY grade, job

call count cpu elapsed disk query current


rows
------- ------ -------- ---------- ---------- ---------- ---------- --
--------
Parse 1 0.04 0.06 2 16 1
0
Execute 1 0.00 0.00 0 0 0
0
Fetch 1 0.01 0.01 1 10 12
10
------- ------ -------- ---------- ---------- ---------- ---------- --
--------

Page 106
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

total 3 0.05 0.07 3 26 13


10

Misses in library cache during parse: 1


Optimizer goal: CHOOSE
Parsing user id: 02 (USER02)
Rows Execution Plan
------- ---------------------------------------------------
0 SELECT STATEMENT GOAL: CHOOSE
14 SORT (ORDER BY)
14 NESTED LOOPS
5 TABLE ACCESS (FULL) OF 'SALGRADE'
70 TABLE ACCESS (FULL) OF 'EMP'
************************************************************************
********

SELECT LPAD(' ',level*2)||ename org_chart, level, empno, mgr, job,


deptno
FROM emp
CONNECT BY prior empno = mgr
START WITH ename = 'clark'
OR ename = 'blake'
ORDER BY deptno

call count cpu elapsed disk query current


rows
------- ------ -------- ---------- ---------- ---------- ---------- --
--------
Parse 1 0.01 0.01 0 0 0
0
Execute 1 0.00 0.00 0 0 0
0
Fetch 1 0.01 0.01 0 1 2
0
------- ------ -------- ---------- ---------- ---------- ---------- --
--------
total 3 0.02 0.02 0 1 2
0

Misses in library cache during parse: 1


Optimizer goal: CHOOSE
Parsing user id: 02 (USER02)

Rows Execution Plan


------- ---------------------------------------------------
0 SELECT STATEMENT GOAL: CHOOSE

Page 107
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

0 SORT (ORDER BY)


0 CONNECT BY
14 TABLE ACCESS (FULL) OF 'EMP'
0 TABLE ACCESS (BY ROWID) OF 'EMP'
0 TABLE ACCESS (FULL) OF 'EMP'
************************************************************************
********
CREATE TABLE TKOPTKP (a number, b number)

call count cpu elapsed disk query current


rows
------- ------ -------- ---------- ---------- ---------- ---------- --
--------
Parse 1 0.00 0.00 0 0 0
0
Execute 1 0.01 0.01 1 0 1
0
Fetch 0 0.00 0.00 0 0 0
0
------- ------ -------- ---------- ---------- ---------- ---------- --
--------
total 2 0.01 0.01 1 0 1
0

Misses in library cache during parse: 1


Optimizer goal: CHOOSE
Parsing user id: 02 (USER02)
Rows Execution Plan
------- ---------------------------------------------------
0 CREATE TABLE STATEMENT GOAL: CHOOSE

************************************************************************
********
INSERT INTO TKOPTKP
VALUES (1,1)

call count cpu elapsed disk query current


rows
------- ------ -------- ---------- ---------- ---------- ---------- --
--------
Parse 1 0.07 0.09 0 0 0
0
Execute 1 0.01 0.20 2 2 3
1
Fetch 0 0.00 0.00 0 0 0
0

Page 108
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

------- ------ -------- ---------- ---------- ---------- ---------- --


--------
total 2 0.08 0.29 2 2 3
1

Misses in library cache during parse: 1


Optimizer goal: CHOOSE
Parsing user id: 02 (USER02)
Rows Execution Plan
------- ---------------------------------------------------
0 INSERT STATEMENT GOAL: CHOOSE

************************************************************************
********
INSERT INTO TKOPTKP SELECT * FROM TKOPTKP
call count cpu elapsed disk query current
rows
------- ------ -------- ---------- ---------- ---------- ---------- --
--------
Parse 1 0.00 0.00 0 0 0
0
Execute 1 0.02 0.02 0 2 3
11
Fetch 0 0.00 0.00 0 0 0
0
------- ------ -------- ---------- ---------- ---------- ---------- --
--------
total 2 0.02 0.02 0 2 3
11

Misses in library cache during parse: 1


Optimizer goal: CHOOSE
Parsing user id: 02 (USER02)
Rows Execution Plan
------- ---------------------------------------------------
0 INSERT STATEMENT GOAL: CHOOSE
12 TABLE ACCESS (FULL) OF 'TKOPTKP'
************************************************************************
********
SELECT *
FROM TKOPTKP
WHERE a > 2

call count cpu elapsed disk query current


rows

Page 109
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

------- ------ -------- ---------- ---------- ---------- ---------- --


--------
Parse 1 0.01 0.01 0 0 0
0
Execute 1 0.00 0.00 0 0 0
0
Fetch 1 0.00 0.00 0 1 2
10
------- ------ -------- ---------- ---------- ---------- ---------- --
--------
total 3 0.01 0.01 0 1 2
10

Misses in library cache during parse: 1


Optimizer goal: CHOOSE
Parsing user id: 02 (USER02)
Rows Execution Plan
------- ---------------------------------------------------
0 SELECT STATEMENT GOAL: CHOOSE
24 TABLE ACCESS (FULL) OF 'TKOPTKP'
************************************************************************
********

Sample TKPROF Summary


OVERALL TOTALS FOR ALL NON-RECURSIVE STATEMENTS
call count cpu elapsed disk query current
rows
------- ------ -------- ---------- ---------- ---------- ---------- --
--------
Parse 18 0.40 0.53 30 182 3
0
Execute 19 0.05 0.41 3 7 10
16
Fetch 12 0.05 0.06 4 105 66
78
------- ------ -------- ---------- ---------- ---------- ---------- --
--------
total 49 0.50 1.00 37 294 79
94

Misses in library cache during parse: 18


Misses in library cache during execute: 1

OVERALL TOTALS FOR ALL RECURSIVE STATEMENTS


call count cpu elapsed disk query current
rows

Page 110
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

------- ------ -------- ---------- ---------- ---------- ---------- --


--------
Parse 69 0.49 0.60 9 12 8
0
Execute 103 0.13 0.54 0 0 0
0
Fetch 213 0.12 0.27 40 435 0
162
------- ------ -------- ---------- ---------- ---------- ---------- --
--------
total 385 0.74 1.41 49 447 8
162

Misses in library cache during parse: 13


19 user SQL statements in session.
69 internal SQL statements in session.
88 SQL statements in session.
17 statements EXPLAINed in this session.
************************************************************************
********
Trace file: v80_ora_2758.trc
Trace file compatibility: 7.03.02

Sort options: default


1 session in tracefile.
19 user SQL statements in trace file.
69 internal SQL statements in trace file.
88 SQL statements in trace file.
41 unique SQL statements in trace file.
17 SQL statements EXPLAINed using schema:
SCOTT.prof$plan_table
Default table was used.
Table was created.
Table was dropped.
1017 lines in trace file.

Summary
‰ Execution plans are a hierarchical arrangement of simple data access operations.
‰ An execution plan defines how Oracle finds or writes the data, when a query is fired.
‰ Explain plan is statement through which you can see the execution plan chosen by
Oracle.
‰ Execution plan is the sequence of operations that Oracle performs to run the
statement.

Page 111
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

‰ SQL trace and TKPROF are the two basic diagnostic tools that help to monitor and
tune applications.
o SQL Trace facility provides performance information on individual SQL
statements.
o TKPROF program formats the contents of the trace file and places the output in a
readable output file.

Test Your Understanding


1. What is Execution Plan?
2. How do you look at execution plan generated by Oracle?
3. What are factors that influence the execution plan to differ for the same SQL?
4. How do you enable SQL Trace for a Session and Instance?
5. How do you read the output generated by SQL Trace utility?

Page 112
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

Session 08: Oracle 10g Features

Learning Objectives
After completing this session, you will be able to:
‰ Describe Automatic Database Diagnostics Monitor
‰ Explain Automatic SGA Management

Automatic Performance Diagnostics and Tuning Features


When problems occur with a system, it is important to perform accurate and timely diagnosis of the
problem before making any changes to a system. For Oracle systems, the statistical data needed
for accurate diagnosis of a problem is saved in the Automatic Workload Repository (AWR). The
Automatic Database Diagnostic Monitor (ADDM) analyzes the AWR data on a regular basis, then
locates the root causes of performance problems, provides recommendations for correcting any
problems, and identifies non-problem areas of the system. Because AWR is a repository of
historical performance data, ADDM can be used to analyze performance issues after the event,
often saving time and resources reproducing a problem.

An ADDM analysis is performed every time an AWR snapshot is taken and the results are saved in
the database. You can view the results of the analysis using Oracle Enterprise Manager or by
viewing a report in a SQL*Plus session. In most cases, ADDM output should be the first place that
a DBA looks when notified of a performance problem. ADDM provides the following benefits:
‰ Automatic performance diagnostic report every hour by default
‰ Problem diagnosis based on decades of tuning expertise
‰ Time-based quantification of problem impacts and recommendation benefits
‰ Identification of root cause, not symptoms
‰ Recommendations for treating the root causes of problems
‰ Identification of non-problem areas of the system
‰ Minimal overhead to the system during the diagnostic process

It is important to realize that tuning is an iterative process and fixing one problem can cause the
bottleneck to shift to another part of the system. Even with the benefit of ADDM analysis, it can
take multiple tuning cycles to reach acceptable system performance. ADDM benefits apply beyond
production systems; on development and test systems ADDM can provide an early warning of
performance issues.

Automatic Database Diagnostics Monitor


The Automatic Database Diagnostic Monitor (ADDM) provides a holistic tuning solution. ADDM
analysis can be performed over any time period defined by a pair of AWR snapshots taken on a
particular instance. Analysis is performed top down, first identifying symptoms and then refining
them to reach the root causes of performance problems.

Page 113
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

The goal of the analysis is to reduce a single throughput metric called DB time. DB time is the
cumulative time spent by the database server in processing user requests. It includes wait time
and CPU time of all non-idle user sessions. DB time is displayed in the V$SESS_TIME_MODEL and
V$SYS_TIME_MODEL views. By reducing DB time, the database server is able to support more
user requests using the same resources, which increases throughput. The problems reported by
the ADDM are sorted by the amount of DB time they are responsible for. System areas that are not
responsible for a significant portion of DB time are reported as non-problem areas.
‰ The types of problems that ADDM considers includes the following:
o CPU bottlenecks - Is the system CPU bound by Oracle or some other
application?
o Undersized Memory Structures: Are the Oracle memory structures, such as the
SGA, PGA, and buffer cache, adequately sized?
o I/O capacity issues: Is the I/O subsystem performing as expected?
o High load SQL statements: Are there any SQL statements which are consuming
excessive system resources?
o High load PL/SQL execution and compilation, as well as high load Java usage
o RAC specific issues: What are the global cache hot blocks and objects; are
there any interconnect latency issues?
o Sub-optimal use of Oracle by the application: Are there problems with poor
connection management, excessive parsing, or application level lock contention?
o Database configuration issues: Is there evidence of incorrect sizing of log files,
archiving issues, excessive checkpoints, or sub-optimal parameter settings?
o Concurrency issues: Are there buffer busy problems?
o Hot objects and top SQL for various problem areas

ADDM also documents the non-problem areas of the system. For example, wait event classes that
are not significantly impacting the performance of the system are identified and removed from the
tuning consideration at an early stage, saving time and effort that would be spent on items that do
not impact overall system performance. In addition to problem diagnostics, ADDM recommends
possible solutions. When appropriate, ADDM recommends multiple solutions for the DBA to
choose from. ADDM considers a variety of changes to a system while generating its
recommendations. Recommendations include the following:
‰ Hardware changes: Adding CPUs or changing the I/O subsystem configuration
‰ Database configuration: Changing initialization parameter settings
‰ Schema changes: Hash partitioning a table or index, or using automatic segment-
space management (ASSM)
‰ Application changes: Using the cache option for sequences or using bind variables
‰ Using other advisors: Running the SQL Tuning Advisor on high load SQL or running
the Segment Advisor on hot objects

ADDM Analysis Results


ADDM analysis results are represented as a set of FINDINGs. Each ADDM finding can belong to
one of three types:
‰ Problem: Findings that describe the root cause of a database performance issue.
‰ Symptom: Findings that contain information that often leads to one or more problem
findings.
‰ Information: Findings that are used for reporting non-problem areas of the system.

Page 114
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

Each problem finding is quantified by an impact that is an estimate of the portion of DB time
caused by the finding's performance issue. A problem finding can be associated with a list of
RECOMMENDATIONs for reducing the impact of the performance problem. Each recommendation
has a benefit which is an estimate of the portion of DB time that can be saved if the
recommendation is implemented. A list of recommendations can contain various alternatives for
solving the same problem; you not have to apply all the recommendations to solve a specific
problem.

Recommendations are composed of ACTIONs and RATIONALEs. You need to apply all the
actions of a recommendation in order to gain the estimated benefit. The rationales are used for
explaining why the set of actions were recommended and to provide additional information to
implement the suggested recommendation.

An ADDM Example Report


FINDING 1: 31% impact (7798 seconds)
------------------------------------

SQL statements were not shared due to the usage of literals. This resulted in additional hard
parses which were consuming significant database time.

RECOMMENDATION 1: Application Analysis, 31% benefit (7798 seconds)

ACTION: Investigate application logic for possible use of bind variables instead of literals.
Alternatively, you may set the parameter "cursor_sharing" to "force".

RATIONALE: SQL statements with PLAN_HASH_VALUE 3106087033 were found to be using


literals. Look in V$SQL for examples of such SQL statements.

In this example, the finding points to a particular root cause, the usage of literals in SQL
statements, which is estimated to have an impact of about 31% of total DB time in the analysis
period. The finding has a recommendation associated with it, composed of one action and one
rationale. The action specifies a solution to the problem found and is estimated to have a
maximum benefit of up to 31% DB time in the analysis period. Note that the benefit is given as a
portion of the total DB time and not as a portion of the finding's impact. The rationale provides
additional information on tracking potential SQL statements that were using literals and causing
this performance issue. Using the specified plan hash value of SQL statements that could be a
problem, a DBA could quickly examine a few sample statements.

Automatic SGA Management


One of the key self-management enhancements in the Oracle Database 10G is Automatic Shared
(SGA) Memory Management. This functionality automates the management of shared memory
used by an Oracle Database 10g instance and frees administrators from having to manually
configure the sizes of shared memory components. Besides making more effective use of
available memory and thereby reducing the cost incurred of acquiring additional hardware memory
resources, the Automatic Shared Memory Management feature significantly simplifies Oracle
database administration by introducing a more dynamic, flexible and adaptive memory
management scheme.

Page 115
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

A system global area (SGA) is a group of shared memory structures that contain data and control
information for one Oracle database instance. If multiple users are concurrently connected to the
same instance, then the data in the instance's SGA is shared among the users. Consequently, the
SGA is sometimes called the shared global area.

Automatic Shared Memory Management

Shared Database
Pool buffer cache Log Buffer
(auto tuned) (auto tuned)

Java Pool Large Pool Fixed


(auto tuned) (auto tuned) SGA

TOTAL SGA = 16G


Initialization Parameters: SGA_TARGET = 16G
STATISTICS_LEVEL = TYPICAL

‰ The SGA contains the following data structures:


‰ Database buffer cache (used for caching disk blocks)
‰ Redo log buffer
‰ Shared pool (used for allocating memory for SQL and PL/SQL execution)
‰ Java pool (used for java objects and other java execution memory)
‰ Large pool (optional for large allocations such as RMAN backup buffers)
‰ Streams pool
‰ Data dictionary cache
‰ Other miscellaneous information

Part of the SGA contains general information about the state of the database and the instance,
which the background processes need to access; this is called the fixed SGA. No user data is
stored here. The SGA also includes information communicated between processes, such as
locking information.

The task of manually adjusting the sizes of individual SGA components could pose a few
challenges. It may not be easy to determine the optimal sizes of these components suitable for a
given workload. Oracle9i Database alleviated this problem to a great extent by introducing
advisory mechanisms that allow DBAs to determine the optimal sizes of the buffer cache and
shared pool. However, these recommendations still had to be implemented by the administrator.
This challenge is further compounded in situations in which the workload tends to vary with the
time of the day e.g., online users during the day and batch jobs at night. Sizing for peak load could
mean memory wastage while under-sizing may cause out-of-memory errors (ORA-4031).

Page 116
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

For example if a system is configured with a big large pool to accommodate a nightly RMAN
backup job, most of this memory – which could have been better utilized in the buffer cache or
shared pool for OLTP activity remains unused for the most part of the day. At the same time, the
cost of failures could be prohibitive from a business point of view leaving administrators with few
other options.

The SGA_TARGET Parameter


To resolve these challenges, Oracle Database 10g introduces Automatic Shared Memory
Management. In Oracle Database 10g, DBAs can just specify the total amount of SGA memory
available to an instance using the new parameter SGA_TARGET. The database server then
automatically distributes the available memory among various components as required. The
Automatic Shared Memory Management feature is based on a sophisticated algorithm internal to
the database that continuously monitors the distribution of memory and changes it periodically as
needed, according to the demands of the workload.

The SGA_TARGET parameter reflects the total size of the SGA and includes memory for:
‰ Fixed SGA and other internal allocations needed by the Oracle instance
‰ Log buffer
‰ Shared Pool
‰ Java Pool
‰ Buffer Cache
‰ Keep/Recycle buffer caches (if specified)
‰ Non standard block size buffer caches (if specified)
‰ Streams Pool (new in Oracle Database 10g)

An important point to note is that SGA_TARGET includes the entire memory for the SGA. Thus,
SGA_TARGET allows the user to precisely control the size of the shared memory area allocated by
Oracle.

Automatically Managed SGA Components


When SGA_TARGET is set, the most commonly configured components are sized automatically.
There is no need to set the size of any of the above components explicitly and by default the
parameters for these components will appear to have values of zero. Whenever a component
needs memory, it can request that it be transferred from another component via the internal auto-
tuning mechanism. This will happen transparently without user-intervention.

The performance of each of these components is also monitored by the Oracle instance. The
instance uses internal views and statistics to determine how to optimally distribute memory among
the automatically sized components. As the workload changes, memory is redistributed to ensure
optimal performance with the new workload. This algorithm is never complacent and always tries
to find the optimal distribution by taking into consideration long term as well as short terms trends.

The administrator can still exercise some control over the sizes of the auto-tuned components by
specifying minimum values for each of these components. This can be useful in cases in which the
administrator knows that an application needs a minimum amount of memory in certain
components to function properly. The minimum value of a component is specified by setting the
corresponding parameter for the component.

Page 117
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

Here is an example configuration:


SGA_TARGET = 132M
SHARED_POOL_SIZE = 32M
DB_CACHE_SIZE = 20M

In the earlier example, the shared pool and the default buffer pool will not be sized below the
specified values (32M and 20M, respectively). This implies that the remaining 80M can be
distributed across all the components. The actual distribution of values between the SGA
components may be as follows:
Actual Shared Pool Size = 92M
Actual buffer cache size = 20M
Actual java pool size = 16M
Actual Large Pool Size = 0M
Other = 4M

The fixed view V$SGA_DYNAMIC_COMPONENTS displays the current size of each SGA component
while the parameter values (For example,DB_CACHE_SIZE, SHARED_POOL_SIZE) specify the
minimum values. The current sizes of the SGA components can also be obtained by looking at the
Enterprise Manager Memory configuration page.

Figure displays the current sizes of automatically tuned SGA components

Page 118
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

Manually Sized SGA Components


There are a few SGA components whose sizes are not automatically adjusted. The administrator
needs to specify the sizes of these components explicitly, if needed by the application. Such
components are as follows:
‰ Keep or recycle buffer caches (controlled by DB_KEEP_CACHE_SIZE and
DB_RECYCLE_CACHE_SIZE)
‰ Additional buffer caches for non-standard block sizes (controlled by
DB_<N>K_CACHE_SIZE, N={2,4,8,16,32})

The size of these components is determined by the administrator-defined value of their


corresponding parameters. These values can, of course, be changed any time either using
Enterprise Manager or from the command-line via the ALTER SYSTEM command. The memory
consumed by manually sized components reduces the amount of memory available for automatic
adjustment. So for example, in the following configuration:
‰ SGA_TARGET = 256M
‰ DB_8K_CACHE_SIZE = 32M

The instance has only 224M (256 – 32) remaining to be distributed among the automatically sized
components

BENEFITS - More Flexible and Adaptive Memory Utilization


The most significant benefit of using automatic SGA memory management is that the sizes of the
different SGA components are flexible and will adapt to the needs of a workload without requiring
user intervention.

Let us illustrate this with an example. Consider a manual configuration in where 1G of memory is
available for SGA and distributed as follows (for the purpose of simplicity you ignore other SGA
components for now):
SHARED_POOL_SIZE=128M
DB_CACHE_SIZE=896M
In this case, if the application ever tries to allocate more than 128M of memory from the shared
pool, it will receive an ORA-4031 indicating that available shared pool has been exhausted. Note
that when this condition happens, there may be free memory in the buffer cache - but it is not
accessible to the shared pool. The user will then manually have to shrink the buffer cache and
grow the shared pool to work around this problem.

Instead with automatic management, the DBA can simply set:


SGA_TARGET = 1G
In this case, if the application needs more shared pool memory for avoiding an ORA-4031 error
condition, it will simply obtain that memory by acquiring it from the buffer cache.

Enhanced Performance
Besides maximizing the use of available memory, the Automatic Shared Memory Management
feature can enhance workload performance as well. With manual configuration, it is possible that
compiled SQL statements will frequently age out of the shared pool because of its inadequate size.
This will manifest in terms of frequent hard parses and, hence, reduced performance.

Page 119
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

However when automatic management is enabled, the internal tuning algorithm will monitor the
performance of the workload and grow the shared pool if it determines that doing so will reduce the
number of parses required. This is one of the most wonderful aspects of Automatic Shared
Memory Management feature since it provides enhanced out-of-box performance, without
requiring any additional resources or manual tuning effort.

Ease of Use
Having just a single parameter to deal with greatly simplifies the job of administrators. DBAs can
now just specify the amount of SGA memory an instance has its disposal and forget about the rest.
They do not need to figure out the sizes of individual components any more. In addition, they can
be assured of the fact that no out of memory errors will be generated unless the system has truly
run out of memory.

Enabling Automatic Shared Memory Management


The Automatic Shared Memory Management feature can be enabled either using EM or by setting
the SGA_TARGET parameter. When migrating from a manual scheme, it is best to tally the existing
values of the SGA parameters and add a small amount (For example, 16MB) to account for fixed
SGA and internal overhead. At the same time the values of the automatically sized components
can be removed from the parameter file.
For instance, when migrating from the following configuration:
SHARED_POOL_SIZE=256M
DB_CACHE_SIZE=512M
LARGE_POOL_SIZE=256M
LOG_BUFFER=16M

The preceding parameters can be replaced with SGA_TARGET = 256 M + 512M + 256 M + 16M +
16 M (fixed SGA overhead) = 1056 M

Automatic Shared Memory Management may also be enabled dynamically. If you are using
Enterprise Manager, then you can enable SGA tuning by clicking the enable button on the SGA
screen in the memory parameters section.

Page 120
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

Figure displays Enabling Automatic Shared Memory Management using Enterprise


Manager

When enabling the Automatic Shared Memory Management feature using EM, the appropriate
value for SGA_TARGET is automatically calculated according to the formula described above. In
addition, EM also unsets all the parameters specifying the size of individual components in order to
maximize the benefit of automatic management.

If using command line interface, then the steps involved in enabling Automatic Shared Memory
Management are as follows:
‰ Dynamically set SGA_TARGET to the current SGA size. The current size of the SGA
can be determined from the fixed-view V$SGA by the following query:
Select sum(value) from v$sga;
‰ Next dynamically set each of the auto-tuned component sizes to zero so that the
automatic shared memory tuning algorithm can modify the sizes as needed.

Page 121
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

If the earlier query for example returns the result of 536870912 (or 512M) then the steps for
enabling auto SGA are as follows:
Alter system set sga_target=512M;
Alter system set shared_pool_size = 0;
Alter system set large_pool_size = 0;
Alter system set java_pool_size = 0;

Dynamic Modification of SGA_TARGET


The SGA_TARGET parameter is dynamic and can be increased up to the value specified by the
parameter SGA_MAX_SIZE. The value of this parameter can also be reduced. In that case, one or
more automatically tuned components are identified to release memory. The value of the
SGA_TARGET parameter can be reduced until one or more auto-tuned components reach their
minimum size.

The change in the amount of physical memory consumed when SGA_TARGET is modified depends
on the OS platform. On some UNIX platforms that do not support dynamic shared memory, the
physical memory in use by the SGA is equal to the value of SGA_MAX_SIZE. On such platforms,
there is no real benefit in running with a value of SGA_TARGET less than SGA_MAX_SIZE and
setting SGA_MAX_SIZE on those platforms is, therefore, not recommended. On other platforms,
such as Solaris and Windows, the physical memory consumed by the SGA is equal to the value of
SGA_TARGET parameter.

Note that when SGA_TARGET is resized, the only components to be affected are the auto-tuned
components. Any manually configured components remain unaffected.
For example, if you have an environment with the following configuration:
SGA_MAX_SIZE=1024M
SGA_TARGET = 512M
DB_8K_CACHE_SIZE = 128M

In this example, the value of SGA_TARGET can be resized up to 1024M and can also be lowered
until one or more of the buffer cache, shared pool, large pool, or java pool reaches its minimum
size (the exact value depends on environmental factors such as the number of CPUs on the
system). But the value of DB_8K_CACHE_SIZE will remain fixed at all times at 128M.

Also, when SGA_TARGET is reduced, if the values for any auto-tuned component sizes have been
specified to limit their minimum sizes, then those components will not shrink below their respective
minimums. Therefore, if you have the following combination of parameters:
SGA_MAX_SIZE=1024M
SGA_TARGET = 512M
DB_CACHE_SIZE = 96M
DB_8K_CACHE_SIZE = 128M

In this example, in addition to the DB_8K_CACHE_SIZE being permanently fixed at 128M, the
primary buffer cache will not shrink below 96M. This imposes an additional restriction on how far
the value of SGA_TARGET can be reduced.

Page 122
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

SGA Size Advisor


To determine the appropriate value for SGA_TARGET, Oracle provides the SGA Size Advisor. The
SGA size advisor can be accessed from the Memory Parameters page of the Enterprise Manager
Interface. The advisor performs a what-if analysis to quantify the expected impact on the overall
system performance for various sizes of the SGA. In the example below, the best improvement will
be obtained by setting the SGA_TARGET value to 164M.

CONCLUSION
Memory is a precious system resource and administrators currently spend a significant amount of
their time optimizing its use. With Automatic Shared Memory Management, they are relieved of
this time consuming and often tedious exercise. The flexibility of this solution will ensure the best
possible utilization of existing resources and thereby help organizations reduce capital
expenditure. Just another example of how the Oracle Database 10g is going to let administrators
play more strategic roles and allow businesses to become more profitable!

Summary
‰ ADDM collects data from AWR in a periodic time and gives suggestion for problem
areas.
‰ Goal of ADDM report analysis is to reduce the single throughput metric – DBTIME.
‰ Types of problems that ADDM considers are as follows:
o CPU bottlenecks
o Undersized Memory Structures
o I/O capacity issues
o High load SQL statements
‰ SGA contains data and control information for one oracle database instance.
‰ One of key self-management enhancements in Oracle 10g is automatic SGA
management.

Test Your Understanding


1. In which repository the data collected for diagnosis is stored by Oracle?
2. What is the goal for automatic database diagnostic monitor (ADDM)?
3. What are the types of findings reported by ADDM?
4. What is SGA and how does it related to performance problems?
5. How do you enable automatic SGA management feature?

Page 123
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

References

Websites
‰ Oracle® Database Performance Tuning Guide10g – Oracle database Documentation
library.
‰ Oracle® Database Performance Tuning Guide Oracle 10g release 2 Documentation
library
‰ http://dba-oracle.com/art_sql_tune.htm
‰ http://www.databasejournal.com/features/oracle/article.php/10893_3341851_2

Books
‰ Oracle SQL Tuning Pocket Reference by Mark Gurry
‰ Oracle® SQL by Example, Third Edition by Alice Rischert
‰ Sams Teach Yourself SQL® in 24 Hours, Third Edition
‰ SQL Performance Tuning by Peter Gulutzan; Trudy Pelzer
‰ Oracle SQL Tuning Pocket Reference by Mark Gurry

Page 124
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected
Handout – Oracle 10g PL/SQL Performance Tuning

STUDENT NOTES:

Page 125
©Copyright 2007, Cognizant Technology Solutions, All Rights Reserved
C3: Protected

S-ar putea să vă placă și