Tuesday, August 10, 2010
Monitor your sequences
select ds.sequence_name,
dtc.table_name,
dtc.column_name,
ds.last_number,
dtc.data_precision,
round(ds.last_number/power(10,dtc.data_precision),2)*100||'%' percent_used
from all_sequences ds,
all_tab_columns dtc
where ds.sequence_name like 'SEQ_'||trim(upper(dtc.column_name))
order by percent_used desc, sequence_name;
Avoid Use of Sequence in the CASE, DECODE, NVL
Create Sequence TEST_SEQ Start with 1 increment by 1;
SELECT TEST_SEQ.CURRVAL FROM DUAL
------------
2
SELECT CASE WHEN 1>2 THEN TEST_SEQ.NEXTVAL ELSE TEST_SEQ.CURRVAL END SEQ_NO FROM DUAL;
------------
3
In second select statement, NEXTVAL is used inside a FALSE condition
The process of evaluating a sequence reference in an SQL statement is somewhat unique. It's almost like Oracle treats them as substitution variables on a per-row basis, prior to any other expression/condition evaluations, evaluating .NEXTVAL first (if referenced), then .CURRVAL, then the other conditions/expressions.
This is in part due to the need to return the same sequence.nextval value within a row, regardless of the number of sequence.nextval references. To do this, it probably goes ahead and evaluates .NEXTVAL even if it is not "needed" (due to a false condition in a CASE, DECODE, etc. statement). Interestingly that's how sequences work, and its documented that way. The SQL REFERENCE manual (Chapter 3 "Pseudo columns", section for "sequences") states "Within a single SQL statement containing a reference to NEXTVAL, Oracle increments the sequence only once: For each row returned by the outer query block of a SELECT statement."
so, if the query block references NEXTVAL and returns a row, the sequence is incremented. doesn't matter if you use it in a case, decode, nvl or anything else.
Suggested to use the function which will not be direct reference to the sequence and therefore it will not increment for the FALSE condition. GettestSequence custom function will get the next value from the SEQUENCE.
SELECT CASE WHEN 1>2 THEN GettestSequence('INSTRUMENT') ELSE c14_ads.TEST_SEQ.CURRVAL END SEQ_NO FROM DUAL;
Friday, May 28, 2010
How to get Age in Years and Months? (Using MONTHS_BETWEEN)
select trunc(months_between(<(today)>,<(birth Date)>)/12) years,
FLOOR(months_between(<(today)>,<(birth Date)>)-12*trunc(months_between(<(today)>,<(birth Date)>)/12)) months
from dual;
So for e.g. If somebody was born on 01/01/2009 and you want to know the age then run the following
select trunc(months_between(SYSDATE,to_date('01/01/2009','mm/dd/yyyy'))/12) years,
FLOOR(months_between(SYSDATE,to_date('01/01/2009','mm/dd/yyyy'))-12*trunc(months_between(SYSDATE,to_date('01/01/2009','mm/dd/yyyy'))/12)) months
from dual;
Wednesday, March 31, 2010
Use of Bind Variables in Dynamic SQLs
"create or replace procedure dsal(p_empno in number)
as
begin
execute immediate 'update emp set sal = sal*2 where empno = '||p_empno; commit;
end;
The way to use bind variables instead is to change the EXECUTE IMMEDIATE command as follows:
create or replace procedure dsal(p_empno in number) as
begin
execute immediate 'update emp set sal = sal*2 where empno = :x' using p_empno;
commit;
end;
/"
Use Bulk Collect/ Object Type for batch Processing
Enable Oracle to perform hash joins
Front End Field Validation
Apply Validation on the Front End. Don’t let DB constraint drive front end validation |
Avoid Distinct if you can
SELECT DISTINCT dept_no, dept_name FROM dept D, emp E WHERE D.dept_no = E.dept_no; | SELECT dept_no, dept_name FROM dept D WHERE EXISTS ( SELECT 'X' FROM emp E WHERE E.dept_no = D.dept_no); |
Avoid queries with condition IS NULL
Avoid queries with condition IS NULL ( Rather create column with NOT NULL Default value). If IS NULL is required, consider replacing it with a NVL call and a function based index, while this may not help with outer joins, it will help with IS NULL type selects. select count(*) from test where object_id is null; ( TABLE ACCESS (FULL)) select count(*) from test where nvl(object_id,-1)=-1; - INDEX (RANGE SCAN) OF 'FBI_TEST' (NON-UNIQUE)" |
Use GOTO Statements
INSERT INTO MyTable (char_col) VALUES ('Done!');
END;/"
Use NOCOPY Parameter hint for Stored Procedures
Example:
PROCEDURE in_out_nocopy (p_tab IN OUT NOCOPY t_tab) IS BEGIN NULL; END;
Saturday, March 13, 2010
Hide Query Complication using Types
1) Create Type
2) Write Stored Procedure
3) Query
Create Type:
----------------------------------------------------------
Drop type OT_TEST_ROW;
Drop type OT_TEST;
CREATE OR REPLACE
TYPE "OT_TEST_ROW" AS OBJECT
--===========================================================================
-- Application : HCP - NJTA
--
-- Description : This type is to populate Data for High Variance
--
-- Modification History:-
-- --------------------------------------------------------------------------
-- Date Name Comments
-- -------- ------------------- --------------------------------------------
-- 03/13/10 Parag Wardhane Created.
--===========================================================================
(
COL_DATE DATE,
COL_CHAR VARCHAR2(10),
COL_NUMBER NUMBER(10,2)
)
/
CREATE OR REPLACE
TYPE "OT_TEST" AS TABLE OF
--===========================================================================
-- Application : HCP - NJTA
--
-- Description : This type is to populate Data for High Variance
--
--
-- Modification History:-
-- --------------------------------------------------------------------------
-- Date Name Comments
-- -------- ------------------- ---------------------------------------------
-- 03/13/10 Parag Wardhane Created.
--===========================================================================
OT_TEST_ROW;
/
2) Write Stored procedure
-----------------------------------------
CREATE OR REPLACE FUNCTION HideQueryComplication (arg_in_Testid IN NUMBER)
RETURN OT_TEST
IS
V_AttemptStep VARCHAR2(500) := 'attempting to initialize';
V_error_msg VARCHAR2(400);
v_success VARCHAR2(1);
V_ErrorCode NUMBER DEFAULT 0;
V_ErrorText VARCHAR2(400);
V_CustomErrorText VARCHAR2(400);
V_ErrorReturnCode NUMBER;
V_CountOrgs NUMBER := 1;
l_data OT_TEST := OT_TEST();
l_BlankData OT_TEST := OT_TEST();
V_Counter NUMBER := 1;
BEGIN
For TestRec in ( SELECT sysdate col_date,'TEST' col_char,'1234' col_number
FROM DUAL /* Any Complicated Query */ ) LOOP
l_data.extend;
l_data(V_Counter) := OT_TEST_ROW(
TestRec.col_date, /* DATE */
TestRec.col_char, /*VARCHAR2 */
TestRec.col_number /*NUMBER*/ );
V_Counter := V_Counter + 1;
END LOOP;
RETURN l_data;
EXCEPTION
WHEN OTHERS THEN
V_CustomErrorText := ': ' || 'While ' || V_AttemptStep;
V_ErrorCode := SQLCODE;
V_ErrorText := SUBSTR(SQLERRM, 1, 400);
RETURN l_BlankData ;
END HideQueryComplication;
/
--------------------------------------------------------
2) Query:
SELECT HideQueryComplication(1) FROM DUAL;
Saturday, February 27, 2010
Use ROWNUM for Pagination!!!

Use of ROWNUM in the queries can be very useful to improve query performance for pagination.
select * from
( select rownum rnum, a.* from (your_query) a where rownum <= :M )
where rnum >= :N;
select * from (
select /*+ first_rows(25) */ your_columns, row_number() over (order by something unique) rn from your_tables )
where rn between :n and :m
order by rn;
Avoid accidental table scans
Table scans that occur unintentionally are a major source of poorly performing SQL. Causes include:
a. Missing Index
b. Using “!=“, “<>” or NOT
i. Use inclusive range conditions or IN lists
c. Looking for values that are NULL
i. Use NOT NULL values with a default value
d. Using functions on indexed columns – Function Based Indexes.
Use “functional” indexes in Oracle8i and above
One of the most fundamental SQL tuning problems is the “accidental” table scan. Accidental table scans usually occur when the SQL programmer tries to perform a search on an indexed column that can’t be supported by an index. This can occur when:
Using != (not equal to). Even if the not equals condition satisfies only a small number of rows, Oracle will not use an index to satisfy such a condition. Often, you can re-code these queries using > or IN conditions, which can be supported by index lookups.
Searching for NULLS. Oracle won’t use an index to find null values, since null values are not usually stored in an index (the exception is a concatenated index entry where only some of the values are NULL). If you’re planning to search for values which are logically missing, consider changing the column to NOT NULL with a DEFAULT clause. For instance, you could set a default value of “UNKNOWN” and use the index to find these values.
Using functions on indexed columns. Any function or operation on an indexed column will prevent Oracle from using an index on that column. For instance, Oracle can’t use an index to find SUBSTR(SURNAME,1,4)=’PWAR’. Instead of manipulating the column, try to manipulate the search condition. In the previous example, a better formulation would be SURNAME LIKE ‘PWAR%’. In Oracle8i you can create functional indexes, which are indexes created on functions, providing that the function always returns the same result when provided with the same inputs. This allows you, for instance, to create an index on UPPER(surname).
Common Complaints
Every application big or small at some point in time will have performance issues in its life spam. Some of the common complaints are
1) Application is very slow
2) Reports taking hours to generate
3) Schedule jobs taking way too long to complete
4) Tired of throwing money @ Oracle consulting.
By taking some pro-active approach and setting the right expectation some of the issues can be handled. There is no single Oracle init parameter which will fix all the problems.
Always design and develop with performance in mind
All too often, SQL tuning is performed on an application designed and developed with virtually no consideration given to performance requirements. SQL tuning is often the best option for tuning such applications, but it is both more efficient and effective to design an application with performance in mind.
Producing good performance by design requires that the following activities occur within the development life-cycle:
1) Identify performance targets
2) Measure performance as early as possible.
3) Focus on key areas of the application
4) Prototype critical portions of the application
5) Consider de-normalization where ever applicable.
Establish a tuning and development environment
1) A significant portion of SQL that performs poorly in production was originally crafted against empty or nearly empty tables.
2) Make sure you establish a reasonable sub-set of production data that is used during development and tuning of SQL
3) Make sure your developers understand EXPLAIN PLAN and tkprof, or equip them with commercial tuning tools.
Keep it Simple.
1) Balance/Reduce the workload (If Possible).
2) Pre – Generate reports overnight when there is less load on the system.
3) Parallelize the queries – Use the full potential of the system.
Execute Smart Queries
1) Index wisely - Use of Indexes
2) Eliminate Full table scans.
3) Use concatenated indexes where appropriate
4) Consider advanced indexing options
a. Hash Clusters
b. Bit mapped indexes
c. Index only tables