ORA-01555: "Snapshot Too Old" - Overview: 1. Fewer and Smaller Rollback Segments For A Very Actively Changing Database
ORA-01555: "Snapshot Too Old" - Overview: 1. Fewer and Smaller Rollback Segments For A Very Actively Changing Database
There are various reasons why customers can get the error ORA-01555. Sometimes it is due to rollback
segments being too small in size, but there are other reasons. This bulletin is an attempt to give a
complete summary of all the situations which would cause an ORA-01555 error and how to resolve them.
In order to understand the bulletin, one needs to understand some of the internal mechanisms of Oracle,
so we start by explaining briefly about read consistency and block cleanouts.
Oracle always enforces statement-level read consistency. This guarantees that the data returned by a
single query is consistent with respect to time when the query began. Therefore, a query never sees the
data-changes made by transactions that commit during the course of execution of the query.
Oracle uniquely identifies any given point in time by a set of numbers called the System Change Numbers
(SCN). So SCN can be defined as the state of the database at any one given point in time. To produce
read-consistency, Oracle marks the current SCN as the query enters the execution phase. The query can
only see the snapshot of the records as they were at the time of marked SCN.
Oracle uses rollback segments to reconstruct the read-consistent snapshot of the data. Whenever a
transaction makes any changes, a snapshot of the record before the changes were made is copied to a
rollback segment and the data block header is marked appropriately with the address of the rollback
segment block where the changes are recorded. The data block also maintains the SCN of the last
committed change to the block.
As the data blocks are read on behalf of the query, only blocks with lower SCN than the query SCN will
be read. If a block has uncommitted changes of other transactions or changed data with more recent
SCN, then the data is reconstructed using the saved snapshot from the rollback segments. In some rare
situations, if RDBMS is not able to reconstruct the snapshot for a long running query, the query results in
an ORA-01555 error.
A rollback segment maintains the snapshot of the changed data as long as the transaction is still active
(commit or rollback has not been issued). Once a transaction is committed, RDBMS marks it with current
SCN and the space used by the snapshot becomes available for reuse.
Therefore, ORA-01555 will result if the query is looking for the snapshot which is so old that rollback
segment information could not be found because of wrap around or overwrite.
1. Fewer and smaller rollback segments for a very actively changing database
If the database has many transactions changing data and commiting very often, then the chance of
reusing the space used by a committed transaction is higher. A long running query then may not be able
to reconstruct the snapshot due to wrap around and overwrite in rollback segments. Larger rollback
segments in this case will reduce the chance of reusing the committed transaction slots.
If the rollback segment is corrupted and could not be read, then a statement needing to reconstruct a
before image snapshot will result in the error.
This is the situation when a query opens a cursor, then loops through fetching, changing, and committing
the records on the same table. In this scenerio, very often an ORA-01555 can result. Let's take the
following example to explain this:
A cursor was opened at SCN=10. The execution SCN of the query is then marked as SCN=10. Every
fetch by that cursor now needs to get the read-consistent data from SCN=10. The user program is now
fetching x numbers of records, changing them, and committing them. Let's say they were committed with
SCN=20. If a later fetch happens to retrieve a record which is in one of the previously committed blocks,
then the fetch will see that the SCN there as 20. Since the fetch has to get the snapshot from SCN=10 it
will try to find it in the rollback segments. If it could rollback sufficiently backwards as previously
explained, then it could reconstruct the snapshot from SCN=10. If not, then it will result in an ORA-01555
error.
Committing less often which will result in larger rollback segments will REDUCE the probability of getting
'snapshot too old' error.
To complicate things, now we see how delayed block clean outs play an important role in getting this
error.
When a data or index block is modified in the database and the transaction committed, Oracle does a fast
commit by marking the transaction as committed in the rollback segment header but does not clean the
datablocks that were modified. The next transaction which does a select on the modified blocks will do
the actual cleanout of the block. This is known as a delayed block cleanout.
Now, take the same scenario as described in previous section. But instead of assuming one table, let us
assume that there are two tables in question. i.e: the cursor is opened and then in a loop, it fetches from
one table and changes records in another, and commits. Even though the records are getting committed
in another table it could still cause ORA-01555 because cleanout has not been done on the table from
which the records are being fetched.
For this case, a full table scan before opening and fetching through the cursor will help.
Summary:
Fetches across commits as explained in the last two cases are not supported by ANSI standard.
According to ANSI standard a cursor is invalidated when a commit is performed and should be closed and
reopened. Oracle allows users to do fetch across commits but users should be aware that it might result
in ORA-01555.
ORA-01555 "Snapshot too old" - Detailed Explanation
Terminology
Two key concepts are briefly covered below which help in the understanding of ORA-01555, Read
Consistency and Delayed Block Cleanout.
1. Read Consistency
This is documented in the Oracle Database Concepts manual and so will not be discussed further.
However, for the purposes of this article this should be read and understood if not understood already.
Oracle Server has the ability to have multi-version read consistency which is invaluable to you because it
guarantees that you are seeing a consistent view of the data (no 'dirty reads').
This is best illustrated with an example: Consider a transaction that updates a million row table. This
obviously visits a large number of database blocks to make the change to the data. When the user
commits the transaction Oracle does NOT go back and revisit these blocks to make the change
permanent. It is left for the next transaction that visits any block affected by the update to 'tidy up' the
block (hence the term 'delayed block cleanout').
Whenever Oracle changes a database block (index, table, cluster) it stores a pointer in the header of the
data block which identifies the rollback segment used to hold the rollback information for the changes
made by the transaction. (This is required if the user later elects to not commit the changes and wishes to
'undo' the changes made.)
Upon commit, the database simply marks the relevant rollback segment header entry as committed. Now,
when one of the changed blocks is revisited Oracle examines the header of the data block which
indicates that it has been changed at some point. The database needs to confirm whether the change has
been committed or whether it is currently uncommitted. To do this, Oracle determines the rollback
segment used for the previous transaction (from the block's header) and then determines whether the
rollback header indicates whether it has been committed or not.
If it is found that the block is committed then the header of the data block is updated so that subsequent
accesses to the block do not incur this processing.
This behaviour is illustrated in a very simplified way below. Here we walk through the stages involved in
updating a data block.
Description: This is the starting point. At the top of the data block we have an area used to link active
transactions to a rollback segment (the 'tx' part), and the rollback segment header has a table that stores
information upon all the latest transactions that have used that rollback segment.
In our example, we have two active transaction slots (01 and 02) and the next free slot is slot 03. (Since
we are free to overwrite committed transactions.)
Stage 2 - Row 2 is Updated
Description: We have now updated row 2 of block 500. Note that the data block header is updated to
point to the rollback segment 5, transaction slot 3 (5.3) and that it is marked uncommitted (Active).
Description: Next the user hits commit. Note that all that this does is it updates the rollback segment
header's corresponding transaction slot as committed. It does *nothing* to the data block.
Description: Some time later another user (or the same user) revisits data block 500. We can see that
there is an uncommitted change in the data block according to the data block's header.
Oracle then uses the data block header to look up the corresponding rollback segment transaction table
slot, sees that it has been committed, and changes data block 500 to reflect the true state of the
datablock. (i.e. it performs delayed cleanout).
ORA-01555 Explanation
There are two fundamental causes of the error ORA-01555 that are a result of Oracle trying to attain a
'read consistent' image. These are:
The rollback information itself is overwritten so that Oracle is unable to rollback the (committed)
transaction entries to attain a sufficiently old enough version of the block.
The transaction slot in the rollback segment's transaction table (stored in the rollback segment's
header) is overwritten, and Oracle cannot rollback the transaction header sufficiently to derive the
original rollback segment transaction slot.
Both of these situations are discussed below with the series of steps that cause the ORA-01555. In the
steps, reference is made to 'QENV'. 'QENV' is short for 'Query Environment', which can be thought of as
the environment that existed when a query is first started and to which Oracle is trying to attain a read
consistent image. Associated with this environment is the SCN (System Change Number) at that time and
hence, QENV 50 is the query environment with SCN 50.
This breaks down into two cases: another session overwriting the rollback that the current session
requires or the case where the current session overwrites the rollback information that it requires. The
latter is discussed in this article because this is usually the harder one to understand.
Now, Oracle can see from the block's header that it has been changed and it is later than the required
QENV (which was 50). Therefore we need to get an image of the block as of this QENV.
If an old enough version of the block can be found in the buffer cache then we will use this, otherwise we
need to rollback the current block to generate another version of the block as at the required QENV.
It is under this condition that Oracle may not be able to get the required rollback information because
Session 1's changes have generated rollback information that has overwritten it and returns the ORA-
1555 error.
Next Oracle attempts to lookup the rollback segment header's transaction slot pointed to by the top of the
data block. It then realises that this has been overwritten and attempts to rollback the changes made to
the rollback segment header to get the original transaction slot entry.
If it cannot rollback the rollback segment transaction table sufficiently it will return ORA-1555 since Oracle
can no longer derive the required version of the data block.
It is also possible to encounter a variant of the transaction slot being overwritten when using block
cleanout. This is briefly described below:
Session 1 starts a query at QENV 50. After this another process updates the blocks that Session 1 will
require. When Session 1 encounters these blocks it determines that the blocks have changed and have
not yet been cleaned out (via delayed block cleanout). Session 1 must determine whether the rows in the
block existed at QENV 50, were subsequently changed.
In order to do this, Oracle must look at the relevant rollback segment transaction table slot to determine
the committed SCN. If this SCN is after the QENV then Oracle must try to construct an older version of
the block and if it is before then the block just needs clean out to be good enough for the QENV.
If the transaction slot has been overwritten and the transaction table cannot be rolled back to a sufficiently
old enough version then Oracle cannot derive the block image and will return ORA-1555.
Note: Normally Oracle can use an algorithm for determining a block's SCN during block cleanout even
when the rollback segment slot has been overwritten. But in this case Oracle cannot guarantee that the
version of the block has not changed since the start of the query.
Solutions
This section lists some of the solutions that can be used to avoid the ORA-01555 problems discussed in
this article. It addresses the cases where rollback segment information is overwritten by the same session
and when the rollback segment transaction table entry is overwritten.
It is worth highlighting that if a single session experiences the ORA-01555 and it is not one of the special
cases listed at the end of this article, then the session must be using an Oracle extension whereby
fetches across commits are tolerated. This does not follow the ANSI model and in the rare cases where
ORA-01555 is returned one of the solutions below must be used.
1. Use any of the methods outlined above except for '6'. This will allow transactions to spread their
work across multiple rollback segments therefore reducing the likelihood or rollback segment
transaction table slots being consumed.
2. If it is suspected that the block cleanout variant is the cause, then force block cleanout to occur
prior to the transaction that returns the ORA-1555. This can be achieved by issuing the following
in SQL*Plus, SQL*DBA or Server Manager :
If indexes are being accessed then the problem may be an index block and clean out can be forced by
ensuring that all the index is traversed. Eg, if the index is on a numeric column with a minimum value of
25 then the following query will force cleanout of the index:
Examples
Listed below are some PL/SQL examples that can be used to illustrate the ORA-1555 cases given above.
Before these PL/SQL examples will return this error the database must be configured as follows:
Rollback Overwritten
Special Cases
There are other special cases that may result in an ORA-01555. These are given below but are rare and
so not discussed in this article:
Summary
This article has discussed the reasons behind the error ORA-01555 "Snapshot too old", has provided a
list of possible methods to avoid the error when it is encountered, and has provided simple PL/SQL
scripts that illustrate the cases discussed.