Pages

Tuesday, August 10, 2010

Monitor your sequences

Never let your sequence exceed your column precision. Here is simple way to generate a check..

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

While using the NEXTVAL function in a select query (CASE) , inside a false condition, it increases the current value of the sequence.

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;