Mohamed Houri’s Oracle Notes

February 26, 2007

ORA-01555 and set transaction : another reason

Filed under: Ora-01555 — hourim @ 12:31 pm

Another reason that might cause ora-01555 to happen on rollback segment YYL_RB while we have explicitly set the transaction so that it will use the rollback segment XXL_RB can be explained by the beginning and the end of a transaction. When using the following command:


We have to ensure that this command is the first instruction of the transaction. Otherwise we will get the following error:

ORA-01453: SET TRANSACTION must be first statement of transaction

The question we have to ask is: when the transaction finishes? The transaction finishes when a commit or a rollback is issued. Thus, if you set your transaction to use rollback segment xxl_rb be aware that when you commit or you rollback, your transaction has finished and is no longer instructed to use xxl_rb rollback segment for its redo/undo. Be aware also that any DDL issued in your transaction such as truncate table marks the transaction as finished.

February 22, 2007

ORA-01555 and set transaction use rollback segment XXL_RB

Filed under: Ora-01555 — hourim @ 8:02 am

If you do not understand why you got a rollback segment snapshot too old on YYL_RB rollback segment in a transaction where you have explicitly instructed oracle to use the rollback segment XXL_RB, then read this ora-1555-and-set-transaction.pdf

February 8, 2007

How to avoid ora-01555 error

Filed under: Ora-01555 — hourim @ 12:14 pm

When dealing with oracle initial loads or with massif updates/deletes that generate undo (also known as rollback) and redo overheads, then the most frequent error in this context is the so famous ORA-01555: Rollback segment snapshot too old.

What also makes this error very frequent in many production applications is the data volume difference between test and production environments of those applications. Due to this data volume difference, the ORA-01555 error takes place most frequently in production were we are too late to change the logic and were it is so difficult to intervene.

This is why one of the obvious but very important solution to avoid this error is to have a real test environment with a leat the same data volume as it will be the case in production. Thus if the ORA-01555 error will have to happen, it will be pointed out much earlier in the development process making changes more flexible.

In On-Line Transaction Processing (OLTP) systems I have been faced with the ORA-01555 error in many cases. One of the main actions I realised I have to do in order to avoid it is to do not commit accross fetch (this is what many developers came to a long time before me).

Commit across fecth represents a commit inside a loop as shown here below:

FOR r_cur IN c_cur LOOP

-- Traitement is done here
 update/delete ....
 COMMIT; -- commit across fetch increases the odds of ora-01555

Thus in order to drastically decrease the odds of ORA-01555, commit outside the loop as shown below:

FOR r_cur IN c_cur LOOP
 -- Traitement is done here
 update/delete ....
 COMMIT; -- Commit is done here outside the loop

But commiting only once for the whole process will certainly contribute to avoid ORA-01555 error but may also increases the odds of its twin sister ORA-01562 : failed to extend rollback segment number string.

So that the probability of the occurence of both errors will decrease, the above plsql code are updated as follows:

 v_record_number NUMBER := 0;
 v_commit_val NUMBER := 500; -- commit when 500 records have been processed


LOOP -- main technical loop
 v_record_number := 0;

FOR r_cur IN c_cur LOOP

-- log the number of treated record
 v_record_number := v_record_number + 1;

-- Traitement is done here
 update/delete ....

-- Decide to commit
 IF v_record_number >= v_commit_val THEN


-- Cursor is closed automatically in the for loop
 COMMIT; -- commit outside the inner loop

EXIT WHEN v_record_number less than v_commit_val ;
 END LOOP; -- inner loop
 END; -- main technical loop</strong>

In any way, one thing you must absolutely consider is to make your process restartable. If not, then any ORA-01555 or ORA-01562 error will let updates done in the FOR loop cursor in a totally unknown state and will be considered as fatal.

Using Oracle Partitioning (I)

Filed under: Partitioning — hourim @ 12:13 pm

The Partitioning aspect brought by Oracle since its release 8i has been considered as a major improvement by the oracle data base developers and Administrators.

However, partitioning can make a system run many orders of magnitude slower when it is inappropriately applied. When a SQL statement accesses one or more partitioned tables, the Oracle optimizer attempts to use the information in the WHERE clause to eliminate some of the partitions from consideration during statement execution. This process, called partition pruning, speeds statement execution by ignoring partitions that cannot satisfy the statement’s WHERE clause. To do so, the optimizer uses information from the table definition with information from the statement’s WHERE clause.

In order for the oracle optimizer to make this type of decision, the WHERE clause must reference at least one column from the set of columns that comprise the partition key.

Hence, the partition type (range, hash, list or hash-range) design together with the partition key choice is the most important issue when you decide to partition your tables.

I am not going here to explain those different types of partitions largely documented in several excellent books as Practical Oracle 8i by Jonathan Lewis and Expert Oracle Data Base Architecture by Thomas Kyte. What I want to emphasize here is how to best partition, how to best choose the key partition and how to index using locally or globally partitioned index.

I would like to work by example. Let’s create a simple table called Mho_Arc_Mast described as:

Name             Type
 --------------- ---------
 Ide               NUMBER
 Dat_Part          DATE
 Nmfi_Ide          NUMBER
 Ptfl_ide          NUMBER

I would like to range partition this table using the DAT_PART column as the key partition.
I would like also to create 16 partitions for DAT_PART on a quarter time base:

P_MHO_20040331 for DAT_PART less than 2004-04-01
 P_MHO_20040631 for DAT_PART less than 2004-07-01
 P_MHO_20081231 for DAT_PART less than 2009-01-01

So, what have conducted me to choose this column as the key partition? This is the most fundamental question every one should ask when designing a table partition.

Do the DAT_PART means any thing in my business? Or will my application be using many queries involving WHERE CLAUSES such as:
If answers to the above question are YES then you got a nice candidate to the key partition column. However if answers are NO then maintaining this column as a key partition will be at least not useful and in the worst case disastrous.

Let’s considers the YES and the NO cases in order to see the differences between them. Consider, the YES case and examine the following select and its corresponding explain plan:

select mast.*
 from mho_arc_mast mast
 where mast.DAT_PART = SYSDATE;

Execution Plan
 SELECT STATEMENT Optimizer=CHOOSE (Cost=11 Card=2835 Bytes= 68040)
 2 1 TABLE ACCESS (FULL) OF 'MHO_ARC_MAST'(Cost=11 Card=2835 Bytes= 68040)

MHO_ARC_MAST table is range partitioned by DAT_PART. And there is no yet any index applied to it. This table contains 283467 rows.

You can point out that the optimizer is doing a single partition range.

In the NO case where the key DAT_PART do not figure in any where clause, the following select:

select mast.*

from mho_arc_mast mast
 where mast.nmfi_ide = 35689;

generates this kind of explain plan

Execution Plan
 SELECT STATEMENT Optimizer=CHOOSE (Cost=157 Card=100 Bytes=2400)
 2 1 TABLE ACCESS (FULL) OF 'MHO_ARC_MAST' (Cost=157 Card=100 Bytes=2400)

where the oracle optimiser chooses to do a Partition Range All, starting from partition 1 (Pstart 1) to partition 16 (Pstop 16).

When the key partition is used in the where query clauses then a partition pruning (partition elimination) will occur improving performance. When the key partition is not used in the where query clauses, then selects not using the key partition are candidate to a full scan all partitions.

Senior Oracle Developer interview I

Filed under: Oracle — hourim @ 12:12 pm

What are the most important skills a senior Oracle developer and a junior DBA must have? Can I hire this DBA/developer or not? Should I prefer to hire a high school graduate with 5 years of experience or a college graduate with 1 year of experience and an OCP (Oracle Certified Practice)? Those are kind of questions recruiters are faced to when they are in a process of hiring oracle consultant specialized in data base administrator and PLSQL developments.

Tom Kyte in his famous website emphasize that he considers people skills as the most important things he look for in a process of hiring. The ability to communicate, to keep an open mind and to realize that things change over time, he said, are at least as important as technical skills. How do we not agree with such assumption? This is a perfect first step hiring process.

The second step in the hiring process would be to test the candidate technical skills. Here below is a snapshot of questions that might serve to distinguish between a good, a bad or an indifferent candidate.
Question 1: Could you explain ORA-01555 rollback segment snapshot too old error?
If you understand the principle of oracle multi-versioning then you can easily explain ora-01555 error. Oracle multi-versioning is the ability of oracle to maintain simultaneously a multiple version of the same data. Let’s consider that and end user starts a query (q1) that selects tab.ides on table tab at time t1. At time t1+1 a transaction starts and updates tab.ides that are being selected by query q1. Suppose that the query q1 is still running and is still getting new tab.ides at time t1+1, what values of tab.ides query q1 will be retrieving? Values of tab.ides at time t1 or values of tab.ides at time t1+1?

The answer is that query q1 will be retrieving values of tab.ides at the time of the beginning of the query i.e t1. That is at time t1+1 oracle has two versions of the same data tab.ides values at time t1 and values at time t1+1. This is the multi-versioning process in oracle.

Then, what is the relation between multi-versioning and ora-01555 rollback segment snapshot too old error?

When query q1 starts oracle did not copy the content of this query in any place but instead when a modification occurs in data queried by query q1 oracle will preserve a copy of this data before the modification happen in a place called rollback segment. Oracle uses this rollback segment to reconstruct the read-consistent snapshot of the data. The data provided by query q1 is reconstructed from rollback segment and presented as it was when the query q1 began at time t1.

Consequently when you (or other session) are actively updating information you are reading through cursor or through sql query, oracle will be actively using its rollback segments in order to store those modifications aiming to provide you with a data read consistency. When oracle is not anymore able to restore a consistent data then you will receive the famous ORA-1555 rollback segment snapshot too old.

Question 2: What solutions you will advise in order to avoid ORA-01555 error?

In addition to what has been recommended here how to avoid ora-01555 you may also consider this
1. increase size of rollback segment
2  make your query run very quickly
3. make your transaction (or job) restartable so that when an ora-01555 error occurs you can re-run your job
4 schedule your job at time where there is less update activity on the data base.

More questions next time….

Senior Oracle developer interview II

Filed under: Oracle — hourim @ 12:08 pm

Question 3: Could you explain the difference between an empty collection and a not null collection object type?

Suppose we have the following object type definition

09:45:17 MHO> desc gsp.o_npk_stihis

Name           Null?              Type
 -------------- ----------------- -------- ----
 INDICEIP                         VARCHAR2(6)
 INDICEIC                         VARCHAR2(50)
 POSTINGQNV                       NUMBER
 MOVEMENTIDE                      NUMBER
 MOVEMENTTYPE                     VARCHAR2(6)
 TRADEDATE                        DATE
 BALANCEDATE                      DATE
 PORTFOLIOLABEL                   VARCHAR2(6)
 PORTFOLIOIDE                     VARCHAR2(50)
 COUNTERPARTIDE                   VARCHAR2(50)
 SECURITYTYPE                     VARCHAR2(3)
 NEWSOLDE                         NUMBER
 BALANCETYPE                      VARCHAR2(6)

to which we’ve attached a collection

09:45:26 MHO> desc gsp.col_npk_stihis
 gsp.col_npk_stihis TABLE OF GSP.O_NPK_STIHIS
 Name        Null?               Type
 ------------------------------- ------------

INDICEIP                        VARCHAR2(6)
 INDICEIC                        VARCHAR2(50)
 POSTINGQN                       NUMBER
 MOVEMENTIDE                     NUMBER
 MOVEMENTTYPE                    VARCHAR2(6)
 TRADEDATE                       DATE
 BALANCEDATE                     DATE
 PORTFOLIOLABEL                  VARCHAR2(6)
 PORTFOLIOIDE                    VARCHAR2(50)
 COUNTERPARTIDE                  VARCHAR2(50)
 SECURITYTYPE                    VARCHAR2(3)
 NEWSOLDE                        NUMBER
 BALANCETYPE                     VARCHAR2(6)

We would like to use them in a piece of PLSQL code which resemble to this:


v_npk_col_stihis Gsp.Col_Npk_Stihis;
 v_npk_stihis Gsp.O_Npk_Stihis;BEGIN

-- initialize object type collection
 v_npk_col_stihis := Gsp.Col_Npk_Stihis();

IF v_npk_col_stihis is null then
 dbms_output.put_line('collection is null');
 dbms_output.put_line('collection is not null');


Execute the above plsql code and you will see that the collection is not null. We can conclude that once a collection is initialized it becomes not null.

Since the collection is not null, then let’s get its last binary integer index. The above code is re-used with a very few modifications


v_npk_col_stihis Gsp.Col_Npk_Stihis;
 v_npk_stihis Gsp.O_Npk_Stihis;

-- initialize object type
 v_npk_col_stihis := Gsp.Col_Npk_Stihis();

IF v_npk_col_stihis is null then
 dbms_output.put_line('collection is null');
 dbms_output.put_line('collection is not null');

-- If collection is not null then let's get its elements
 j_last := v_npk_col_stihis.last;

IF j_last is null then
 dbms_output.put_line('Collection last index is null');
 dbms_output.put_line('Collection last index is not null');


Execute it and you will see that the collection is not null while its last index is null. This is what we call a not null but empty collection.

We have identified what is a not null but empty collection. What I want to emphasize here is that if we don’t clearly understood this difference, we will be certainly confronted, at execution time, to very strange errors that are not easily fixed. Let’s show this via a simple example.

The above piece of code is enriched as follows:


v_npk_col_stihis Gsp.Col_Npk_Stihis;
 v_npk_stihis Gsp.O_Npk_Stihis;
 v_indiceIp VARCHAR2(6);


-- initialize object type
 v_npk_col_stihis := Gsp.Col_Npk_Stihis();

IF v_npk_col_stihis is null then
 dbms_output.put_line('collection is null');
 dbms_output.put_line('collection is not null');

-- If collection is not null then let's get its elements
 j_last := v_npk_col_stihis.last;

IF j_last is null then
 dbms_output.put_line('Collection last index is null');
 dbms_output.put_line('Collection last index is not null');
 -- I suppose I have the index and I start using it
 v_indiceIp := v_npk_col_stihis(j_last).INDICEIP;
 dbms_output.put_line('Indice IP := '||v_indiceIp);



Execute it and you will get ORA-06502: PL/SQL: numeric or value error: NULL index table key value.
In order to avoid such a kind of error I often advise to precede any use of collection elements by the following IF statement:

IF v_npk_col_stihis is not null then
 IF v_npk_col_stihis.exists(1) THEN
 -- If collection is not null then let's get its elements
 j_last := v_npk_col_stihis.last;
 ..../... -- all your use of collection elements should be put here

Hence you will be protected against errors like those mentioned above. Of course collection.exists(1) has a sense only if the option collection.delete is not used. When this feature is used, gaps may exist in the collection and index (1) may also do not exist within a collection full of other binary indexes


Blog at

Tony's Oracle Tips

Tony Hasler's light hearted approach to learning about Oracle

Richard Foote's Oracle Blog

Focusing Specifically On Oracle Indexes, Database Administration and Some Great Music

Hatem Mahmoud Oracle's blog

Just another Oracle blog : Database topics and techniques

Mohamed Houri’s Oracle Notes

Qui se conçoit bien s’énonce clairement

Oracle Diagnostician

Performance troubleshooting as exact science

Raheel's Blog

Things I have learnt as Oracle DBA

Coskan's Approach to Oracle

What I learned about Oracle

So Many Oracle Manuals, So Little Time

“Books to the ceiling, Books to the sky, My pile of books is a mile high. How I love them! How I need them! I'll have a long beard by the time I read them”—Lobel, Arnold. Whiskers and Rhymes. William Morrow & Co, 1988.

Carlos Sierra's Tools and Tips

Tools and Tips for Oracle Performance and SQL Tuning

Oracle Scratchpad

Just another Oracle weblog


Dominic Brooks on Oracle Performance, Tuning, Data Quality & Sensible Design ... (Now with added Sets Appeal)