Home › Database › ORA-01555 Snapshot Too Old — Undo Retention Fix
Advanced 5 min · September 23, 2026

ORA-01555 Snapshot Too Old — Undo Retention Fix

Fix Oracle ORA-01555 by sizing UNDO_RETENTION, auto-extending undo, and stopping commits inside fetch loops.

N
Naren Founder & Principal Engineer

20+ years shipping high-throughput database systems. Notes here come from systems that actually shipped.

Follow
✓ Production
production tested
September 23, 2026
last updated
1,942
articles · all by Naren
Before you start⏱ 12 min
  • ✓An Oracle database (11g+) with v$undostat access
  • ✓A long-running query or report that hits 01555
  • ✓DBA cooperation for retention and tablespace changes
 ● Production Incident 🔎 Debug Guide
⚡Quick Answer
  • ORA-01555 means your long-running query needed an old row version that undo no longer holds — writers overwrote it after UNDO_RETENTION seconds (default 900) expired
  • Size the fix from v$undostat: set UNDO_RETENTION above your longest query's runtime, auto-extend the undo tablespace, and consider RETENTION GUARANTEE for critical reports
  • Never COMMIT inside a fetch loop: it releases your snapshot position and invites fetch-across-commit failures on top of the retention pressure
  • When retention can't cover the workload, redesign instead — shorter queries, fewer full scans, and writers that commit sanely beat infinite undo growth
✦ Definition~90s read
What is ORA-01555 Snapshot Too Old Fix?

ORA-01555 is raised when a query needs a read-consistent version of a block that undo no longer contains. Every query runs as of its start SCN; blocks changed after that SCN must be rolled back in memory using undo records. Undo space is finite and ring-reused: once a transaction's undo passes UNDO_RETENTION seconds (default 900) and the space is needed, writers overwrite it.

★
Picture reading a long newspaper in a library that recycles old editions.

A reader arriving later finds its history gone and fails — the alternative would be silently wrong results, so Oracle fails loud.

Four patterns trigger it. Long query vs hot writers: a 6-hour full scan over tables that batch jobs update heavily — retention can't span the gap. Fetch-across-commit: code that commits inside its own cursor loop, releasing and re-establishing position while the underlying rows move (often surfacing as 01555 or fetch-out-of-sequence).

Delayed block cleanout: full scans touching masses of blocks with uncleaned transaction state, each needing undo for cleanout checks. Small undo: a starved tablespace (no autoextend, tiny datafiles) that recycles aggressively regardless of retention.

The durable answer pairs storage with design. UNDO_RETENTION above the longest query's runtime, an auto-extending undo tablespace, and RETENTION GUARANTEE where reports are sacred cover the storage side. Shorter queries, indexed access over full scans, and writers that neither hold nor spew commits pathologically cover the design side. v$undostat arbitrates: maxquerylen tells you what retention reality demands.

Plain-English First

Picture reading a long newspaper in a library that recycles old editions. Your query is on page 40 while staff pulps editions older than 15 minutes (UNDO_RETENTION 900). ORA-01555 is reaching page 41 and finding it pulped — writers overwrote the version you needed. The fixes match the metaphor: keep editions longer (retention), build a bigger archive room (undo tablespace), stop handing your copy back mid-read (commits in fetch loops), or read faster than the pulping schedule (shorter queries).

ORA-01555: snapshot too old: rollback segment number 12 with name "_SYSSMU12" too small. It kills the long ones — the 6-hour analytics rollup, the full-export select, the month-end reconciliation that scans everything. Short queries never see it; marathon readers meet it at 3 AM when the report dies at 94% complete after hours of work.

Oracle promises every query a consistent snapshot as of its start (SCN), reconstructed from undo. That promise holds only while undo survives: concurrent writers overwrite old versions as soon as they pass UNDO_RETENTION, and a query still reading them fails loudly instead of returning wrong data.

This guide covers both sides of the race: sizing retention and undo storage from v$undostat, ending fetch-loop commits, calming hot-block churn, doing the retention math for your longest query, and redesigning reads that no retention setting can cover. Every section pairs the storage fix with the design fix, because error 01555 always has one foot in each world.

Read Consistency in 90 Seconds

Every Oracle query sees the database as of one instant — its start SCN. Blocks changed after that instant get rolled back in memory using undo, so the query observes a frozen past while writers march on. This is read consistency: no locks on readers, no dirty reads, results that make sense as of a moment. Undo is the time machine, and like all time machines it has fuel limits.

The fuel gauge has three dials. UNDO_RETENTION (seconds, default 900) is the requested history depth — how long expired undo should survive before reuse. The undo tablespace size plus autoextend is the physical room: retention is a wish without space to honor it. RETENTION GUARANTEE (per tablespace) turns the wish into a promise — at the cost of failing writers (ORA-30036) when space runs out instead of recycling readers' history.

Check all three before theorizing: SHOW PARAMETER undo_retention, dba_tablespaces retention column, dba_data_files autoextend flags. Most 01555 scenes show the same tableau — 900 seconds, fixed-size files, no guarantee — against queries measured in hours. The gap between the dials and the workload is the entire diagnosis. Write the three values into the ticket before theorizing further.

undo_baseline.sqlSQL
1
2
3
4
5
6
7
8
9
10
-- The three dials: requested retention, guarantee, physical room
SHOW PARAMETER undo_retention;
SHOW PARAMETER undo_tablespace;
SELECT tablespace_name, retention FROM dba_tablespaces
WHERE contents = 'UNDO';
SELECT file_name, ROUND(bytes/1024/1024) AS mb,
  autoextensible, ROUND(maxbytes/1024/1024) AS max_mb
FROM dba_data_files
WHERE tablespace_name = (SELECT value FROM v$parameter
  WHERE name = 'undo_tablespace');
📊 Production Insight
A 900-second retention against a 6-hour query is a 24× gap — visible in one v$parameter read, yet the team rebuilt undo twice before checking the dials.
🎯 Key Takeaway
Read consistency runs on undo fuel: check retention setting, guarantee, and tablespace room before any other theory.

UNDO_RETENTION and the Undo Tablespace

UNDO_RETENTION is a target the space manager honors when room allows: expired undo older than retention gets reused only under space pressure, and auto-tuned retention (tuned_undoretention in v$undostat) stretches beyond your setting when space permits. The setting is therefore a floor for requests, not a promise — the promise comes from space plus RETENTION GUARANTEE. Raising retention without adding space is wishing louder, not fueling further.

Size both sides together. Set UNDO_RETENTION above your longest query plus margin (20%), enable AUTOEXTEND on undo datafiles with a sane MAXBYTES cap, and add datafiles until the tablespace holds retention-seconds × peak-undo-rate. For sacred reports, ALTER TABLESPACE ... RETENTION GUARANTEE converts recycling into writer backpressure — monitor for ORA-30036 afterward, because guarantee trades reader failures for writer failures when sizing is short.

Apply online and verify from history, not hope: ALTER SYSTEM SET undo_retention=21600 SCOPE=BOTH takes effect immediately, and v$undostat over the next cycle shows whether tuned retention actually reaches the workload's maxquerylen. If tuned retention flatlines below your setting, space — not configuration — is the binding constraint. Add room.

size_undo.sqlSQL
1
2
3
4
5
6
7
8
9
10
11
12
-- What retention does reality demand? (seconds)
SELECT MAX(maxquerylen) AS longest_query_s,
  MAX(tuned_undoretention) AS tuned_s
FROM v$undostat;

-- Raise the floor + grow the room (online)
ALTER SYSTEM SET undo_retention = 21600 SCOPE = BOTH;
ALTER DATABASE DATAFILE '/u01/oradata/undotbs01.dbf'
  AUTOEXTEND ON NEXT 1G MAXSIZE 120G;

-- Promise retention for sacred reports (watch for ORA-30036)
ALTER TABLESPACE undotbs1 RETENTION GUARANTEE;
📊 Production Insight
Retention raised to 21600 with 40 GB autoextend took tuned retention past the 6-hour demand in one cycle — the next rollup completed without a retry.
🎯 Key Takeaway
Retention is a floor honored only with space: set above longest-query-plus-margin, autoextend, and guarantee selectively.

Commits Inside Fetch Loops

The classic self-inflicted 01555: a PL/SQL loop that FETCHes a row, processes it, COMMITS, and repeats. Each COMMIT ends the transaction and releases the cursor's snapshot anchor; the next FETCH re-establishes position against data that moved on — and against undo that may already be gone. The loop manufactures the exact inconsistency it then dies from, usually reported as snapshot-too-old or fetch-out-of-sequence depending on timing.

Restructure to batch semantics: BULK COLLECT ... LIMIT 1000 into collections, FORALL the writes, one COMMIT per batch — fetching stays inside a stable snapshot per batch while commits happen between fetches, never inside them. When processing must interleave reads and writes row-by-row, split sessions: one session holds the read cursor untouched, a second performs the writes and commits. The read snapshot then survives the entire pass.

Lint loops for COMMIT placement in review: any COMMIT lexically inside a FETCH loop is a defect until proven otherwise. The pattern hides in exception handlers too — a COMMIT in the loop's exception branch fires exactly when the data is most turbulent. Batch it, split it, but never commit mid-cursor. Ever. No exception.

fetch_loop_fix.sqlSQL
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
-- WRONG: commit inside the fetch loop (releases snapshot position)
-- LOOP FETCH c INTO r; EXIT WHEN c%NOTFOUND; process(r); COMMIT; END LOOP;

-- RIGHT: bulk fetch, forall write, commit per batch
DECLARE
  CURSOR c IS SELECT order_id, total FROM shop.orders WHERE processed = 'N';
  TYPE t IS TABLE OF c%ROWTYPE;
  rows_ t;
BEGIN
  OPEN c;
  LOOP
    FETCH c BULK COLLECT INTO rows_ LIMIT 1000;
    EXIT WHEN rows_.COUNT = 0;
    FORALL i IN 1..rows_.COUNT
      UPDATE shop.orders SET processed = 'Y'
      WHERE order_id = rows_(i).order_id;
    COMMIT;  -- between fetches, never inside one
  END LOOP;
  CLOSE c;
END;
/
⚠ COMMIT Inside FETCH Is Always a Defect
A COMMIT inside a fetch loop releases the cursor's snapshot anchor mid-pass — the next FETCH reads moved data with possibly-expired undo. Bulk-collect with LIMIT, FORALL the writes, and commit between fetches.
📊 Production Insight
A per-row-commit loop failed nightly with 01555 until bulk restructuring — same work, one commit per thousand rows, zero snapshot failures since.
🎯 Key Takeaway
Never COMMIT inside a fetch loop — bulk-collect, FORALL, and commit between fetches.

Delayed Block Cleanout and Hot Blocks

Every committed change leaves its mark on data blocks until cleanout visits them; blocks bulk-loaded or mass-updated without follow-up reads carry thousands of uncleaned transaction slots. A full scan over such blocks must check undo per block to confirm cleanout state — multiplying undo demand far beyond the query's logical work. The 01555 trace naming cleanout is the signature: the query isn't reading hot history, it's paying cleanout tax on cold blocks.

The cure sits with the writers. Commit in sane batches (thousands of rows, not per-row and not once per 10M) so each commit's blocks get cleaned by subsequent reads promptly; follow massive loads with a DBMS_STATS gather or a light full scan that touches and cleans blocks while undo is fresh. Readers help by avoiding SELECT * full scans where indexed access suffices — fewer blocks touched, less cleanout owed.

Confirm before redesigning: the 01555 error trace (event 1555) distinguishes cleanout-driven failures from retention gaps, and AWR shows the writer's commit pattern. When cleanout dominates, writer hygiene plus a touch-pass fixes more than any retention raise — because the undo needed was never about query duration at all.

cleanout_check.sqlSQL
1
2
3
4
5
6
7
8
9
10
11
12
13
14
-- Writer commit sanity (commits/sec during load windows)
SELECT snap_id, value AS commits
FROM dba_hist_sysstat
WHERE stat_name = 'user commits'
ORDER BY snap_id DESC FETCH FIRST 10 ROWS ONLY;

-- Touch-pass after bulk loads (cleans blocks while undo is fresh)
-- (run post-load, off-peak)
-- SELECT /*+ FULL(o) */ COUNT(*) FROM shop.orders o;
-- EXEC DBMS_STATS.GATHER_TABLE_STATS('SHOP','ORDERS');

-- Readers: prefer indexed access over full scans where possible
EXPLAIN PLAN FOR SELECT * FROM shop.orders WHERE order_date > SYSDATE - 1;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);
📊 Production Insight
A post-load touch-pass plus saner writer batching ended cleanout-driven 01555s that two retention raises hadn't touched — the undo was never the bottleneck.
🎯 Key Takeaway
Cleanout tax masquerades as retention gaps — fix writer batching and touch blocks post-load.

Retention Math: Size Undo for Your Longest Query

Retention sizing is arithmetic, not folklore. From v$undostat: MAX(maxquerylen) is the longest query the system has seen (your requirement), and tuned_undoretention shows what space actually allowed. Set UNDO_RETENTION to maxquerylen plus 20% margin; then verify the tablespace holds retention-seconds × peak undo-block production (UNXPBLKRELCNT/UNXPBLKREUCNT trends per SECOND in the same view). If tuned retention sits below your setting, space binds — add datafiles until tuned meets the setting across a full workload cycle.

Watch the steal counters as your early warning: SSOLD (stolen expired blocks) climbing means retention promises are being broken for space; NOSPACEERRCOUNT nonzero means writers already failed under guarantee. Alert on both, plus maxquerylen crossing 80% of UNDO_RETENTION — the trend predicts the 01555 weeks before the marathon query meets the hot writer.

Recompute on cadence, not just after incidents. Workloads drift: new batch jobs raise undo production, new reports raise maxquerylen. A weekly v$undostat review (or an automated sizing report) keeps the garment fitted — retention sized once rots into the next 01555 within two quarters of steady workload drift.

retention_math.sqlSQL
1
2
3
4
5
6
7
8
9
10
11
12
13
14
-- Requirement: longest query seen (seconds)
SELECT MAX(maxquerylen) AS requirement_s,
  MAX(tuned_undoretention) AS tuned_s,
  SUM(ssold) AS stolen_blocks
FROM v$undostat;

-- Undo production rate per second (sizes the tablespace)
SELECT begin_time, undoblks AS undo_blocks,
  maxquerylen, tuned_undoretention
FROM v$undostat
ORDER BY begin_time DESC FETCH FIRST 12 ROWS ONLY;

-- Set 20% above the longest query, effective immediately
ALTER SYSTEM SET undo_retention = 26000 SCOPE = BOTH;
📊 Production Insight
Weekly v$undostat reviews caught maxquerylen creeping toward retention twice — both resized quietly, neither became an incident.
🎯 Key Takeaway
Requirement = MAX(maxquerylen) + 20%; verify tuned retention meets it; alert at 80% and on stolen blocks.

Prevention: Design Queries Shorter Than Retention

Infinite undo is not a design — queries must fit history, not the reverse. Break marathon rollups into incremental chunks (per-day partitions, committed progress, restartable from the last chunk) so no single query runs longer than retention. Prefer indexed range scans over full-table sweeps where the business question allows; push aggregation into materialized views refreshed incrementally. The 6-hour scan retired into 24 twenty-minute chunks is immune to 01555 by construction.

Isolate what remains long. Run unavoidable marathons on standby snapshots or flashback-guarded copies where writers can't churn the blocks being read — physical separation beats any retention number. Schedule them outside batch windows so even shared-primary runs face minimal churn, and fence batch writers from the scanned tables during the window.

Monitor the margin continuously: a sqlplus cron comparing v$undostat maxquerylen against UNDO_RETENTION pages when the gap narrows, long before any query dies. Retention pressure is a slow leak with a precise gauge — watch the gauge and the 3 AM pages stop. Put the margin graph on the same dashboard as batch runtimes so the team sees pressure and demand move together.

watch_retention_margin.shBASH
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/bin/bash
# Page when longest queries approach retention (80% threshold)
set -euo pipefail
OUT=$(sqlplus -S 'mon/pass@//db-prod:1521/shop' << 'EOF'
SET HEADING OFF FEEDBACK OFF
SELECT MAX(maxquerylen) || ',' ||
  (SELECT TO_NUMBER(value) FROM v$parameter WHERE name='undo_retention')
FROM v$undostat;
EOF
)
MAXQ=$(echo "$OUT" | cut -d, -f1 | tr -d ' ')
RET=$(echo "$OUT" | cut -d, -f2 | tr -d ' ')
PCT=$(python3 -c "print(int(100*$MAXQ/$RET))")
[ "$PCT" -ge 80 ] && { echo "PAGE: retention margin ${PCT}% (maxq=$MAXQ ret=$RET)"; exit 1; }
echo "OK: retention margin ${PCT}%"
📊 Production Insight
An 80%-margin alert now pages weeks before pressure becomes failure — retention resizes land as routine changes, never as incident responses.
🎯 Key Takeaway
Chunk marathons, isolate long reads, and alert when maxquerylen crosses 80% of retention.
● Production incidentPOST-MORTEMseverity: high

A 6-Hour Rollup Died at 94% Against Nightly Batch Writers

Symptom
At 1:00 AM the daily revenue rollup started its 6-hour full scan; at 6:40 AM — 94% complete — it died with ORA-01555. The retry at 7:00 AM died again at 11:50 AM after another 5 hours, also near completion. Finance had no numbers by noon, the retry consumed a second business day of I/O, and the batch window for the next night shrank to unworkable. Two full runs, zero output, twelve hours of the warehouse's fastest storage burned.
Assumption
The team assumed corrupt undo segments and asked the DBAs to rebuild undo — twice — while the real mismatch sat in plain arithmetic: 6-hour reads against 15-minute retention with aggressive writers. An hour went to alert-log archaeology for corruption markers that never existed, because 'snapshot too old' sounded like broken storage instead of expired history.
Root cause
Three compounding facts: UNDO_RETENTION at the 900-second default against a 21,600-second query; batch writers committing every 30 seconds across the same order tables (churning undo furiously); and the report's full-table scan touching every hot block, maximizing exposure. v$undostat later showed maxquerylen demanding ~22,000 seconds while tuned retention sat at 900 — a 24× gap no retry could cross.
Fix
They moved the rollup to a STANDBY snapshot (zero writer churn), raised UNDO_RETENTION to 21600 with undo autoextend plus 40 GB, and broke the report into per-day chunks committing progress hourly. The rollup finished in 3.5 hours that night. Permanent: retention sized from v$undostat maxquerylen weekly, batch writers consolidated to fewer commits, and the 6-hour scan retired in favor of incremental rollups.
Key lesson
  • Size retention from v$undostat maxquerylen, not from defaults: the longest query's runtime is the requirement, and 900 seconds covers almost no analytics workload.
  • Separate readers from writers for marathon queries: standby snapshots and incremental rollups remove the race instead of out-armoring it.
  • Never retry a 01555 unchanged: the arithmetic guarantees the same failure — change retention, storage, isolation, or query shape before rerunning.
Production debug guideSix steps from the dead report to sized retention or a redesigned read.6 entries
Symptom · 01
Long query dies with ORA-01555 near completion
→
Fix
Read the retention reality: SELECT * FROM v$undostat ORDER BY begin_time DESC; — note MAXQUERYLEN (longest query, seconds) and TUNED_UNDORETENTION versus your UNDO_RETENTION setting (SHOW PARAMETER undo_retention;). If MAXQUERYLEN dwarfs retention, the arithmetic names the cause: history expired before the reader finished. Capture SSOLD (stolen expired extents) as corroboration.
Symptom · 02
You need undo storage facts, not guesses
→
Fix
Audit the tablespace: SELECT tablespace_name, retention FROM dba_tablespaces WHERE contents = 'UNDO'; then SELECT file_name, bytes/1024/1024 AS mb, autoextensible, maxbytes FROM dba_data_files WHERE tablespace_name = '<undo_ts>'; Fixed-size files with AUTOEXTENSIBLE=NO recycle aggressively no matter what retention says — enable autoextend and add space before tuning anything else.
Symptom · 03
Failure clusters around one job's schedule
→
Fix
Find the churn: SELECT sql_id, executions, elapsed_time/1000000 AS sec FROM v$sql WHERE elapsed_time > 3600*1000000 ORDER BY elapsed_time DESC; for marathon readers, and check batch writers committing furiously in the same window (AWR 'user commits' per second). A 5-hour reader overlapping a 30-second-commit writer storm is the classic pairing — separate them in time or isolate the reader.
Symptom · 04
PL/SQL loop fetching and committing per row fails
→
Fix
Stop committing inside the fetch loop: the COMMIT releases snapshot position and the next FETCH re-establishes against moved data. Restructure to BULK COLLECT with LIMIT plus FORALL writes, committing per batch outside the fetch — or open a second session for writes. The loop's own commits are manufacturing the inconsistency it then trips over.
Symptom · 05
Full scans over recently-bulk-loaded tables fail fast
→
Fix
Suspect delayed block cleanout: masses of blocks with uncleaned transaction headers force undo lookups per block. Confirm via the 01555 trace (cleanout references), then have writers commit reasonably per batch (not per row, not once per 10M rows) and re-run. Reducing cleanout debt at write time is cheaper than surviving it at read time.
Symptom · 06
You must size retention that actually covers the workload
→
Fix
Compute from history: SELECT MAX(maxquerylen) FROM v$undostat; — set UNDO_RETENTION 20% above it, ensure undo tablespace holds retention-seconds × undo-bytes-per-second (from v$undostat UNXPBLKRELCNT trends), and alert when maxquerylen crosses 80% of retention. Retention is a measured garment, not a default.
ORA-01555 Causes at a Glance
Root CauseHow to ConfirmFixPrevention
Query outruns retention vs hot writersmaxquerylen dwarfs UNDO_RETENTIONRaise retention + space; isolate readerSize from v$undostat; chunk marathons
Starved undo tablespaceFixed files, AUTOEXTENSIBLE=NO, SSOLD climbingAutoextend + datafiles; guarantee selectivelyCapacity-plan undo like any tablespace
COMMIT inside fetch loopPL/SQL loop commits per rowBulk collect + FORALL, commit between fetchesLint loops for mid-cursor COMMITs
Delayed block cleanout01555 trace cites cleanout; post-load scans failSane writer batches + post-load touch-passTouch blocks after bulk loads
Full scans over churned tablesPlan shows FULL; writers heavy in windowIndexed access; standby snapshotsSchedule marathons off batch windows
⚙ Quick Reference
6 commands from this guide
FileCommand / CodePurpose
undo_baseline.sqlSHOW PARAMETER undo_retention;Read Consistency in 90 Seconds
size_undo.sqlSELECT MAX(maxquerylen) AS longest_query_s,UNDO_RETENTION and the Undo Tablespace
fetch_loop_fix.sqlDECLARECommits Inside Fetch Loops
cleanout_check.sqlSELECT snap_id, value AS commitsDelayed Block Cleanout and Hot Blocks
retention_math.sqlSELECT MAX(maxquerylen) AS requirement_s,Retention Math
watch_retention_margin.shset -euo pipefailPrevention

Key takeaways

1
01555 means the reader outran surviving undo
measure maxquerylen vs retention first.
2
Retention is a floor honored with space
autoextend plus room, guarantee selectively.
3
Never COMMIT inside a fetch loop
bulk-collect, FORALL, commit between fetches.
4
Cleanout tax and starved space mimic retention gaps
check traces and steals.
5
Requirement = MAX(maxquerylen) + 20%; alert at 80% and on stolen blocks.
6
Chunk marathons and isolate long reads; infinite undo is not a design.

Common mistakes to avoid

5 patterns
×

Retrying the dead marathon unchanged

Symptom
Second 6-hour run dies at 94% again — arithmetic guarantees it.
Fix
Change retention, space, isolation, or query shape before any rerun.
×

Raising UNDO_RETENTION without adding space

Symptom
Tuned retention flatlines; 01555s continue — the setting was never the constraint.
Fix
Autoextend plus datafiles until tuned retention meets the setting.
×

Committing per row inside fetch loops

Symptom
Nightly 01555/fetch-out-of-sequence from the loop's own snapshot churn.
Fix
BULK COLLECT with LIMIT, FORALL writes, commit between fetches.
×

Rebuilding undo for an arithmetic gap

Symptom
Fresh segments, identical failures — hours lost on healthy storage.
Fix
Read v$undostat first: maxquerylen vs retention names the gap in seconds.
×

Guaranteeing retention without watching writers

Symptom
01555s become ORA-30036 writer failures — the pressure moved, not vanished.
Fix
Size for guarantee and monitor NOSPACEERRCOUNT; guarantee is a promise needing room.
INTERVIEW PREP · PRACTICE MODE

Interview Questions on This Topic

Q01JUNIOR
What does ORA-01555 mean?
Q02SENIOR
How do you size UNDO_RETENTION from evidence?
Q03SENIOR
Why must you never COMMIT inside a fetch loop?
Q04SENIOR
Retention is high but 01555s persist. What else?
Q05SENIOR
Design reporting that can't hit 01555.
Q01 of 05JUNIOR

What does ORA-01555 mean?

ANSWER
A query needed a read-consistent block version whose undo was overwritten — the query outran surviving history. Long readers plus hot writers plus short retention is the classic triangle.
FAQ · 6 QUESTIONS

Frequently Asked Questions

01
Will more undo space alone fix 01555?
02
Is RETENTION GUARANTEE always good?
03
Can SELECT-only workloads get 01555?
04
Do indexes really prevent 01555?
05
Why did the retry fail at the same percentage?
06
Flashback queries and 01555?
N
Naren Founder & Principal Engineer

20+ years shipping high-throughput database systems. Notes here come from systems that actually shipped.

Follow
✓ Verified
production tested
September 23, 2026
last updated
1,942
articles · all by Naren
🔥

That's Oracle. Mark it forged?

5 min read · try the examples if you haven't

←
Previous
ORA-02291 Integrity Constraint Fix
5 / 5 · Oracle
Next
MongoDB E11000 Duplicate Key Fix
→