Oracle データベースのあらゆる変更には SCN(System Change Number)が割り当てられます。SCN はコミットのたびに単調増加する数値で、「このデータはどの時点の状態か」を内部的に管理する基盤です。
Flashback Query(AS OF SCN)・UNDO の読み取り一貫性・リカバリポイントの特定など、Oracle の信頼性を支える多くの仕組みが SCN に依存しています。SCN の概念を理解することで、Flashback や ORA-01555 のエラーの意味が見えてきます。
- SCN の役割とデータベース内での使われ方
- 現在の SCN を取得する方法(V$DATABASE・DBMS_FLASHBACK)
- SCN_TO_TIMESTAMP / TIMESTAMP_TO_SCN で SCN ⇔ 時刻を相互変換する方法
- Flashback Query・UNDO・ORA-01555 と SCN の関係
- SCN ヘッドルームの確認方法と上限問題への対処
SCN の役割と仕組み
SCN は「データベース全体でコミットが行われるたびに増加するグローバルなカウンター」です。各トランザクションのコミットに SCN が割り当てられ、変更されたデータブロックにもその SCN が記録されます。
| SCN が使われる場面 | 説明 |
|---|---|
| 読み取り一貫性(Read Consistency) | SELECT 開始時の SCN を記録し、それ以降のコミットはない状態の UNDO データを読む |
| Flashback Query(AS OF SCN) | 指定した SCN 時点のデータを UNDO から読み出す |
| UNDO 管理(ORA-01555) | 指定 SCN のデータを読むのに必要な UNDO が上書きされると ORA-01555 が発生する |
| リカバリとリドゥ適用 | リドゥログの各エントリに SCN が記録され、どこまでリカバリしたかを管理する |
| データガード・ストリーム | プライマリとスタンバイ間で SCN を使って適用進捗を管理する |
現在の SCN を取得する
-- 方法①: V$DATABASE で現在の SCN を確認する(DBA権限不要)
SELECT current_scn FROM V$DATABASE;
-- 例: 15234567890
-- 方法②: DBMS_FLASHBACK.GET_SYSTEM_CHANGE_NUMBER(12c 以降は非推奨だが依然動作する)
SELECT DBMS_FLASHBACK.GET_SYSTEM_CHANGE_NUMBER FROM DUAL;
-- 方法③: V$DATABASE のその他 SCN 関連情報
SELECT
current_scn, -- 現在の SCN(最新のコミット SCN)
checkpoint_change#, -- 最後のチェックポイント SCN
resetlogs_change#, -- 最後の RESETLOGS 時の SCN(インカネーション境界)
archive_change# -- 最後にアーカイブされたログの SCN
FROM V$DATABASE;
-- 各セッションのトランザクション開始 SCN を確認する
SELECT
s.sid,
s.username,
t.start_scn -- そのトランザクションの開始 SCN(V$TRANSACTION から)
FROM V$SESSION s
JOIN V$TRANSACTION t ON s.taddr = t.addr
WHERE s.username IS NOT NULL;
SCN ⇔ タイムスタンプの変換
Oracle は内部的に SCN とタイムスタンプのマッピングを SYS.SMON_SCN_TIME テーブルに記録しています(約5分ごとに更新)。SCN_TO_TIMESTAMP / TIMESTAMP_TO_SCN はこのマッピングを使って変換します。
-- SCN → タイムスタンプ(SCN が発生した時刻を取得する) SELECT SCN_TO_TIMESTAMP(15234567890) FROM DUAL; -- 例: 09-APR-26 10:30:00.000000000 AM +09:00 -- タイムスタンプ → SCN(時刻から直近の SCN を取得する) SELECT TIMESTAMP_TO_SCN(TIMESTAMP '2026-04-09 10:00:00') FROM DUAL; -- 例: 15234512345 -- 現在から1時間前の SCN を取得する SELECT TIMESTAMP_TO_SCN(SYSTIMESTAMP - INTERVAL '1' HOUR) AS scn_1hr_ago FROM DUAL; -- SCN を使って過去のデータを参照する(Flashback Query) SELECT * FROM employees AS OF SCN 15234512345 WHERE department_id = 60; -- TIMESTAMP_TO_SCN で取得した SCN を指定することで正確な時点のデータを参照できる -- 注意: SMON_SCN_TIME の保持期間は UNDO_RETENTION に依存する -- 古すぎる SCN は ORA-08181 (specified number is not a valid system change number) になる SELECT SCN_TO_TIMESTAMP(1) FROM DUAL; -- ORA-08181: specified number is not a valid system change number(古い SCN は変換できない) -- 古すぎないか確認する(最古の SCN を確認する) SELECT oldest_flashback_scn, oldest_flashback_time FROM V$FLASHBACK_DATABASE_LOG; -- oldest_flashback_scn より前は SCN_TO_TIMESTAMP が失敗する可能性がある
SCN と読み取り一貫性・ORA-01555 の関係
SELECT 文を実行すると、Oracle は文の開始時点の SCN を記録します。クエリ実行中に他のトランザクションがコミットしても、開始時の SCN より新しいデータは読まず、UNDO から古いバージョンを読み出します。
-- セッション A: 長時間かかる SELECT を実行(開始 SCN: 15000000)
-- セッション B: SELECT 実行中に多数の UPDATE をコミット(SCN が増加)
-- → セッション B のコミットにより、UNDO に必要な古いバージョンが上書きされる
-- → セッション A が古い SCN のデータを読もうとすると UNDO が不足して ORA-01555 発生
-- UNDO の保持状況を確認する
SELECT
tuned_undoretention, -- 実際に保持されている UNDO の期間(秒)
maxquerylen, -- この時間窓内の最長クエリ時間(秒)
undoblks, -- 使用された UNDO ブロック数
ssolderrcnt -- ORA-01555 の発生回数
FROM V$UNDOSTAT
ORDER BY end_time DESC
FETCH FIRST 12 ROWS ONLY; -- 直近 12 行(1時間分)
-- UNDO_RETENTION の設定を確認する
SHOW PARAMETER undo_retention; -- デフォルト: 900 秒(15分)
-- ORA-01555 が多発する場合の対処
-- ① UNDO_RETENTION を増やす
ALTER SYSTEM SET UNDO_RETENTION = 3600; -- 1時間
-- ② UNDO 表領域に RETENTION GUARANTEE を設定する(UNDO の早期上書きを防止)
ALTER TABLESPACE undotbs1 RETENTION GUARANTEE;
-- ③ 長時間クエリを小分けにする(ROWNUM や ROWID でバッチ処理)
-- ④ セッション設定で UNDO の影響を最小化する
SCN ヘッドルームの確認と管理
Oracle の SCN には上限があります(約 281 兆:2^48 – 1)。SCN は時間ベースの上限(最大 SCN = 経過秒 × 16384)も持ちます。「SCN ヘッドルーム」とは現在の SCN が上限までどのくらい余裕があるかを示す指標です。
-- 現在の SCN とヘッドルームを計算する
SELECT
current_scn,
-- SCN の理論上限: データベース作成からの経過秒 × 16384
(EXTRACT(DAY FROM (SYSTIMESTAMP - TO_TIMESTAMP('01-JAN-1988', 'DD-MON-YYYY'))) * 86400
+ EXTRACT(HOUR FROM (SYSTIMESTAMP - TO_TIMESTAMP('01-JAN-1988', 'DD-MON-YYYY'))) * 3600
+ EXTRACT(MINUTE FROM (SYSTIMESTAMP - TO_TIMESTAMP('01-JAN-1988', 'DD-MON-YYYY'))) * 60
+ EXTRACT(SECOND FROM (SYSTIMESTAMP - TO_TIMESTAMP('01-JAN-1988', 'DD-MON-YYYY')))
) * 16384 AS max_scn,
ROUND(
((EXTRACT(DAY FROM (SYSTIMESTAMP - TO_TIMESTAMP('01-JAN-1988', 'DD-MON-YYYY'))) * 86400) * 16384 - current_scn)
/ (16384 * 3600 * 24 * 365), 1
) AS headroom_years -- 残りの理論的ヘッドルーム(年単位)
FROM V$DATABASE;
-- Oracle 12.2 以降: V$DATABASE に SCN_TO_TIME_FORMAT 等の追加列がある
-- SCN_TO_TIME_FORMAT が CONVERSION_TO_LOCAL_TIME_ENABLED なら精度が高い
-- SCN ヘッドルームが少ない場合(通常は何十年も余裕があるが、バグやミスで急増した場合):
-- ① バグ(Bug 13498243 など)による SCN スパイクを確認する
-- ② SCN 上限が近い場合はサポートに連絡してパッチを適用する
-- データベースの SCN 増加速度を確認する(直近の統計から推定)
SELECT
100 AS sample_count,
AVG(end_scn - begin_scn) AS avg_scn_per_interval,
MAX(end_scn - begin_scn) AS max_scn_per_interval
FROM (
SELECT
current_scn AS end_scn,
LAG(current_scn, 1, current_scn) OVER (ORDER BY 1) AS begin_scn
FROM V$DATABASE
CONNECT BY LEVEL <= 1 -- 単一行取得のためのダミー
);
-- 実際の増加速度を確認するには時間をおいて複数回クエリする
まとめ
- SCN の役割:コミットのたびに増加するグローバルカウンター。読み取り一貫性・Flashback・リカバリ・データガードのすべてが SCN に基づく
- 現在の SCN:
SELECT current_scn FROM V$DATABASEで確認。チェックポイント SCN も同時に確認できる - SCN_TO_TIMESTAMP / TIMESTAMP_TO_SCN:SCN と時刻を相互変換できる。変換可能な範囲は UNDO の保持期間に依存する(古すぎると ORA-08181)
- ORA-01555 と SCN:長時間クエリで読む必要のある SCN のデータが UNDO から上書きされると発生。UNDO_RETENTION の延長・RETENTION GUARANTEE の設定で防止
- SCN ヘッドルーム:SCN の上限は数十年先であり通常は問題ない。ただし SCN が急増するバグが発生した場合はパッチ適用が必要
Flashback Query での SCN の活用については Oracle Flashback 完全ガイドを参照してください。ORA-01555(スナップショットが古すぎます)の詳細な対処方法は Oracle ORA-01555 完全ガイドも参照してください。UNDO 管理については Oracle トランザクション完全ガイドも参考になります。