Home>Question Details



Thiruvaiyaru -- Thanks for the question regarding "Rollback Segment ", version 8.1.6

Submitted on 24-Jul-2001 10:47 Central time zone
Last updated 21-Nov-2007 9:23

You Asked

Tom,

I run a batch job to delete records from a table and I 
get the following error message :-

ERROR at line 1:
ORA-01555: snapshot too old: rollback segment number 1 with name "RBS01" too small
ORA-06512: at line 20

How can I find out the size of a rollback segment in the database,
and how can I increase the size of it online ?

Thanks in Advance
Sai

Tom,

On your question :-
Are you deleting in a cursor for loop with "commits to save space"??

Answer :-  Yes I am deleting in a cursor for loop with commits.

Thanks,
Sai
 

and we said...

Stop doing that.  Its the number one cause of this error. 

Search for 1555 on my site, you'll see many examples and the reasons for this error.

The #1 cause of 1555 is committing in a cursor for loop. You are causing it yourself. 

If you feel you truly must (and I am 100% of the opinion that you do not want to) commit, 
alter your logic from something like:


  for x in ( select rowid r from t where <some condition> )
  loop
      delete from t where rowid = x.r;
      cnt := cnt+1;
      if ( cnt = 1000 ) then
            commit;
            cnt := 0;
      end if;
  end loop;


into:

  loop
      delete from t where <some condition> AND rownum <= 1000;
      exit when sql%rowcount = 0;
      commit;
  end loop;
  commit;


followup to comment two below


The second loop keeps NO cursors open across commits.  That is why is avoids the 1555.  
It is a cursor opened against a table that you are modifying in a loop and you commit 
frequently that causes the 1555.

I said:

<quote>
The #1 cause of 1555 is committing in a cursor for loop. You are causing it yourself. 
</quote>

Not:

the #1 cause of 1555 is commiting in a loop.

It is when you comitt across fetches that you do this to yourself.



followup to comment three

Yours is a different issue.  Yous is the issue that:

"The probability of getting an ORA-1555 with your Query is directly proportional to the 
size of your SMALLEST rollback segment"


I really dislike the "have a big rollback segment" approach.  I am a firm believe that 
all rollback segments should be created equal -- they should all be the same size.

You see -- the ORA-1555 you are getting is against the table with 2million records.  You 
have other transactions modifying that table while you are reading it.  They are 
modifying and commiting their changes.  Lets say that at the BEGINNING of your run, some 
process updates the "last row" in the 2million row table and committs.  Their rollback 
entry is free to be reused now if that rollback segment they put their UNDO in wraps 
around.  You go about processing the table and eventually get to that last row.  You need 
to do a consistent read on it -- you need their UNDO.  Unfortunately, their UNDO went 
into a small rollback segment that wrapped a couple of times already.  The UNDO you need 
is long gone, you get the ORA-1555.

For you, what you need to do, is to ensure that you have sufficient rollback 
pre-allocated in ALL rollback segments so as these rollback segments do NOT get 
overwritten during the course of your longest process.

In 9i, this might be a little easier to deal with as you can set an undo rentention 
period (however, you must be prepared to have the disk available to support it!)

My book goes into the ORA-1555 in some detail with examples showing how and when you will 
hit it as well.
 

Reviews    
4 stars   July 26, 2001 - 2am Central time zone
Reviewer: A reader from Switzerland / Zuerich


2 stars COMMITs and ORA-01555 errors   July 26, 2001 - 5pm Central time zone
Reviewer: Logo Palanisamy from Santa Clara, USA
Tom,

I understand that ORA-1555 are caused mainly by the commits in a loop. But how is the "loop .. exit 
when .. end loop" different from the "cursor for loop" as far preventing ORA-1555 error. Both of 
them commit after every 1000 records. 

Won't the "loop .. exit when ..commit end loop" also create the same ORA-1555 error? 


4 stars LOOP ...................... END LOOP   July 27, 2001 - 2am Central time zone
Reviewer: Bhawna R from India
I understand the basic problem with the cursor for loop of the example, this has to do with 
refering to the same table for LOOPING condition which is getting updated within the LOOP. But, we 
have a job where a cursor is declared for selecting records from table X within DECLARE section. 
And, in the procedure body, there is a LOOP.....END LOOP, where the processing is done. Records are 
fetched from the cursor, some records are inserted in 4-5 tables, andrecords are deleted from 30-35 
tables (including X). This job takes around 1 hour plus to complete, and sometimes it gives 
ORA-1555. We have used SET TRANSACTION to use BIG_ROLLBACK segment. There is COMMIT at the end of 
this (within LOOP), as otherwise it would give rise to UNABLE TO EXTEND ROLLBACK SEGMENT. This is 
actually a purging job and it runs everyday once. Now, we need to add 10 more tables to it, as a 
few more modules have been added. Could you advice us how to handle this situation? The main table 
(cursor table) has some 2 million records. 


4 stars New Idea   July 30, 2001 - 2am Central time zone
Reviewer: Pramodu from U.A.E, Middle East
Dear Tom
I was getting this error message, now i can solve my problem

Thanks 


4 stars Tricks   July 31, 2001 - 12am Central time zone
Reviewer: Anthony Lai Cheuk Tung from Hong Kong SAR
Thank you , Tom, it is a nice trick that we always ignore . May be, apart from looking into your 
Wrox book, as a DBA or developer, we are required to log down our knowledge and share with others. 
If this forum can be searched by catalogs, it is excellent. 

Work hard , Tom! I have to learn from you and myself as well as from all of Oracle fans.

Anthony
 


2 stars   August 2, 2001 - 9am Central time zone
Reviewer: A reader 


4 stars what about UNDOTBS in oracle 9i   September 29, 2002 - 6am Central time zone
Reviewer: Irfan from Kuwait
Hi Tom, 

I am using UNDO tablespace in oracle 9i with undo_management=Auto; 
How does it control rollback segment? Does system controls the size of rollback segments ?

I tried to insert 95000 records in a table in oracle 9i with default undo_retention. I am still 
getting ora-1555 and ora-6512. By the way I am doing commit in cursor for loop. What should I do to 
resove this error ? should I increase undo_retention value or use commit outside the loop?

Thanks
 


Followup   September 29, 2002 - 8am Central time zone:

Yes, the entire purpose of AUTO is to have Oracle

o decide how many (we'll create new rbs's in this undo tablespace as we need)
o decide how big (based on your retention period)

If you are getting ora-1555, you set the undo retention TOO small -- it needs to be set for longer 
then your longest running query to avoid the 1555.


(but YES, YES YES you should commit OUTSIDE THE CURSOR FOR LOOP)!!!!!

The "theory" behind committing inside the cursor for loop goes like this "it'll save on the amount 
of rollback segment space I need".  Hopefully you can see how woefully wrong this is.  YOU NEED 
that undo in order for your query to proceed.  Yet, when you commit, you released that undo for 
subsequent reuse -- which since the undo retention period is small -- WE DID.  Hence, when you 
increase the undo retention, you will increase the amount of undo we save, which means all your 
commits in the cursor for loop are doing for you are precisely:

o making you run slower
o generating more resources
o removing data integrity from your database


Thats all those frequent commits are accomplishing!!!! 

4 stars followup   September 29, 2002 - 2pm Central time zone
Reviewer: Irfan from Kuwait
In your eg you select the rowid from table t and then use that rowid to delete data from table same 
table t.
But in our case :
We select from table x and insert into table y;
eg

DECLARE
CURSOR C1 IS
   SELECT * FROM PGIT_POLICY
   WHERE  POL_APPR_STS = 'A'
   AND    POL_CLASS_CODE = '001'
   AND    POL_SEG_03 = '02'
   AND    TO_CHAR(POL_ISSUE_DT,'YYYY') = '2000';

BEGIN

FOR C1REC IN C1
LOOP
INSERT INTO PGITH_POLICY (POLH_SYS_ID)
SELECT
POL_SYS_ID
FROM PGIT_POLICY 
WHERE POL_SYS_ID = C1REC.POL_SYS_ID;

INSERT INTO PGITH_POL_ADDL_INFO (PAIH_SYS_ID)
SELECT
PAC_SYS_ID
FROM  PGIT_POL_APPL_CURR       
WHERE PAC_POL_SYS_ID   = C1REC.POL_SYS_ID  ;

like this there are another 8 tables. 

COMMIT;
END LOOP;
END;

So here our tables from where we select is different and table where we insert is different. Do u 
still think putting COMMIT in this kind of FOR LOOP is wrong and it will generate ora - 1555. 


Followup   September 29, 2002 - 3pm Central time zone:

yes.  see

http://asktom.oracle.com/pls/asktom/f?p=100:11:::::P11_QUESTION_ID:895410916429
for example -- there I query a read only tablespace (read only) and generate the 1555 all by myself 
by committing in the cursor for loop.

Only commit in the cursor for loop if:

a) you want to waste resources (generate more redo, waste cpu cycles)
b) you want to run slower
c) you want to lose data integrity


If any of those bother you -- don't commit in the cursor for loop!

 

3 stars OK   June 30, 2004 - 9am Central time zone
Reviewer: Raju from Hyderabad,India
Hi Tom,
If I insert some rows into a table,What will be the Undo 
generated for the inserted rows?Will it be Delete entries for
the inserted rows or previous memory address of the table's
data blocks which existed prior to row inserts.Is there any way to check that?
Please do reply.
Bye!
 


Followup   June 30, 2004 - 10am Central time zone:

if you insert rows, undo will consist of "delete this rowid".

 

3 stars ORA-01555: snapshot too old: rollback segment   November 7, 2007 - 5pm Central time zone
Reviewer: Anne from MN,USA
Hi Tom,

I have a materialized view (bps_mv) created as :
CREATE MATERIALIZED VIEW BPS_MV 
TABLESPACE BPS_DATA
PCTUSED    40
PCTFREE    10
INITRANS   2
MAXTRANS   255
STORAGE    (
            INITIAL          64K
            MINEXTENTS       1
            MAXEXTENTS       2147483645
            PCTINCREASE      0
            FREELISTS        1
            FREELIST GROUPS  1
            BUFFER_POOL      DEFAULT
           )
NOCACHE
LOGGING
NOPARALLEL
BUILD IMMEDIATE
USING INDEX TABLESPACE BPS_INDEX
REFRESH COMPLETE   ON DEMAND   WITH PRIMARY KEY  USING DEFAULT LOCAL ROLLBACK SEGMENT 
AS
SELECT 
   ......
   .....
FROM lbr_vw@remote 
where ...
;


select count(*) from BPS_MV;
COUNT(*)
----------
  60445

I refresh this bps_mv once a month as :
begin
 dbms_mview.refresh('BPS_MV', 'c');
 ommit;
end;
/


The first time it refreshes it errors out and if I run the same piece of code right away the MV refreshes fine.

The error is :
ORA-12008: error in materialized view refresh path
ORA-12801: error signaled in parallel query server P016
ORA-01555: snapshot too old: rollback segment number 29 with name "_SYSSMU29$" too small
ORA-02063: preceding 2 lines from BPS_IAW
ORA-06512: at "SYS.DBMS_SNAPSHOT", line 794
ORA-06512: at "SYS.DBMS_SNAPSHOT", line 851
ORA-06512: at "SYS.DBMS_SNAPSHOT", line 832
ORA-06512: at line 2


Since I have created it to use "default local rollback" : I am not sure what it is using. Could you please help.

Thanks so much.

Followup   November 7, 2007 - 6pm Central time zone:

queries (read bits) use rollback, queries get 1555

where you generate your rollback - meaningless

where the rollback exists that your QUERY needs to complete - priceless.

Your select is getting this, not the "insert" bit. You have insufficient undo to exist and not wrap around during the time it takes your query to execute, you need more total undo (on that database that is doing the SELECT)
3 stars ORA-1555   November 8, 2007 - 9am Central time zone
Reviewer: Anne from MN,USA
Thanks Tom!.

Just want to make sure I understand this correct : "Your select is getting this, not the "insert" 
bit" -  From the tkprof, I see that the  BPS_MV refresh does a truncate + insert /*APPEND*/. 
So the "select" is the select query inside the bps_mv, right ?

The rollback for the insert (part of the refresh) exists on the local database, right ?

How about the rollback for the query in the mv - the mv resides on local database, but query is 
from table@remote, so does the rollback for the query exist on the remote db ?

As always, you help is so valuable! Thank you.


Followup   November 9, 2007 - 11am Central time zone:

reads are the things that get 1555

so yes, the select of the insert as select.

and the rollback it needs is on the remote site. The query that is running needs to see all of the blocks it queries as of the point in time it began (consistent read). It needs UNDO from the remote site to perform that magic.
4 stars ORA-1555   November 13, 2007 - 1pm Central time zone
Reviewer: Anne from MN, USA
Thanks so much Tom - I understand now. And thank you so much for your patience in assisting me... You have been of tremendous help to me! (Sometimes I hesitate to ask for fear of asking "silly" questions, but I figure, it is better to ask, than not have a "solid basis" for my reasoning...) So, please bear with me. :)

I have couple more questions in relation to this :
1. Since bps_mv is using "DEFAULT" rollback on the remote site, does that mean that it is using whatever rollback segment it happens to be using on the remote site ?

2. The first time bps_mv refreshes (complete refresh), it errors out with the ORA-1555 and if I run the same piece of code right away the MV refreshes fine. Would you be able to help me understand why it works fine the 2nd time?
Code for the refresh :
begin
 dbms_mview.refresh('BPS_MV', 'c');
 commit;
end;
/



3. To solve the ORA-1555 problem, the query for the mv needs more UNDO from the remote site. The remote site is a Statewide system where I have only read access to certain tables. Would you have any suggestion as to "how" I can get rid of this ORA-1555 problem on my side, since I cannot do anything on remote?

Just a little background on what bps_mv does : It does a complete refresh once a month and gets project, employess and hours from 30-OCT-2005 onwards from lbr_vw@remote.

There is a program then, that takes the hours for the previous month from bps_mv, calculates billable amounts from billable hours of projects, and then creates Invoices.

I appreciate your help Tom! Thank you!


Followup   November 16, 2007 - 2pm Central time zone:

1) the query will use potentially ALL rollback segments on the remote site to undo the changes.

Let us say you have a 5 block table, right now the status is:

block 1 is modified by uncommitted transaction T1 using rbs1
block 2 is modified by uncommitted transaction T2 using rbs2
....
block 5 is modified by uncommitted transaction T5 using rbs5


If you were to do a select * from that_table, you would read block 1, find it has uncommitted stuff on it (you cannot see that stuff), so you go to rbs1, find the undo and undo that change - that is the version of block 1 for you. Then you do the same for block 2 - but block 2's undo is in rbs2. And so on.

You will end up reading 5 blocks from the table and 1 block from EACH of the 5 rollback segments to process that query.


2) sounds like delayed block cleanout.
http://asktom.oracle.com/pls/ask/search?p_string=delayed+block+cleanout


3) the best way would be to make the refresh "faster" - any chance of an incremental refresh? Instead of repulling all of the data you pulled last time PLUS lots of new stuff?
5 stars Very interesting!   November 16, 2007 - 6pm Central time zone
Reviewer: Anne from MN, USA
Thank you so much, Tom - this is great insight!

As far as an "incremental" refresh, I tried creating the mv "refresh fast on demand" and I got ORA-12015
12015, 00000, "cannot create a fast refresh materialized view from a complex query"
// *Cause: Neither ROWIDs and nor primary key constraints are supported for//      complex queries.
// *Action: Reissue the command with the REFRESH FORCE or REFRESH COMPLETE option or create a simple materialized view.

So, it looks like I have to use complete refresh, right ?

I have another suggestion though that may help, and if you could provide some guidance on whether or not it will help, I would greatly appreciate it.

Basically I'm creating a table which will have ALL the rows, the mv will have only the "newer" rows and then when the mv is refreshed, it will follow an insert into the table from the mv.
1. create table bps_hours as select * from bps_mv;

2. drop bps_mv;

3. create materialized view bps_mv
.....
REFRESH COMPLETE   ON DEMAND   with ROWID  USING DEFAULT LOCAL ROLLBACK SEGMENT 
AS
SELECT ....
  FROM lbr_vw@remote 
where NVL(pay_end_dt,sysdate) > add_months(sysdate, -15) -- pay_end_dates up to the previous 15 
months
and (<fld1, fld2, fld3) not in 
         (select/*+ HASH_AJ */  fld1, fld2,fld3           
      --basically pk combo
            from bps_hours
           where pay_end_dt > add_months(sysdate, -15)
             and pay_end_dt is not null
           )
;

4. Refresh of mv will follow insert into the bps_hours table.
begin
 dbms_mview.refresh('BPS_MV', 'c');
 --Refresh table from snapshot
     insert into bps_hours
       select *
         from bps_mv
       where pay_end_dt >  add_months(sysdate, -15) 
        and (<fld1, fld2, fld3) not in 
            (select/*+ HASH_AJ */  fld1, fld2,fld3          
      --basically pk combo
            from bps_hours
           where pay_end_dt > add_months(sysdate, -15)
             and pay_end_dt is not null
           )


I appreciate your thoughts on this. Once again, thank you so much.

Followup   November 21, 2007 - 11am Central time zone:

lose hints, lose all hints.


especially deprecated hints.

explain your logic a bit better here. Why the subquery - if you want


... It does a complete refresh once a month and gets project, employess and hours from 30-OCT-2005 onwards from lbr_vw@remote.
....


that would just be a simple MV, no subqueries or anything.
2 stars Rollback too small   November 28, 2007 - 12am Central time zone
Reviewer: Anne from MN, USA
Yes Tom, that is exactly what I had at first "just a simple MV, no subqueries or anything."

But then I am getting the ORA-1555 error  rollback segment too small, on complete refresh 

That's why I came up with the idea of creating the mv with rows that are not in the local table, 
and then upon refresh of mv, do an insert into the local table from the mv.  So the local table 
will always have the entire data from OCT-2005 onwards, and the mv will be refreshing for just the 
newer records. I am hoping that this may get rid of the rollback segment too small error on refresh 
of mv. 

I would appreciate your thoughts. Thanks so much.



Write a Review
 


All information and materials provided here are provided "as-is"; Oracle disclaims all express and implied warranties, including, the implied warranties of merchantability or fitness for a particular use. Oracle shall not be liable for any damages, including, direct, indirect, incidental, special or consequential damages for loss of profits, revenue, data or data use, incurred by you or any third party in connection with the use of this information or these materials.

About Oracle | Legal Notices and Terms of Use | Privacy Statement