You are on page 1of 34

Performance tuning is an art which has lots of section like the below

 Identifying which query takes much time, by the use of trace, TKPROF and execution plans at
various load scenarios.
 Tuning the identified time taking query based on the existing scenario and with the knowledge
base.
 Tuning the DB parameters and hardware requirements.
 Monitoring the tuned query for quite some time at various load scenarios.
 Giving different solutions according to the load levels.
 
Scope:

Now we are going to see just the part “Tuning the identified time taking query, based on the
existing scenario and with the knowledge base”. This will say the don’ts in a query or PL/SQL
code and then it will explain you how to tune them.

Result after this session:

This session will help you to understand the oracle basic architecture and do some basic tuning
which can improve your query and PL/SQL code.

Technology Focus - performance fine tuning in Oracle 1


Instance

SGA
Shared Pool

Database Buffer Redo Log


Library
Cache Buffer Memory
Cache
Structures

Data
Dictionary Java Pool Large Pool
Cache

Back-
Ground
PMON SMON DBWR LGWR CKPT Others Processes

Technology Focus - performance fine tuning in Oracle 2


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

The Oracle shared pool contains the following components:


* The library cache
* The dictionary cache
* Control Structures

Oracle's library cache, which is responsible for collecting, parsing, interpreting, and executing
all of the SQL statements that go against the Oracle database. Hence, the shared pool is a key
component, so it's necessary for the Oracle database administrator to check for shared pool
contention.

Oracle's parsing algorithm ensures that identical SQL statements do not have to be parsed each
time they're executed. 

Control Structures - Common control structure information, for example, lock information

The dictionary cache stores “metadata” (data about your tables and indexes) and it’s also
known as the row cache. It is used to cache data dictionary related information in RAM for quick
access.

Technology Focus - performance fine tuning in Oracle 3


Database Buffer cache:

The buffer cache is part of the SGA. It holds copies of data blocks so as they can be accessed
quicker by oracle than by reading them off disk. The purpose of the buffer cache is to minimize
physical io. When a block is read by Oracle, it places this block into the buffer cache, because
there is a chance that this block is needed again. Reading a block from the buffer cache is less
costly (in terms of time) than reading it from the disk.

Redo Log Buffer:

Each Oracle database has a redo log. This redo log records all changes made in datafiles. This
is to restore data back when failure happens. The redo log makes it possible to replay SQL
statements. Before Oracle changes data in a datafile it writes these changes to the redo log. If
something happens to one of the datafiles, a backed up datafile can be restored and the redo,
that was written since, replied, which brings the datafile to the state it had before it became
unavailable

Large Pool:

Oracle Large Pool is an optional memory component of the oracle database SGA. This area is
used for providing large memory allocations in many situations that arise during the operations
of an oracle database instance.

Technology Focus - performance fine tuning in Oracle 4


Actually the data is getting stored in Segments which Is made up of one or more Extents. Each
Extent is made up of one or more data blocks.

Each and every table will be available in a single segment.

The data may or may not be available in consecutive blocks.

Technology Focus - performance fine tuning in Oracle 5


Basics of Index:

Indexes are optional structures associated with tables. Indexes can be created to increase the
performance of data retrieval. Just as the index in a manual helps you quickly locate specific
information, an Oracle index provides an access path to table data.

Indexes are useful when applications frequently query a table for a range of rows (for example,
all employees with a salary greater than 1000 dollars) or a specific row. Indexes are created on
one or more columns of a table.Changes to table data (such as adding new rows, updating
rows, or deleting rows) are automatically incorporated into all relevant indexes. Indexes are the
primary means of reducing disk I/O when properly used. However, the presence of many
indexes on a table decreases the performance of updates, deletes, and inserts, because Oracle
must also update the indexes associated with the table.

An index is merely a fast access path to the data. It affects only the speed of execution. Given a
data value that has been indexed, the index points directly to the location of the rows containing
that value. Indexes are logically and physically independent of the data in the associated table.
You can create or drop an index at any time without affecting the base tables or other indexes.

Oracle RDBMS accesss table data in one of the two ways


Full table scan
Using Indexes

Using Indexes is always preferrable to using a full table scan as it allows more immediate
access to just the desired rows.
Full table scan is preferable when you know that more than about 25% of the records in the
queried tables will be selected;

Technology Focus - performance fine tuning in Oracle 6


Oracle RDBMS accesss table data in one of the two ways
Full table scan
Using Indexes

Using Indexes is always preferrable to using a full table scan as it allows more immediate
access to just the desired rows.
Full table scan is preferable when you know that more than about 25% of the records in the
queried tables will be selected;

Index segment:

Each index has an index segment that stores all of its data.

Some basic types of index are

B-tree indexes
Bitmap indexes
Function-Based Indexes

Technology Focus - performance fine tuning in Oracle 7


What Is ROWID?

ROWID is an internal number Oracle uses to uniquely identify each row. NOT a primary key! Is
the actual location of a row on a disk. Very efficient for retrieval. Format specifies block, row,
and file (and object in 8). This is called pseudo-column since can be selected

Oracle 7: BBBBBBB.RRRR.FFFFF
Oracle 8: OOOOOO.FFF.BBBBBB.RRR

As given in the figure - below are the steps for searching Patrick:

 In the root block, Rh is the smallest key >= Peter.


 Follow the link before Rh to branch block (N, P, Ph).
 In this block, Ph is the smallest key >= Peter.
 Follow the link before Ph to leaf block (Pablo, Patrick, Paula, Peter).
 In this block, search for key Peter = Peter.
 Found Peter = Peter, return (KEY, ROWID).
Technology Focus - performance fine tuning in Oracle 8
Bitmap index
It maintain sparse matrix to handle the indexing.

Parts table
partno color size

1 GREEN MED
2 RED MED
3 RED SMALL
4 BLUE LARGE

Bitmapped index on ‘color’


color = ‘BLUE’ 0 0 0 1
color = ‘RED’ 0 1 1 0
color = ‘GREEN’ 1 0 0 0

Part number 1 2 3 4

Technology Focus - performance fine tuning in Oracle 9


This is what the Oracle SQL engine does in a nutshell:
1.Create cursor
A cursor exists for every statement run. If you need programmatic control you can use an
explicit cursor that you define. Otherwise, an implicit cursor is built for you.
 
2.Parse statement
A lot of complicated stuff is going on. The goal is to get out of this step as quickly as possible.
The quickest way to get out is to submit a DML statement that has already been submitted (a
soft parse); otherwise Oracle will have to go thru the whole parsing process (a hard parse).
 
Here are the steps that happen during (hard) parsing:
 
-Translate the statement and verify the syntax is valid
-check the data dictionary and make sure the referenced objects exist
-get parsing locks on all required objects so the definitions don't change
-check and make sure the executing user has privileges to the objects
-figure out the best way (execution plan) to perform the request
-load all this into a shared SQL area so others won't have to get this far
-(route distributed statements)
 
3. Describe results (Queries only)

4. Bind variables
 
This is where your variables (like department_id) get attached. PLEASE use bind variables

Technology Focus - performance fine tuning in Oracle 10


5. Parallelize statement (optional)
 
If you want multiple processes to work on your statement, this is where Oracle splits it up for you
(more...uh...later)

6. Run
 
This is when Oracle takes a big breath and executes your statement. If you are running a
DELETE or UPDATE statement, those rows will be locked for data integrity until a commit or
rollback.
 
7. Fetch rows (Queries only)
 
If you ran a SELECT, this is the step that gets your rows and sends them back to you (ordered if
you requested them to be).
 
8. Close cursor
"The final stage of processing a SQL statement is closing the cursor."

Technology Focus - performance fine tuning in Oracle 11


An Explain Plan is a tool that you can use to have Oracle explain to you how it plans on
executing your query. This is useful in tuning queries to the database to get them to perform
better. Once you know how Oracle plans on executing your query, you can change your
environment to run the query faster.

Before you can use the EXPLAIN PLAN command, you need to have a PLAN_TABLE installed.
This can be done by simply running the $ORACLE_HOME/rdbms/admin/utlxplan.sql script in
your schema. It creates the table for you. After you have the PLAN_TABLE created, you issue
an EXPLAIN PLAN for the query you are interested in tuning. The command is of the form:

Example:

EXPLAIN PLAN FOR


select min(actt_sk) from ed_actv_typ where actt_cd like '6%'
/

Technology Focus - performance fine tuning in Oracle 12


Why using hints

It is a perfect valid question to ask why hints should be used. Oracle comes with an optimizer
that promises to optimize a query's execution plan. When this optimizer is really doing a good
job, no hints should be required at all. Sometimes, however, the characteristics of the data in the
database are changing rapidly, so that the optimizer (or more accuratly, its statistics) are out of
date. In this case, a hint could help. It must also be noted, that Oracle allows to lock the
statistics when they look ideal which should make the hints meaningless again.

All hints except /*+ rule */ cause the CBO to be used. Therefore, it is good practise to analyze
the underlying tables if hints are used (or the query is fully hinted).

There are many hints available. Some of them are


•FIRST_ROWS
•CHOOSE
•RULE
•INDEX
•INDEX_FFS
•USE_HASH
•USE_NL
•PARALLEL
•APPEND
•ORDERED

Technology Focus - performance fine tuning in Oracle 13


Analyze Statement

The ANALYZE statement can be used to gather statistics for a specific table, index or cluster.
The statistics can be computed exactly, or estimated based on a specific number of rows, or a
percentage of rows. If a table has not been analyzed, the cost-based optimizer can use only
rule-based logic to select the best access path.

If the table has proper statistics then the CBO will decide easily that which is the optimal path to
travel and retrieve the data, which will improve the performance.

ANALYZE TABLE employees COMPUTE STATISTICS;


ANALYZE INDEX employees_pk COMPUTE STATISTICS;

ANALYZE TABLE employees ESTIMATE STATISTICS SAMPLE 100 ROWS;


ANALYZE TABLE employees ESTIMATE STATISTICS SAMPLE 15 PERCENT;

Set OPTIMIZER_MODE = CHOOSE


By choosing this mode instead of either RULE / COST, DB will decide on the situation.

Technology Focus - performance fine tuning in Oracle 14


Incorrect Driving Table

If the table driving a join is not optimal, there can be a significant increase in the amount of time
required to execute a query. Consider the following example:
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. Because the parser
processes table names from right to left, the table name that is specified last (e.g., DEPT in the
example above) is actually the first table processed (the driving table).

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;

It is important that the table that is listed last in the FROM clause is going to return the fewest
number of rows. There is also potential to adjust your indexing to force the driving table. For
example, you may be able to make the COST_CENTER index a concatenated index, joined with
another column that is frequently used in SQL enquires with the column. This will avoid it
ranking so highly when joins take place.
Technology Focus - performance fine tuning in Oracle 15
Incorrect Index

WHERE clauses often provide the rule-based optimizer with a number of indexes that it could
utilize. The rule-based optimizer is totally unaware of how many rows each index will be required
to scan and the potential impact on the response time. A poor index selection will provide a
response time much greater than it would be if a more effective index was selected.

The rule-based optimizer has simple rules for selecting which index to use. These rules and
scenarios are described earlier in the various "What the RBO rules don't tell you" sections.
Let's consider an example.

An ERP package has been developed in a generic fashion to allow a site to use columns for
reporting purposes in any way its users please. There is a column called BUSINESS_UNIT that
has a single-column index on it. Most sites have hundreds of business units. Other sites have
only one business unit.

Our JOURNAL table has an index on (BUSINESS_UNIT), and another on


(BUSINESS_UNIT, ACCOUNT, JOURNAL_DATE). The WHERE clause of a query is as
follows:
WHERE business_unit ='A203'
AND account = 801919 AND journal_date between '01-DEC-2001' and '31-DEC-2001‘

The single-column index will be used in preference to the three-column index, despite the fact
that the three-column index returns the result in a fraction of the time of the single-column index.
This is because all columns in the single-column index are used in the query. In such a situation,
the only options open to us are to drop the index or use the cost-based optimizer. If you're not
using packaged software, you may also be able to use hints.

Technology Focus - performance fine tuning in Oracle 16


Incorrect Driving Index

The way you specify conditions in the WHERE clause(s) 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.
If two index rankings are equal -- for example, two single-column indexes both have their
columns in the WHERE clause -- Oracle will merge the indexes. The merge (AND-EQUAL)
order has the potential to have a significant impact on runtime. If the index that drives the query
returns more rows
than the other index, query performance will be suboptimal. 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';

Technology Focus - performance fine tuning in Oracle 17


 WHERE EXISTS sub-queries can be better than join if can you reduce drastically the number
of records in driver query. Otherwise, join is better.

WHERE EXISTS can be better than join when driving from parent records and want to make
sure that at least on child exists. Optimizer knows to bail out as soon as finds one record. Join
would get all records and then distinct them!

Query before tuning:

SELECT *
FROM suppliers, orders
WHERE suppliers.supplier_id = orders.supplier_id;

Query after tuning:

SELECT *
FROM suppliers
WHERE EXISTS
(select *
from orders
where suppliers.supplier_id = orders.supplier_id);

Exists returns TRUE whenever the subquery gives a row count > 1.

In this case once the where clause gets the true condition from EXISTS, it will select all rows
from the table.

Technology Focus - performance fine tuning in Oracle 18


 Consider NOT EXISTS instead of NOT IN.
When using “NOT IN”, the query performs nested full table scans, whereas for “NOT
EXISTS”, query can use an index within the sub-query.
 Avoid NOT in or NOT = on indexed columns. They prevent the optimizer from using indexes.
Use where amount > 0 instead of where amount! = 0.
 Avoid writing where project category is not null. Nulls can prevent the optimizer from using an
index.
 Consider using IN or UNION in place of OR on indexed columns. ORs on indexed columns
causes the optimizer to perform a full table scan.
 Avoid calculations on indexed columns. Write WHERE approved_amt > 26000/3 instead of
WHERE approved_amt/3 > 26000.
 Avoid this: SUBSTR(haou.attribute1,1,LENGTH(':p_otc')) = :p_otc). Consider this: WHERE  
haou.attribute1 like :p_otc||'%'
 Talk to your DBA. If you think that a column used in a WHERE clause should have an index,
don't assume that an index was defined. Check and talk to your DBA if you don't find any.
 Consider replacing outer joins on indexed columns with UNIONs. A nested loop outer takes
more time than a nested loop unioned with another table access by index.
 Consider adding small frequently accessed columns (not frequently updated) to an existing
index. This will enable some queries to work only with the index, not the table.
 If a query is going to read most of the records in a table (more than 60%), use a full table
scan.
 Try to group multiple sub queries into one.

Technology Focus - performance fine tuning in Oracle 19


 Consider NOT EXISTS instead of NOT IN.
When using “NOT IN”, the query performs nested full table scans, whereas for “NOT
EXISTS”, query can use an index within the sub-query.
 Avoid NOT in or NOT = on indexed columns. They prevent the optimizer from using indexes.
Use where amount > 0 instead of where amount! = 0.
 Avoid writing where project category is not null. Nulls can prevent the optimizer from using an
index.
 Consider using IN or UNION in place of OR on indexed columns. ORs on indexed columns
causes the optimizer to perform a full table scan.
 Avoid calculations on indexed columns. Write WHERE approved_amt > 26000/3 instead of
WHERE approved_amt/3 > 26000.
 Avoid this: SUBSTR(haou.attribute1,1,LENGTH(':p_otc')) = :p_otc). Consider this: WHERE  
haou.attribute1 like :p_otc||'%'
 Talk to your DBA. If you think that a column used in a WHERE clause should have an index,
don't assume that an index was defined. Check and talk to your DBA if you don't find any.
 Consider replacing outer joins on indexed columns with UNIONs. A nested loop outer takes
more time than a nested loop unioned with another table access by index.
 Consider adding small frequently accessed columns (not frequently updated) to an existing
index. This will enable some queries to work only with the index, not the table.
 If a query is going to read most of the records in a table (more than 60%), use a full table
scan.
 Try to group multiple sub queries into one.

Technology Focus - performance fine tuning in Oracle 20


Order of the tables in Joins:

If you specify 2 or more tables in the FROM clause of a SELECT statement, then Oracle parser
will process the tables from right to left, so the table name you specify last will be processed
first. In this case you have to choose one table as driving table.
Always choose the table with less number of records as the driving table.

Name the Columns in a Query:

There are three good reasons why it is better to name the columns in a query rather than to use
"select * from ...".
1. Network traffic is reduced. This can have a significant impact on performance if the table has
a large number of columns, or the table has a long or long raw column (both of which can be up
to 2 GB in length). These types of columns will take a long time to transfer over the network and
so they should not be fetched from the database unless they are specifically required.
2. The code is easier to understand.
3. It could save the need for changes in the future. If any columns is added to or removed from
the base table/view, then “select * “statement can produce wrong results set and statement may
fail.

Use table alias:

Always use table alias and prefix all column names with the aliases when you are using more
than one table.

Never compare NULL to anything else:

All expressions return NULL if one of the operands is NULL. This is applicable for all operators
except Concatenation operator (||).

Technology Focus - performance fine tuning in Oracle 21


Use Bind Variables:

It is also better to use bind variables in queries. That way the query becomes generic and
therefore re-usable. For example, instead of writing a query like -

SELECT ename, sal FROM emp WHERE deptno = 20;

Change it to -

SELECT ename, sal FROM emp WHERE deptno = :deptno;

The first query can be re-used for deptno number 20 only, whereas the second query can be
reused for any other deptno also.

Use EXISTS instead of DISTINCT:

Use EXISTS in place of DISTINCT if you want the result set to contain distinct values while
joining tables.

For example:

SELECT DISTINCT d.deptno, d.dname FROM dept d, emp e WHERE d.deptno = e.deptno;

The following SQL statement is a better alternative.

SELECT d.deptno, d.dname FROM dept d WHERE EXISTS


(SELECT e.deptno FROM emp e WHERE d.deptno = e.deptno);

Technology Focus - performance fine tuning in Oracle 22


Any computation of constants is performed only once when the statement is optimized rather
than each time the statement is executed. Consider these conditions that test for salaries
greater than $2000.
sal > 24000/12
sal > 2000
sal*12 > 24000

If a SQL statement contains the first condition, the optimizer simplifies it into the second
condition. Please note that optimizer does not simplify expressions across comparison
operators. The optimizer does not simplify the third expression into the second. For this reason,
we should write conditions that compare columns with constants whenever possible, rather than
conditions with expressions involving columns.

The Optimizer does not use index for the following statement:

SELECT *
FROM emp
WHERE sal*12 > 24000 ;

Instead of this use the following statement:

SELECT *
FROM emp
WHERE sal > 24000/12 ;

Technology Focus - performance fine tuning in Oracle 23


Use of NOT operator on indexed columns:

Never use NOT operator on an indexed column. Whenever Oracle encounters a NOT on an
index column, it will perform full-table scan.

For Example:
SELECT * FROM emp WHERE NOT deptno = 0;
Instead use the following:
SELECT * FROM emp WHERE deptno > 0;

Function or Calculation on indexed columns:

Never use a function or calculation on an indexed column. If there is any function is used on an
index column, optimizer will not use index.
For Example:

Do not use until need exactly match string:


SELECT * FROM emp WHERE SUBSTR (ename, 1, 3) = 'MIL';
Use following instead:
SELECT * FROM emp WHERE ename LIKE 'MIL%';

Technology Focus - performance fine tuning in Oracle 24


Do not use the following as || is the concatenate function.

Like other functions and it disables index.

SELECT * FROM emp WHERE ename || job = 'MILLERCLERK';


Use the following instead
SELECT * FROM emp WHERE ename = 'MILLER' AND job = 'CLERK';.

Avoid Transformed Columns in the WHERE Clause:

Use untransformed column values.


For example, use:
WHERE a.order_no = b.order_no
Rather than
WHERE TO_NUMBER (SUBSTR(a.order_no, INSTR(b.order_no, '.') - 1))
= TO_NUMBER (SUBSTR(a.order_no, INSTR(b.order_no, '.') - 1))

Technology Focus - performance fine tuning in Oracle 25


Combine Multiples Scans with CASE Statements:

Often, it is necessary to calculate different aggregates on various sets of tables. Usually, this is
done with multiple scans on the table, but it is easy to calculate all the aggregates with one
single scan. Eliminating n-1 scans can greatly improve performance.

Combining multiple scans into one scan can be done by moving the WHERE condition of each
scan into a CASE statement, which filters the data for the aggregation. For each aggregation,
there could be another column that retrieves the data.

The following example has count of all employees who earn less then 2000, between 2000 and
4000, and more than 4000 each month. This can be done with three separate queries.

SELECT COUNT (*) FROM emp WHERE sal < 2000;


SELECT COUNT (*) FROM emp WHERE sal BETWEEN 2000 AND 4000;
SELECT COUNT (*) FROM emp WHERE sal>4000;

However, it is more efficient to run the entire query in a single statement. Each number is
calculated as one column. The count uses a filter with the CASE statement to count only the
rows where the condition is valid. For example:

SELECT COUNT (CASE WHEN sal < 2000


THEN 1 ELSE null END) count1,
COUNT (CASE WHEN sal BETWEEN 2001 AND 4000
THEN 1 ELSE null END) count2,
COUNT (CASE WHEN sal > 4000
THEN 1 ELSE null END) count3
FROM emp;

Technology Focus - performance fine tuning in Oracle 26


Constraint checks – NOT NULL constraint incurs overhead

PROCEDURE calc_m IS
m NUMBER NOT NULL:=0;
a NUMBER;
b NUMBER;
BEGIN
...
m := a + b;
...
END;
 
Several of the PL/SQL numeric data types are constrained. PL/SQL allows any variable to be
constrained to only NOT NULL values. Constraint checks, including the NOT NULL constraint,
require an extra byte code instruction on every assignment. The NOT NULL constraint,
therefore, does not come for free; it requires the PL/SQL compiler to ensure NOT NULLness
after every operation. Constrained data types used in PL/SQL blocks which have no associated
exception handler are excellent candidates for replacement by corresponding unconstrained
types.
Consider the example on the above, which uses the NOT NULL constraint for m.
Because 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
A more efficient way to write the same example is shown on the below.

Technology Focus - performance fine tuning in Oracle 27


PROCEDURE calc_m IS
m NUMBER; --no constraint
a NUMBER;
b NUMBER;
BEGIN
...
m := a + b;
IF m IS NULL THEN
-- raise error
END IF;
END;

Conditional control statements


– In logical expressions, PL/SQL stops evaluating the expression as soon as the result is
Determined. Performance can be improved by tuning conditional constructs carefully.

– Scenario 1
IF (sal < 1500) OR (comm IS NULL) THEN
...
END IF;

– Scenario 2
IF credit_ok(cust_id) AND (loan < 5000) THEN
...
END IF;

Technology Focus - performance fine tuning in Oracle 28


Example 1:
IF (sal < 1500) OR (comm IS NULL) THEN
...
END IF;
In this example, when the value of sal is less than 1,500 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).
Example 2:
IF credit_ok(cust_id) AND (loan < 5000) THEN
...
END IF;

In this example, the Boolean function CREDIT_OK is always called. However, if you
switch the operands of AND as follows, the function is called only when the expression
loan < 5000 is true (because AND returns TRUE only if both its operands are true):
IF (loan < 5000) AND credit_ok(cust_id) THEN
...
END IF;

Technology Focus - performance fine tuning in Oracle 29


Pinning Packages

One way to improve performance is to pin frequently used packages in the shared pool.

When a package is pinned, it is not aged out with the normal least recently used (LRU)
mechanism that Oracle otherwise uses to flush out a least recently used package. The package
remains in memory no matter how full the shared pool gets or how frequently you access the
package.

You pin packages with the help of the DBMS_SHARED_POOL package.

Example:

SYS.DBMS_SHARED_POOL.KEEP('SYS.STANDARD','P');

To remove the same from pinning

SYS.DBMS_SHARED_POOL.UNKEEP('SYS.STANDARD','P');

Technology Focus - performance fine tuning in Oracle 30


Subquery Factoring

Subquery factoring, also known as the WITH clause, provides a convenient and flexible way for
us to define subqueries and in-line views in Oracle 9i. The primary purpose of subquery
factoring is to reduce repeated table accesses by generating temporary datasets during query
execution. However, even if we do not take advantage of this internal query optimisation, we can
use subquery factoring to structure our complex SQL statements in a more logical and
understandable format.

The following syntax example is possibly more common in everyday use. We define two named
subqueries, but the second builds on the first.

WITH subquery_name AS ( SELECT ... FROM table ) ,


another_subquery_name AS ( SELECT ... FROM subquery_name )
SELECT ... FROM another_subquery_name WHERE ...

This form of subquery factoring is the semantic equivalent of the following pseudo-SQL.

SELECT ... FROM (


SELECT ... FROM (
SELECT ...))

Technology Focus - performance fine tuning in Oracle 31


Use NOCOPY Clause:

When a parameter is passed as an IN variable, it is passed by reference. Since it will not


change, PL/SQL uses the passed variable in the procedure/function. When variables are
passed in OUT or INOUT mode, a new variable is define, and the value is copied to the passed
variable when the procedure ends. If the variable is a large structure such as a PL/SQL table or
an array, the application could see a performance degradation cause by copying this structure.

The NOCOPY clause tells to PL/SQL engine to pass the variable by reference, thus avoiding the
cost of copying the variable at the end of the procedure. The PL/SQL engine has requirements
that must be met before passing the variable by reference and if those requirements are not
met, the NOCOPY clause will simply be ignored by the PL/SQL engine.

Example:

PROCEDURE in_out_nocopy (p_tab IN OUT NOCOPY t_tab) IS


BEGIN
NULL;
END;

in_out_nocopy(l_tab); -- pass IN OUT NOCOPY parameter

Technology Focus - performance fine tuning in Oracle 32


Use BULK COLLECT:

1. BULK COLLECT avoids context switching. context switching is nothing but movement of data
between PLSQL engine and SQL Engine.

A bulk collect is a method of fetching data where the PL/SQL engine tells the SQL engine to
collect many rows at once and place them in a collection.  The SQL engine retrieves all the rows
and loads them into the collection and switches back to the PL/SQL engine.  All the rows are
retrieved with only 2 context switches.

The tradeoff with BULK COLLECT, like so many other performance-enhancing features, is "Run
faster but consume more memory." Specifically, memory for collections is stored in the Program
Global Area (PGA), not the System Global Area (SGA). SGA memory is shared by all sessions
connected to Oracle Database, but PGA memory is allocated for each session

Technology Focus - performance fine tuning in Oracle 33


Normal code:
DECLARE
CURSOR major_polluters IS
SELECT name, mileage
FROM cars_and_trucks
WHERE vehicle_type IN ('SUV', 'PICKUP');
BEGIN
FOR bad_car IN major_polluters
LOOP
names.EXTEND;
names (major_polluters%ROWCOUNT) := bad_car.name;
mileages.EXTEND;
mileages (major_polluters%ROWCOUNT) := bad_car.mileage;
END LOOP;

... now work with data in the arrays ...


END;
BULK COLLECT Code:
DECLARE
names name_varray;
mileages number_varray;
BEGIN
SELECT name, mileage
FROM cars_and_trucks
BULK COLLECT INTO names, mileages
WHERE vehicle_type IN ('SUV', 'PICKUP');

... now work with data in the arrays ...


END;

Technology Focus - performance fine tuning in Oracle 34

You might also like