TATA CONSULTANCY SERVICES
Coding and Tuning
Guidelines
for
Developers and Tuners
Confidential
TCS Confidential
TATA CONSULTANCY SERVICES
Overview
Performance is a continuing process as far as database applications are concerned. Performance
comes into picture at various stages of software development lifecycle right from Requirement
Analysis through Design, Development, Testing, Deployment to Maintenance. It is with this aim
we have drafted this document. This document will come into use in the Development and
Deployment stages of all Oracle Database Applications. It aims at
Developing code with performance in mind
Reducing time for Tuning before code rolls out into Production
Confidential
TCS Confidential
TATA CONSULTANCY SERVICES
INDEX
Overview...........................................................................................................................................................2
INDEX.............................................................................................................................................................3
SQL Tuning Guidelines..................................................................................................................................4
Avoid datatype mismatch...........................................................................................................................4
Avoid functions on Indexed columns........................................................................................................4
Define initial columns in composite indexes.............................................................................................4
Using WHERE instead of HAVING.........................................................................................................5
Avoid nested queries...................................................................................................................................6
Using driving table in RULE based Optimizer........................................................................................6
Not exists and Outer joins.....................................................................................................................6
Do not use NOT EQUAL...........................................................................................................................6
Functional index for NVL columns...........................................................................................................6
Reduce the Number of Trips to the Database..........................................................................................7
Using TRUNCATE instead of DELETE..................................................................................................8
Advantages of using DECODE..................................................................................................................8
Counting rows from Table.........................................................................................................................9
Use UNION-ALL in Place of UNION (Where Possible).........................................................................9
Use WHERE Instead of ORDER BY Clause.........................................................................................10
Use IN in Place of OR...............................................................................................................................11
Full Table Scans are better?....................................................................................................................12
When to go for Fast Full Scans................................................................................................................12
Bitmap Indexes..........................................................................................................................................12
Using composite indexes...........................................................................................................................12
PL/SQL Tuning Guidelines..........................................................................................................................13
Use of bind variables................................................................................................................................13
Avoiding unnecessary database calls......................................................................................................13
Use of PLS_INTEGER.............................................................................................................................14
Avoid BINARY_INTEGER.....................................................................................................................14
Pinning stored procedures.......................................................................................................................14
Using WHEN clause in triggers...............................................................................................................14
Use AFTER row triggers..........................................................................................................................14
Use of Bulk binding..................................................................................................................................15
Use of LIMIT clause.................................................................................................................................15
PRO* C Tuning Guidelines..........................................................................................................................16
Confidential
TCS Confidential
TATA CONSULTANCY SERVICES
Precompiler Options.................................................................................................................................16
SQL Tuning Guidelines
Avoid datatype mismatch
Avoid data type mismatch for index columns. If there are datatype mismatches then the index
on that particular column will not be used and a FULL TABLE SCAN will be made.
Avoid functions on Indexed columns
Avoid functions on index columns. In this case too the presence of a function will make the
optimizer go for FULL TABLE SCAN.
Define initial columns in composite indexes
Confidential
TCS Confidential
TATA CONSULTANCY SERVICES
Ensure initial columns are defined when using a composite index. If the initial columns are not
used. Then the composite index will not be made use of.
For eg:
Consider a table in which brand and product columns have a composite index. And we
execute this query.
Select count(*)
From products
Where price < 1000;
The composite index will not be made use of. But the same composite index will be hit for
the query given below.
Select count(*)
From products
Where brand = Arrow;
Hence its important to that initial columns are defined while we are making use of
composite indexes. We can hit the index by doing the following.
Select count(*)
From products
Where brand > 0
and price < 1000;
Using WHERE instead of HAVING
Move conditions from having clause to where clause
For eg:
Consider this query
Select brand, sum(price)
From products
Group by brand
Confidential
TCS Confidential
TATA CONSULTANCY SERVICES
Having brand = Arrow;
The above query can be re-written as the one below. This will ensure the index if present
is made use of.
Select brand, sum(price)
From products
Where brand = Arrow
Group by brand;
Avoid nested queries
Rewrite nested queries using joins, whenever possible
Using driving table in RULE based Optimizer
Ensure smallest table appears last when specifying a join query if you are using RULE based
optimizer.
Not exists and Outer joins
Replace not in by not exists or outer join. This will ensure indexes are hit if present.
Do not use NOT EQUAL
Replace != by union or < and >
Functional index for NVL columns
Make use of functional indexes in case NVL has to be avoided.
For eg:
Confidential
TCS Confidential
TATA CONSULTANCY SERVICES
Create index idx_test on test(nvl(column_1,0));
Reduce the Number of Trips to the Database
Every time a SQL statement is executed, ORACLE needs to perform many internal processing
steps; the statement needs to be parsed, indexes evaluated, variables bound, and data blocks
read. The more you can reduce the number of database accesses, the more overhead you can
save.
For example:
There are 3 distinct ways of retrieving data about employees who have employee numbers 0342
or 0291.
Method 1 (Least Efficient) :
SELECT
EMP_NAME, SALARY, GRADE
FROM
EMP
WHERE
EMP_NO = 0342;
SELECT
EMP_NAME, SALARY, GRADE
FROM
EMP
WHERE
EMP_NO = 0291;
Method 2 (Next Most Efficient) :
DECLARE
CURSOR C1(E_NO NUMBER) IS
SELECT
EMP_NAME, SALARY, GRADE
FROM
EMP
WHERE EMP_NO = E_NO;
BEGIN
OPEN C1(342);
FETCH
C1 INTO , , ;
.
.
OPEN C1(291);
Confidential
TCS Confidential
TATA CONSULTANCY SERVICES
FETCH
C1 INTO , , ;
CLOSE C1;
END;
Method 3 (Most Efficient) :
SELECT
A.EMP_NAME, A.SALARY, A.GRADE,
B.EMP_NAME, B.SALARY, B.GRADE,
FROM
EMP
EMP
A,
WHERE
AND
A.EMP_NO = 0342
B.EMP_NO = 0291;
So make use of Stored Procedures where ever possible.
Using TRUNCATE instead of DELETE
When rows are removed from a table, under normal circumstances, the rollback segments are
used to hold undo information; if you do not commit your transaction, Oracle restores the data to
the state it was in before your transaction started.
With TRUNCATE, no undo information is generated. Once the table is truncated, the data cannot
be recovered back. It is faster and needs fewer resources.
Use TRUNCATE rather than DELETE for wiping the contents of small or large tables when you
need no undo information generated.
Advantages of using DECODE
The DECODE statement provides a way to avoid having to scan the same rows repetitively or to
join the same table repetitively.
For eg:
SELECT
COUNT(*), SUM(SAL)
FROM
EMP
Confidential
TCS Confidential
TATA CONSULTANCY SERVICES
WHERE DEPT_NO = 0020
AND
ENAME LIKE SMITH%;
SELECT
COUNT(*), SUM(SAL)
FROM
EMP
WHERE DEPT_NO = 0030
AND
ENAME LIKE SMITH%;
You can achieve the same result much more efficiently with DECODE:
SELECT COUNT(DECODE(DEPT_NO, 0020, X, NULL)) D0020_COUNT,
COUNT(DECODE(DEPT_NO, 0030, X, NULL)) D0030_COUNT,
SUM(DECODE(DEPT_NO, 0020, SAL, NULL)) D0020_SAL,
SUM(DECODE(DEPT_NO, 0030, SAL, NULL)) D0030_SAL
FROM
EMP
WHERE ENAME LIKE SMITH%;
Similarly, DECODE can be used in GROUP BY or ORDER BY clause effectively.
Counting rows from Table
Contrary to popular belief, COUNT(*) is faster than COUNT(1). If the rows are being returned via
an index, counting the indexed column is faster still.
For eg:
Select COUNT(EMPNO) from emp;
Use UNION-ALL in Place of UNION (Where Possible)
When the query performs a UNION of the results of two queries, the two result sets are merged
via the UNION-ALL operation, and then the result set is processed by a SORT UNIQUE operation
before the records are returned to the user.
If the query had used a UNION-ALL function in place of UNION, then the SORT UNIQUE
operation would not have been necessary, thus improving the performance of the query.
Confidential
TCS Confidential
TATA CONSULTANCY SERVICES
10
For example:
Least Efficient :
SELECT
ACCT_NUM, BALANCE_AMT
FROM
DEBIT_TRANSACTIONS
WHERE
TRAN_DATE = 31-DEC-95
UNION
SELECT
ACCT_NUM, BALANCE_AMT
FROM
CREDIT_TRANSACTIONS
WHERE
TRAN_DATE = 31-DEC-95
Most Efficient :
SELECT
ACCT_NUM, BALANCE_AMT
FROM
DEBIT_TRANSACTIONS
WHERE
TRAN_DATE = 31-DEC-95
UNION ALL
SELECT
ACCT_NUM, BALANCE_AMT
FROM
CREDIT_TRANSACTIONS
WHERE
TRAN_DATE = 31-DEC-95
Use WHERE Instead of ORDER BY Clause
ORDER BY clauses use an index only if they meet 2 rigid requirements.
All of the columns that make up the ORDER BY clause must be contained within a single
index in the same sequence.
All of the columns that make up the ORDER BY clause must be defined as NOT NULL within
the table definition. Remember, null values are not contained within an index.
WHERE clause indexes and ORDER BY indexes cannot be used in parallel.
For example:
Consider a table DEPT with the following fields:
Confidential
TCS Confidential
TATA CONSULTANCY SERVICES
DEPT_CODE
PK
NOT NULL
DEPT_DESC
NOT NULL
DEPT_TYPE
NULL
NON UNIQUE INDEX (DEPT_TYPE)
Least Efficient : (Here, index will not be used)
SELECT
DEPT_CODE
FROM
DEPT
ORDER BY
DEPT_TYPE
Explain Plan:
SORT ORDER BY
TABLE ACCESS FULL
Most Efficient : (Here, index will be used)
SELECT
DEPT_CODE
FROM
DEPT
WHERE
DEPT_TYPE > 0
Explain Plan:
TABLE ACCESS BY ROWID ON EMP
INDEX RANGE SCAN ON DEPT_IDX
Use IN in Place of OR
The following query can be replaced to improve the performance as shown below:
Least Efficient:
SELECT . . .
FROM
LOCATION
WHERE
LOC_ID = 10
OR
LOC_ID = 20
Confidential
TCS Confidential
11
TATA CONSULTANCY SERVICES
OR
12
LOC_ID = 30
Most Efficient:
SELECT . . .
FROM
LOCATION
WHERE LOC_IN IN (10,20,30)
Full Table Scans are better?
When index scan performs more block visitations than a full table scan, better to use full table
scans
When to go for Fast Full Scans
Fast full table scans are an alternative to full table scans when the index contains all the
columns that are needed for the query. This can be used by using Optimizer Hint INDEX_FFS.
Bitmap Indexes
Consider bitmap indexes when where clause predicate contain low-cardinality columns,
contain logical operations such as OR, AND or NOT on those columns. It is advisable that bitmap
indexes are not used in OLTP applications.
Using composite indexes
Make use of composite indexes. These need to be ordered in the decreasing order of
selectivity.
Indexes on Foreign Key
Create indexes on foreign key columns if the queries always retrieve master-detail
relationship-based rows.
Confidential
TCS Confidential
TATA CONSULTANCY SERVICES
13
PL/SQL Tuning Guidelines
Use of bind variables
Making use of bind variables will reduce frequent parsing.
Avoiding unnecessary database calls
Avoid selects against the database when the same functionality can be
achieved in PL/SQL by just assigning to the variables. System variables like UID, SYSDATE can
be assigned to variables without select statements.
We can make use of assignments instead of making a SQL statement.
For eg:
Declare
From_date date;
Confidential
TCS Confidential
TATA CONSULTANCY SERVICES
14
begin
Select sysdate into from_date from dual;
End;
Can be replaced by
Declare
From_date
begin
From_date:=sysdate
End;
Use of PLS_INTEGER
Make use of PLS_INTEGER instead of NUMBER or INTEGER in loop variables as
PLS_INTEGER makes use of machine arithmetic whereas NUMBER and INTEGER makes use
of functional arithmetic. Hence PLS_INTEGER will be faster.
Avoid BINARY_INTEGER
The use of BINARY_INTEGER datatypes within arithmetic operations performs slower than the
same operation using an INTEGER datatype.
Pinning stored procedures
Anonymous PL/SQL should be moved into a stored object when possible and this object then
pinned in the shared pool using dbms_shared_pool.keep() if the object is frequently referenced.
Using WHEN clause in triggers
Use a WHEN clause on the trigger if at all possible so that the trigger is only fired when
absolutely necessary.
Use AFTER row triggers
Confidential
TCS Confidential
TATA CONSULTANCY SERVICES
15
Use AFTER row triggers instead of BEFORE row triggers if at all possible. After row triggers are
faster.
Use of Bulk binding
Bulk binds improve performance by minimizing the number of context switches between PL/SQL
and SQL engines while they pass an entire collection of elements (varray, nested tables, index-by
table, or host array) as bind variables back and forth. Hence make use of BULK COLLECT and
FORALL.
Use of LIMIT clause
Using LIMIT clause during BULK COLLECT will reduce CPU utilization.
For eg:
set serveroutput on
declare
TYPE tstrings IS TABLE OF string(255) INDEX BY BINARY_INTEGER;
type tnumbers IS TABLE OF FLOAT INDEX BY BINARY_INTEGER;
n tstrings;
cursor c is select object_name from user_objects;
bulk_limit number;
begin
open c;
-- first bulk 10
dbms_output.put_line('-- first bulk 10');
bulk_limit := 10;
fetch c bulk collect into n LIMIT bulk_limit;
for i in n.first..n.last loop
dbms_output.put_line(n(i));
end loop;
-- second bulk 15
dbms_output.put_line('-- second bulk 15');
Confidential
TCS Confidential
TATA CONSULTANCY SERVICES
16
bulk_limit := 15;
fetch c bulk collect into n LIMIT bulk_limit;
for i in n.first..n.last loop
dbms_output.put_line(n(i));
end loop;
close c;
end;
/
PRO* C Tuning Guidelines
Precompiler Options
Use HOLD_CURSOR=YES and RELEASE_CURSOR=NO pre-compiler options while
pre-compiling. Using these options when MODE=ANSI will not make use of these options.
These two parameters can be entered in line in a program with the following syntax:
EXEC ORACLE OPTION (HOLD_CURSOR=NO);
EXEC ORACLE OPTION (RELEASE_CURSOR=YES);
MAXOPENCURSORS (default value 10) signifies the initial size of the program cursor cache.
The size of the cursor cache may grow, depending on the values of HOLD_CURSOR and
RELEASE_CURSOR. Hence increase the MAXOPENCURSORS value in pre-compiling options.
Confidential
TCS Confidential
TATA CONSULTANCY SERVICES
Confidential
TCS Confidential
17