【完全版】ORA-01555: snapshot too old エラーの原因と対処法

【完全版】ORA-01555: snapshot too old エラーの原因と対処法

夜間バッチがほぼ完了する直前に、以下のエラーにより失敗した経験はないですか。

ORA-01555: snapshot too old: rollback segment number 12 with name "_SYSSMU12_2..." too small
ORA-01555: スナップショットが古すぎます: ロールバック・セグメント番号 12...

これは業務的なデッドラインを目の前に、開発・運用担当者を悩ませるOracle最難関エラーのひとつです。

  • 大量データの集計バッチが失敗する
  • データ移行スクリプトが途中で停止する
  • 一部のSELECT文だけ失敗する
  • パッケージから呼ばれるクエリだけエラーになる
  • UNDO_RETENTIONを増やしても解決しない
  • 別のDBでは同じSQLが動くが、本番だけ失敗する

ORA-01555は「読み取り一貫性」という Oracle 独自のアーキテクチャに起因するエラーで、表面的な対処ではなく仕組みを理解した上での根本対処が必要です。

本記事では、ORA-01555のすべての原因と対処法を、現場で即使えるトラブルシューティング手順として整理します。読み取り一貫性とUNDOの基礎、UNDO_RETENTION・UNDO表領域の設計、Fetch Across Commit問題、LOBの特殊ケース、運用視点での予防策まで完全網羅。この1本でORA-01555を根本から解決する方法が分かります。


目次

結論:今すぐ試すべき3ステップ

時間がない方向けに、まず試すべき手順を示します。

ステップ1:UNDO_RETENTIONを増やす(応急処置)

-- 現在の設定確認
SHOW PARAMETER undo_retention

-- 増加(秒単位。例:4時間=14400秒)
ALTER SYSTEM SET undo_retention = 14400 SCOPE=BOTH;

ステップ2:UNDO表領域の自動拡張を有効化

SELECT TABLESPACE_NAME, AUTOEXTENSIBLE, MAXBYTES/1024/1024 AS MAX_MB
FROM DBA_DATA_FILES 
WHERE TABLESPACE_NAME LIKE 'UNDO%';

-- 自動拡張化
ALTER DATABASE DATAFILE '/path/to/undotbs01.dbf' AUTOEXTEND ON NEXT 100M MAXSIZE 32G;

ステップ3:UNDO使用状況を確認

SELECT BEGIN_TIME, END_TIME, UNDOBLKS, MAXQUERYLEN, SSOLDERRCNT 
FROM V$UNDOSTAT 
ORDER BY BEGIN_TIME DESC 
FETCH FIRST 24 ROWS ONLY;

SSOLDERRCNTにゼロ以外があれば、その時間帯にORA-01555が発生しています。

応急処置で時間を稼ぎつつ、以下の根本原因分析へ進んでください。


まず押さえる:読み取り一貫性とは

ORA-01555を本質的に理解するには、**Oracleの読み取り一貫性(Read Consistency)**という仕組みを知る必要があります。

読み取り一貫性の概念

Oracleでは、長時間クエリでもクエリ開始時点のデータを一貫して返します。クエリ実行中に他のセッションがデータを更新しても、開始時点の状態を保ったまま結果を返す仕組みです。

時刻 T1: 集計クエリ開始(テーブルAの状態を読み始める)
時刻 T2: 別セッションがテーブルAを更新・コミット
時刻 T3: 集計クエリがまだ実行中
時刻 T4: 集計クエリ完了 → T1時点のデータを返す(正しい一貫性)

この「過去の状態を再構築する」ために必要なのがUNDOデータです。

UNDOの役割

UNDO(旧称:ロールバックセグメント)は、データを変更する前の元の状態を保存しておく領域です。主な役割:

  1. ロールバック: トランザクション取消時に元に戻す
  2. 読み取り一貫性: 過去時点のデータを再構築
  3. フラッシュバック: 時点指定での過去データ参照

ORA-01555の発生メカニズム

クエリ開始後、他のトランザクションが更新してUNDOデータを書き込み、それが保持期間を超えて上書きされた場合に発生します。

時刻 T1: クエリ開始
時刻 T2: 別セッションがUPDATE → UNDO書き込み
時刻 T3: T2のUNDOが保持期間切れで上書き
時刻 T4: クエリがT1時点のデータを再構築しようとするが、UNDOが無い
        → ORA-01555 発生

つまり、**「過去の状態を再構築するためのUNDOデータが失われた」**ことを意味します。


ORA-01555の原因カテゴリ

カテゴリ原因例頻度
UNDO設定不足系UNDO_RETENTION値が小さい、UNDO表領域容量不足
長時間クエリ系バッチ処理、大量データ集計
アプリ設計系Fetch Across Commit、ループ内コミット
同時並行系大量更新と並行する長時間SELECT
LOB特有LOB列のリトリーブで発生(ORA-22924)
遅延ブロッククリーンアウト系過去の大量更新後のクエリ
フラッシュバック系AS OF SCN指定での時点参照

これらを順番に切り分けます。


【原因①】UNDO_RETENTION の設定値が小さい

最も基本的な原因です。UNDOデータの保持時間が、クエリ実行時間より短い設定になっています。

現在の設定確認

SHOW PARAMETER undo_retention

デフォルトは 900 秒(15分)です。これは多くの本番システムでは不足します。

推奨値の判断材料

-- 直近の最長クエリ実行時間
SELECT MAX(MAXQUERYLEN) AS LONGEST_QUERY_SECONDS 
FROM V$UNDOSTAT;

MAXQUERYLENは秒単位での最長クエリ時間です。これより長い値をUNDO_RETENTIONに設定する必要があります。

設定変更

-- 例:4時間(14400秒)に変更
ALTER SYSTEM SET undo_retention = 14400 SCOPE=BOTH;

⚠️ 重要: UNDO_RETENTIONは「目標値」であり「保証値」ではありません。容量不足の場合、Oracleはこの設定を無視して古いUNDOを上書きします(後述のGUARANTEEで保証可能)。


【原因②】UNDO表領域の容量不足

UNDO_RETENTIONを長くしても、UNDO表領域のサイズが小さいと古いUNDOから順次上書きされます。

UNDO表領域のサイズ確認

SELECT 
    TABLESPACE_NAME,
    SUM(BYTES)/1024/1024 AS SIZE_MB,
    SUM(MAXBYTES)/1024/1024 AS MAX_MB,
    MAX(AUTOEXTENSIBLE) AS AUTOEXTEND
FROM DBA_DATA_FILES
WHERE TABLESPACE_NAME = (SELECT VALUE FROM V$PARAMETER WHERE NAME = 'undo_tablespace')
GROUP BY TABLESPACE_NAME;

UNDO使用状況の確認

SELECT 
    TABLESPACE_NAME,
    STATUS,
    ROUND(SUM(BYTES) / 1024 / 1024, 2) AS MB
FROM DBA_UNDO_EXTENTS
GROUP BY TABLESPACE_NAME, STATUS;

STATUSの値:

  • ACTIVE: 進行中トランザクションのUNDO
  • UNEXPIRED: 保持期間内
  • EXPIRED: 保持期間切れ・再利用可能

EXPIREDがほぼ無く UNEXPIRED がいっぱいの場合、容量不足です。

UNDO表領域の拡張

データファイル追加

ALTER TABLESPACE UNDOTBS1 ADD DATAFILE '/path/to/undotbs02.dbf' 
    SIZE 4G AUTOEXTEND ON NEXT 100M MAXSIZE 32G;

既存データファイルの自動拡張化

ALTER DATABASE DATAFILE '/path/to/undotbs01.dbf' 
    AUTOEXTEND ON NEXT 100M MAXSIZE 32G;

新しいUNDO表領域を作って切り替え

-- 新UNDO作成
CREATE UNDO TABLESPACE UNDOTBS2 
    DATAFILE '/path/to/undotbs2_01.dbf' SIZE 8G 
    AUTOEXTEND ON NEXT 100M MAXSIZE 32G;

-- 切り替え
ALTER SYSTEM SET undo_tablespace = UNDOTBS2 SCOPE=BOTH;

-- 古いUNDOは一定時間後に削除
DROP TABLESPACE UNDOTBS1 INCLUDING CONTENTS AND DATAFILES;

UNDOサイズの目安

公式の推奨サイジング:

UNDOサイズ = UNDO_RETENTION(秒)× UNDOブロック生成速度(ブロック/秒)× ブロックサイズ

実際のブロック生成速度は:

SELECT AVG(UNDOBLKS/((END_TIME - BEGIN_TIME)*86400)) AS UNDO_BLKS_PER_SEC
FROM V$UNDOSTAT;

例: UNDO_RETENTION=14400秒、生成速度=100ブロック/秒、ブロックサイズ=8KB → 14400 × 100 × 8192 = 約 11GB が目安


【原因③】RETENTION GUARANTEE が設定されていない

UNDO_RETENTION は通常目標値ですが、GUARANTEE を付ければ保証値になります。

現在の保証設定確認

SELECT TABLESPACE_NAME, RETENTION 
FROM DBA_TABLESPACES 
WHERE CONTENTS = 'UNDO';

RETENTION の値:

  • NOGUARANTEE: 保証なし(デフォルト)
  • GUARANTEE: 保証あり

GUARANTEE を有効化

ALTER TABLESPACE UNDOTBS1 RETENTION GUARANTEE;

これでUNDO_RETENTIONを完全保証します。

GUARANTEEの注意点

⚠️ GUARANTEEを設定すると、UNDO容量が枯渇した時に**新しい更新が失敗(ORA-30036)**します。可用性とのトレードオフです。

解除

ALTER TABLESPACE UNDOTBS1 RETENTION NOGUARANTEE;

【原因④】Fetch Across Commit 問題

取得中のテーブルに対して、同じセッションでコミット」した時に発生します。

問題のあるコード例(PL/SQL)

DECLARE
    CURSOR c IS SELECT id FROM big_table;
BEGIN
    FOR rec IN c LOOP
        UPDATE big_table SET status = 'PROCESSED' WHERE id = rec.id;
        COMMIT;  -- ❌ ループ内コミット
    END LOOP;
END;
/

このコードは、カーソルcがオープン中(読み取り中)に、同じセッションでCOMMITを発行します。コミットすると、そのトランザクションのUNDOが「不要」と判定され早期に再利用される可能性があり、カーソルが過去状態を再構築できなくなる→ORA-01555。

正しい実装例:BULK COLLECT + 一括COMMIT

DECLARE
    CURSOR c IS SELECT id FROM big_table;
    TYPE id_tab IS TABLE OF big_table.id%TYPE;
    v_ids id_tab;
BEGIN
    OPEN c;
    LOOP
        FETCH c BULK COLLECT INTO v_ids LIMIT 10000;
        EXIT WHEN v_ids.COUNT = 0;
        
        FORALL i IN 1..v_ids.COUNT
            UPDATE big_table SET status = 'PROCESSED' 
            WHERE id = v_ids(i);
        COMMIT;  -- バッチサイズごとのコミットは安全
    END LOOP;
    CLOSE c;
END;
/

BULK COLLECT LIMITでフェッチを完了してからコミットするので、Fetch Across Commit問題を回避できます。

Java/Pythonでの典型的アンチパターン

// ❌ アンチパターン
ResultSet rs = stmt.executeQuery("SELECT id FROM big_table");
while (rs.next()) {
    int id = rs.getInt("id");
    // ResultSet取得中に同じセッションでUPDATE+COMMIT
    pstmtUpdate.setInt(1, id);
    pstmtUpdate.executeUpdate();
    conn.commit();  // ❌ rs取得中のCOMMIT
}
// ✅ 推奨:取得とUPDATEを分離
List<Integer> ids = new ArrayList<>();
try (ResultSet rs = stmt.executeQuery("SELECT id FROM big_table")) {
    while (rs.next()) ids.add(rs.getInt("id"));
}
// rsを完全クローズしてから処理
for (int id : ids) {
    pstmtUpdate.setInt(1, id);
    pstmtUpdate.executeUpdate();
}
conn.commit();

【原因⑤】長時間クエリ自体の問題

長すぎるクエリ」自体がORA-01555を呼びやすくなります。

長時間クエリの特定

SELECT 
    SQL_ID, 
    EXECUTIONS, 
    ELAPSED_TIME/1000000 AS ELAPSED_SEC,
    ROUND(ELAPSED_TIME/EXECUTIONS/1000000, 2) AS AVG_SEC
FROM V$SQL
WHERE ELAPSED_TIME/EXECUTIONS > 60000000  -- 平均60秒以上
ORDER BY AVG_SEC DESC
FETCH FIRST 20 ROWS ONLY;

解決アプローチ

  1. クエリ最適化: 実行計画見直し、適切なインデックス追加
  2. パラレル実行: 大量データなら/*+ PARALLEL(t, 4) */ヒントで時間短縮
  3. マテリアライズドビュー: 重い集計を事前計算
  4. 時間外実行: 更新が少ない時間帯にバッチを移動

パラレルクエリのヒント例

SELECT /*+ PARALLEL(big_table, 8) */ 
    region, SUM(sales) 
FROM big_table 
GROUP BY region;

【原因⑥】LOB列のORA-01555(ORA-22924)

LOB列(CLOB/BLOB)の場合、通常のテーブルとは別の挙動でエラーが発生します。

エラー例

ORA-22924: snapshot too old

これはORA-01555のLOB版で、原因も対処も微妙に異なります。

LOBの PCTVERSION と RETENTION

LOB列には独自の「古いバージョン保持」設定があります:

SELECT TABLE_NAME, COLUMN_NAME, PCTVERSION, RETENTION 
FROM USER_LOBS;
設定意味
PCTVERSIONLOBセグメントの何%を古いバージョン保持に使うか
RETENTIONUNDO_RETENTION設定を利用(PCTVERSIONより推奨)

PCTVERSIONの増加

ALTER TABLE my_table MODIFY LOB (clob_col) (PCTVERSION 30);

デフォルトは10%ですが、長時間クエリが多い場合は20〜30%に増やします。

RETENTION モードに変更

ALTER TABLE my_table MODIFY LOB (clob_col) (RETENTION);

RETENTIONモードはUNDO_RETENTIONの値が適用されるため、UNDO_RETENTION調整と一括管理できます。


【原因⑦】遅延ブロック・クリーンアウト

大量UPDATE後にSELECTを実行すると、初回のSELECT時に遅延ブロック・クリーンアウトが発生し、UNDOを参照してORA-01555が出ることがあります。

発生パターン

時刻T1: 大量UPDATE実行
時刻T2: UPDATEのトランザクションコミット
時刻T3: 他セッションが大量UPDATEし続けてUNDOを上書き
時刻T4: T1のUPDATE結果をSELECTすると、ブロック・クリーンアウトでUNDO参照
        → ORA-01555

対処

大量UPDATE後に意図的にダミーSELECTを実行してクリーンアウト:

-- 大量UPDATEの直後に実行
SELECT /*+ FULL(t) */ COUNT(*) FROM updated_table t;
COMMIT;

これで全ブロックを物理的に「綺麗にして」から、後続のクエリでのトラブルを減らせます。


UNDO使用状況のモニタリング

ORA-01555を予防するには、UNDO使用状況の定期監視が重要です。

V$UNDOSTAT(直近4日間)

SELECT 
    BEGIN_TIME,
    END_TIME,
    UNDOBLKS,                    -- 生成UNDOブロック数
    TXNCOUNT,                    -- トランザクション数
    MAXQUERYLEN,                 -- 最長クエリ実行時間(秒)
    MAXQUERYSQLID,               -- そのSQL_ID
    SSOLDERRCNT,                 -- ORA-01555発生回数
    NOSPACEERRCNT,               -- スペース不足エラー
    UNXPSTEALCNT,                -- UNEXPIREDから盗まれた回数
    EXPSTEALCNT                  -- EXPIREDから取られた回数
FROM V$UNDOSTAT
ORDER BY BEGIN_TIME DESC
FETCH FIRST 24 ROWS ONLY;

監視ポイント

カラムアラート閾値
SSOLDERRCNT > 0ORA-01555発生中 → 即対応
UNXPSTEALCNT > 0UNEXPIREDから奪取 → 容量不足の兆候
MAXQUERYLEN > UNDO_RETENTION設定不足
NOSPACEERRCNT > 0スペース不足 → UNDO拡張必要

DBA_HIST_UNDOSTAT(過去履歴)

-- AWR(要Diagnosticパック)から長期トレンド
SELECT 
    BEGIN_TIME,
    MAXQUERYLEN,
    SSOLDERRCNT
FROM DBA_HIST_UNDOSTAT
WHERE BEGIN_TIME > SYSDATE - 7
ORDER BY BEGIN_TIME;

自動拡張ファイルの空き容量確認

SELECT 
    TABLESPACE_NAME,
    ROUND(SUM(BYTES)/1024/1024, 2) AS CURRENT_MB,
    ROUND(SUM(MAXBYTES)/1024/1024, 2) AS MAX_MB,
    ROUND((SUM(BYTES)/SUM(MAXBYTES))*100, 2) AS USED_PCT
FROM DBA_DATA_FILES
WHERE TABLESPACE_NAME = (SELECT VALUE FROM V$PARAMETER WHERE NAME = 'undo_tablespace')
GROUP BY TABLESPACE_NAME;

プログラム言語別 ORA-01555 対処

Python(python-oracledb)

import oracledb

try:
    conn = oracledb.connect(user="scott", password="tiger", dsn="//host:1521/ORCL")
    cursor = conn.cursor()
    cursor.arraysize = 10000  # フェッチサイズを大きく
    cursor.execute("SELECT id FROM big_table")
    
    # データを全て取得してからクローズ → 後続処理
    rows = cursor.fetchall()
    cursor.close()
    
    # ここからUPDATE処理
    for row in rows:
        cursor2 = conn.cursor()
        cursor2.execute("UPDATE big_table SET status='OK' WHERE id=:1", [row[0]])
        if row[0] % 10000 == 0:
            conn.commit()
    conn.commit()
    
except oracledb.DatabaseError as e:
    error, = e.args
    if error.code == 1555:
        print("ORA-01555: UNDO切れによるスナップショット古すぎ")
        print("対処: UNDO_RETENTION増加 or バッチ処理見直し")

Java(JDBC)

// フェッチサイズを大きく設定
stmt.setFetchSize(10000);

try (ResultSet rs = stmt.executeQuery("SELECT id FROM big_table")) {
    List<Long> ids = new ArrayList<>();
    while (rs.next()) {
        ids.add(rs.getLong(1));
    }
    // rsクローズ後にUPDATE
    for (Long id : ids) {
        pstmtUpdate.setLong(1, id);
        pstmtUpdate.executeUpdate();
    }
    conn.commit();
} catch (SQLException e) {
    if (e.getErrorCode() == 1555) {
        System.err.println("ORA-01555: UNDO切れ");
    }
}

Node.js(node-oracledb)

try {
    const conn = await oracledb.getConnection(config);
    const result = await conn.execute(
        'SELECT id FROM big_table',
        [],
        { fetchArraySize: 10000 }  // フェッチサイズ
    );
    // 取得完了後にUPDATE
    for (const row of result.rows) {
        await conn.execute(
            'UPDATE big_table SET status = :1 WHERE id = :2',
            ['OK', row[0]]
        );
    }
    await conn.commit();
} catch (err) {
    if (err.errorNum === 1555) {
        console.error('ORA-01555: snapshot too old');
    }
}

関連エラーと違い

ORA-22924: snapshot too old

LOB列のORA-01555版。LOB特有のPCTVERSION/RETENTION設定で対処(本記事の原因⑥参照)。

ORA-30036: unable to extend segment by … in undo tablespace

UNDO表領域が物理的に枯渇。GUARANTEE設定時、または autoextend が上限到達した時に発生。

対処: UNDO表領域の拡張、またはGUARANTEE解除。

ORA-08177: can’t serialize access for this transaction

SERIALIZABLE分離レベル時のエラー。ORA-01555と同じく読み取り一貫性関連だが、分離レベル特有。

ORA-01628: max # extents reached for rollback segment

非常に古い手動UNDO管理時代のエラー。9i以降のAUM(自動UNDO管理)では基本発生しません。


設計レベルでの予防策

ORA-01555を起こさない設計にすることが最良の対策です。

1. バッチ処理は「読み込み完了 → 更新」フェーズ分離

長時間クエリと並行する大量更新を避ける設計。

2. パーティショニングで対象データ縮小

-- 月次パーティション例
CREATE TABLE sales (
    id NUMBER,
    sale_date DATE,
    amount NUMBER
) PARTITION BY RANGE (sale_date) (
    PARTITION p202601 VALUES LESS THAN (DATE '2026-02-01'),
    PARTITION p202602 VALUES LESS THAN (DATE '2026-03-01')
);

-- 集計時はパーティション指定で範囲限定
SELECT SUM(amount) FROM sales PARTITION (p202601);

3. リード・レプリカ(Active Data Guard)の活用

更新が多い本番DBと、長時間集計を行うスタンバイDBを分離。

4. 適切なUNDO_RETENTION設計

業務最長バッチの2倍以上の値を設定:

-- 最長バッチが6時間(21600秒)なら12時間に
ALTER SYSTEM SET undo_retention = 43200 SCOPE=BOTH;

5. 監視とアラート

定期的にV$UNDOSTAT.SSOLDERRCNTを監視し、検出時に通知:

-- 直近1時間以内にORA-01555が発生したか
SELECT COUNT(*) AS ERR_COUNT
FROM V$UNDOSTAT
WHERE BEGIN_TIME > SYSDATE - 1/24
  AND SSOLDERRCNT > 0;

トラブルシューティング・チェックリスト

ORA-01555が出た時に上から順にチェックする手順です。

  1. 発生時刻と件数の確認: V$UNDOSTAT.SSOLDERRCNT
  2. その時点の最長クエリ: V$UNDOSTAT.MAXQUERYSQLID → V$SQL でクエリ特定
  3. UNDO_RETENTION値: 最長クエリ時間より長いか
  4. UNDO表領域容量: DBA_DATA_FILESで現在サイズと上限確認
  5. EXPIRED/UNEXPIREDの比率: 容量適正か判定
  6. アプリ側のFetch Across Commit: コードレビュー
  7. 長時間クエリ自体の最適化余地: 実行計画見直し
  8. LOB列の場合: PCTVERSION/RETENTION設定
  9. GUARANTEEの可否判断: 業務要件と照らし合わせ
  10. 設計レベル見直し: バッチ設計・パーティショニング検討

よくある質問(FAQ)

Q1. UNDO_RETENTIONを大きくしたのにエラーが続きます

UNDO_RETENTIONは「目標値」で「保証値」ではありません。UNDO表領域の容量が足りない場合、Oracleは設定を無視して古いUNDOを上書きします。UNDO表領域のサイズ拡張またはRETENTION GUARANTEE設定が必要です。

Q2. UNDO表領域を大きくしすぎるとデメリットはありますか?

ディスク容量を消費しますが、運用上の悪影響はほぼありません。むしろ大きめに確保するのが推奨です。目安は最長バッチ時間 × 平均UNDO生成速度の2倍程度。

Q3. GUARANTEEを有効にすると何が起きますか?

UNDO_RETENTIONを完全に保証する代わりに、UNDO容量が枯渇した場合に**新しい更新トランザクションが失敗(ORA-30036)**します。可用性とトレードオフのため、業務要件と慎重に検討してください。

Q4. 同じバッチが昨日は成功して今日失敗します

可能性として:

  • 並行する別バッチ・処理が増えてUNDO消費量が増加
  • データ量増加でクエリ自体が長時間化
  • 別ユーザーの大量UPDATE/DELETEが並行
  • 業務ピーク時間と重なった

V$UNDOSTATの該当時間帯の UNDOBLKS を確認し、UNDO生成量が増えていないかチェックしてください。

Q5. ORA-01555を予防するベストプラクティスは?

優先順位順:

  1. 業務最長クエリの2倍以上のUNDO_RETENTION
  2. UNDO表領域を十分に確保+自動拡張
  3. アプリ側でFetch Across Commitを避ける
  4. 重い集計はマテリアライズドビューで事前計算
  5. 必要に応じてActive Data Guardで読み取り分離
  6. GUARANTEE は最終手段(可用性とのバランス次第)

Q6. LOB列で出るORA-22924はORA-01555と同じ対処でいいですか?

基本的なロジックは同じですが、LOBには独自の保持設定があります。PCTVERSION を増やすか、RETENTION モードに切り替えてUNDO_RETENTION設定を活用してください。

Q7. Active Data Guardのスタンバイで出ます

スタンバイDBでもUNDOは適用されるため発生します。設定は基本的にプライマリと同じUNDO_RETENTION値が必要です。スタンバイ独自にALTER SYSTEM SET undo_retentionの設定が可能です。

Q8. パラレルクエリでORA-01555は出ますか?

出ます。むしろパラレルクエリは複数並列で長時間UNDOを参照するため、ORA-01555が出やすいケースもあります。パラレル度を上げる場合はUNDO設定も合わせて見直してください。

Q9. UNDOブロックの平均生成速度を知るには?

SELECT 
    BEGIN_TIME,
    END_TIME,
    UNDOBLKS,
    ROUND(UNDOBLKS / ((END_TIME - BEGIN_TIME) * 86400)) AS BLKS_PER_SEC
FROM V$UNDOSTAT
ORDER BY BEGIN_TIME DESC
FETCH FIRST 24 ROWS ONLY;

時間帯別の生成速度の傾向が分かります。

Q10. ORA-01555を完全に防ぐ方法はありますか?

RETENTION GUARANTEE+十分なUNDO容量で理論上は防げます。ただし、その場合の副作用(更新失敗)を許容できる環境でのみ採用してください。一般的にはアプリ・設計面での予防と監視の組み合わせが現実解です。


参考リンク・関連資料

Oracle公式ドキュメント

データディクショナリ・ビュー

LOB関連

My Oracle Support(要アカウント)

  • MOS Note: 「ORA-1555 Troubleshooting」 – トラブルシューティング集
  • MOS Note: 「Best Practices for Managing UNDO」 – UNDOベストプラクティス

関連エラー記事(本サイト)

関連Oracle記事(本サイト)

  • [Oracleバージョン確認の方法]
  • [Oracleユーザー一覧の取得方法]
  • [Oracleテーブル一覧の取得方法]
  • [Oracle directoryの確認方法]

まとめ

ORA-01555はOracle特有の「読み取り一貫性」アーキテクチャに起因するエラーで、仕組みを理解した上での設計的対処が本質解決です。要点を再整理します。

  • 発生メカニズム: クエリ実行中にUNDOデータが上書きされ、過去状態を再構築不可能になる
  • 応急処置: UNDO_RETENTION増加・UNDO表領域拡張
  • 根本対処:
    • RETENTION GUARANTEE(可用性とのトレードオフ要検討)
    • Fetch Across Commit パターン回避
    • 長時間クエリの最適化
    • LOBは PCTVERSION または RETENTION モード
  • 設計予防: パーティショニング、Active Data Guard、マテリアライズドビュー
  • 継続監視: V$UNDOSTATSSOLDERRCNTMAXQUERYLEN を定期確認

これらの知識は、Oracleの本番運用・大量データ処理・パフォーマンス改善などDBA・上級開発者には必須です。本記事をブックマークして、ORA-01555のトラブル対応とOracle運用設計のリファレンスとしてご活用ください。


本記事は2026年6月時点の情報をもとに、Oracle Database 19c / 21c / 23ai / 26ai での動作確認・公式ドキュメントに基づき作成しています。バージョンによってはチューニングパラメータの推奨値が異なる場合があるため、最新の情報はOracle公式ドキュメントもあわせてご確認ください。