【Oracle】テーブルリストア時に既存データを保護する方法|REMAP別名復元・MERGE差分反映・外部キー考慮・検証手順まで解説

【Oracle】テーブルリストア時に既存データを保護する方法|REMAP別名復元・MERGE差分反映・外部キー考慮・検証手順まで解説 Oracle

Data Pump Import(impdp)でテーブルをリストアするとき、「既存データを上書きしてしまった」「依存テーブルの整合性が壊れた」というトラブルは起きがちです。リストア操作は一歩間違えると既存の本番データを破壊する危険があるため、安全策を講じてから実行することが不可欠です。

本記事では、テーブル単位のリストアで既存データを保護するための具体的なテクニックを解説します。REMAP_TABLE で別名に復元してから比較・マージする安全ワークフロー外部キー制約がある場合の対処リストア前後の検証手順、そしてロールバック戦略までカバーします。

この記事でわかること
・table_exists_action を「データ保護」の観点で選ぶ基準
・REMAP_TABLE で別名リストア→比較→MERGE の安全ワークフロー
・content=DATA_ONLY / METADATA_ONLY の保護観点での使い分け
・外部キー制約がある場合のリストア手順
・リストア前後の COUNT / MINUS / CHECKSUM 検証手順
・ロールバック可能なリストア戦略
スポンサーリンク

リストア時のリスクと table_exists_action の選び方

table_exists_action 既存データへの影響 リスク 保護の観点
SKIP(デフォルト) 一切変更しない なし(最も安全) リストアが実行されないため復元にならない場合がある
APPEND 既存データを維持して追加 主キー重複エラーの可能性 既存行は安全。ただし重複挿入に注意
TRUNCATE 既存データを全削除して投入 高い(データ喪失) テーブル構造は維持されるが、既存データは消える
REPLACE テーブルを DROP して再作成 最も高い 構造も含めて完全に置き換わる。制約・インデックスも再作成
TRUNCATE / REPLACE は既存データを破壊する
TRUNCATE は全行を削除してからインポートし、REPLACE はテーブル自体を DROP します。いずれも元に戻せません(DDL による暗黙 COMMIT)。本番環境では TRUNCATE / REPLACE を使う前に必ずバックアップを取得してください。
既存データを保護する最も安全な方法
REMAP_TABLE で別名にリストアし、内容を確認してから本番テーブルに反映する方法です。既存テーブルに一切触れずにリストアを完了でき、問題があれば別名テーブルを DROP するだけで元に戻せます。

安全ワークフロー:別名リストア→比較→マージ

これが最も推奨される安全なリストア手順です。本番テーブルに直接触れず、段階的にデータを反映します。

ステップ(1): 別名でリストア

Shell(REMAP_TABLE で別名リストア)
# employees テーブルを employees_restore として復元
impdp hr/password \
    directory=DP_DIR \
    dumpfile=hr_backup_20260327.dmp \
    logfile=restore_remap.log \
    tables=HR.EMPLOYEES \
    remap_table=HR.EMPLOYEES:HR.EMPLOYEES_RESTORE

ステップ(2): リストアデータの確認・比較

SQL(本番 vs リストアの比較)
-- 件数の比較
SELECT 'CURRENT' AS src, COUNT(*) AS cnt FROM employees
UNION ALL
SELECT 'RESTORE', COUNT(*) FROM employees_restore;

-- 本番にあってリストアにないデータ(本番で追加された行)
SELECT employee_id, last_name FROM employees
MINUS
SELECT employee_id, last_name FROM employees_restore;

-- リストアにあって本番にないデータ(復元対象)
SELECT employee_id, last_name FROM employees_restore
MINUS
SELECT employee_id, last_name FROM employees;

-- 同じ主キーで値が異なるレコードを確認
SELECT
    c.employee_id,
    c.salary AS current_salary,
    r.salary AS restore_salary
FROM employees c
JOIN employees_restore r ON c.employee_id = r.employee_id
WHERE c.salary <> r.salary
   OR NVL(c.department_id, -1) <> NVL(r.department_id, -1);

ステップ(3): MERGE で差分だけ反映

SQL(MERGE で安全に反映)
-- 本番テーブルを保護しつつ、リストアデータの差分だけ反映
MERGE INTO employees e
USING employees_restore r
ON (e.employee_id = r.employee_id)
WHEN MATCHED THEN
    UPDATE SET
        e.salary        = r.salary,
        e.department_id = r.department_id,
        e.updated_at    = SYSDATE
    WHERE e.salary <> r.salary
       OR NVL(e.department_id, -1) <> NVL(r.department_id, -1)
WHEN NOT MATCHED THEN
    INSERT (employee_id, last_name, salary, department_id, created_at)
    VALUES (r.employee_id, r.last_name, r.salary, r.department_id, SYSDATE);

-- COMMIT 前に件数を確認
SELECT SQL%ROWCOUNT || ' rows merged' FROM DUAL;
COMMIT;

ステップ(4): 後片付け

SQL(一時テーブルの削除)
-- 反映完了を確認してから削除
DROP TABLE employees_restore PURGE;
このワークフローのメリット
・本番テーブルに直接 impdp しないため、失敗しても既存データは無傷
・MERGE は DML なので COMMIT 前に ROLLBACK 可能
・比較ステップで差分を確認してから反映できる(目視確認可能
・問題があれば employees_restore を DROP するだけで元に戻せる

APPEND モードで安全に追加する

既存データを維持したまま、バックアップから不足分だけを追加したい場合はtable_exists_action=APPEND を使います。ただし主キー重複に注意が必要です。

Shell(APPEND で安全に追加)
# 既存データを維持し、ダンプのデータを追加
impdp hr/password \
    directory=DP_DIR \
    dumpfile=hr_backup.dmp \
    logfile=append_import.log \
    tables=HR.EMPLOYEES \
    table_exists_action=APPEND \
    content=DATA_ONLY

# 主キー重複が発生した場合は ORA-00001 で該当行がスキップされる
# ログファイルでスキップされた行数を確認
APPEND + 主キー重複の動作
主キーが重複する行は ORA-00001 エラーでスキップされます。既存行は上書きされず安全ですが、「同じ主キーで値が変わっている行を更新したい」場合は APPEND では対応できません。その場合は前述の REMAP + MERGE ワークフローを使ってください。

content パラメータで保護範囲を制御する

content 値 動作 既存テーブル構造 既存データ 適するケース
ALL(デフォルト) 構造 + データの両方をインポート table_exists_action に依存 table_exists_action に依存 通常のリストア
DATA_ONLY データのみインポート(DDL は実行しない) 維持される APPEND / TRUNCATE に依存 テーブル構造を変えずにデータだけ復元
METADATA_ONLY DDL のみ実行(データは投入しない) 再作成される なし(空テーブル) テーブル構造だけコピーしたい場合
Shell(DATA_ONLY + TRUNCATE: 構造を維持してデータ入れ替え)
# テーブル構造(インデックス・制約)を維持し、データだけ入れ替え
impdp hr/password \
    directory=DP_DIR \
    dumpfile=hr_backup.dmp \
    tables=HR.EMPLOYEES \
    content=DATA_ONLY \
    table_exists_action=TRUNCATE

content=DATA_ONLY の詳細は「impdp でデータだけをインポートする方法」を参照してください。

外部キー制約がある場合のリストア手順

親テーブルと子テーブルに外部キー制約がある場合、リストアの順序を間違えると参照整合性違反(ORA-02291)が発生します。

SQL(外部キーを考慮した安全な手順)
-- (1) 依存関係を確認
SELECT a.table_name AS child_table,
       a.constraint_name,
       c_pk.table_name AS parent_table
FROM user_constraints a
JOIN user_constraints c_pk ON a.r_constraint_name = c_pk.constraint_name
WHERE a.constraint_type = 'R'
  AND (a.table_name = 'EMPLOYEES' OR c_pk.table_name = 'EMPLOYEES');

-- (2) 外部キー制約を一時的に無効化
ALTER TABLE order_details DISABLE CONSTRAINT fk_order_emp;

-- (3) リストアを実行
-- impdp ... tables=HR.EMPLOYEES table_exists_action=REPLACE

-- (4) 外部キー制約を再有効化
ALTER TABLE order_details ENABLE CONSTRAINT fk_order_emp;
-- 整合性違反があれば ORA-02298 で有効化に失敗する
SQL(impdp で制約を除外してインポート→後で追加)
# 制約を除外してインポート(外部キー制約でエラーにならない)
impdp hr/password \
    directory=DP_DIR \
    dumpfile=hr_backup.dmp \
    tables=HR.EMPLOYEES \
    table_exists_action=REPLACE \
    exclude=CONSTRAINT

# インポート後に制約を手動で追加
# ALTER TABLE employees ADD CONSTRAINT pk_emp PRIMARY KEY (employee_id);
# ALTER TABLE employees ADD CONSTRAINT fk_emp_dept FOREIGN KEY (dept_id) REFERENCES departments(dept_id);
依存テーブルがある場合は REMAP 方式が最も安全
別名でリストアすれば既存の外部キー制約には一切影響しません。MERGE で反映すれば参照整合性を維持したままデータを更新できます。

リストア前後の検証手順

検証項目 SQL 確認内容
件数比較 SELECT COUNT(*) FROM table リストア前後で件数が期待通りか
差分確認 SELECT * FROM current MINUS SELECT * FROM restore 追加・削除された行
データ整合性 SELECT COUNT(*) FROM child WHERE parent_id NOT IN (SELECT id FROM parent) 外部キー整合性
NULL 件数 SELECT COUNT(*) FROM table WHERE key_col IS NULL NULL の増減
チェックサム SELECT SUM(ORA_HASH(col1||col2||col3)) FROM table データ全体の整合性
SQL(リストア前後の自動検証スクリプト)
-- リストア前に件数とチェックサムを記録
CREATE TABLE restore_check AS
SELECT 'BEFORE' AS phase,
       COUNT(*) AS row_count,
       SUM(ORA_HASH(employee_id || salary || department_id)) AS checksum
FROM employees;

-- (ここでリストアを実行)

-- リストア後の値を追加
INSERT INTO restore_check
SELECT 'AFTER', COUNT(*), SUM(ORA_HASH(employee_id || salary || department_id))
FROM employees;

-- 比較
SELECT * FROM restore_check;
-- BEFORE と AFTER を比較して期待通りか確認

ロールバック戦略

リストア方式 ロールバック方法 難易度
REMAP + MERGE ROLLBACK(COMMIT 前なら即時) 簡単(最も推奨)
APPEND ROLLBACK(COMMIT 前)または追加行を DELETE 簡単
TRUNCATE バックアップから再リストア(TRUNCATE は DDL = 自動 COMMIT) 困難
REPLACE バックアップから再リストア(DROP は DDL = 自動 COMMIT) 困難
TRUNCATE / REPLACE を使う場合は事前バックアップ必須
TRUNCATE と REPLACE は DDL 操作であり自動 COMMIT されます。実行後に ROLLBACK はできません。本番テーブルに TRUNCATE / REPLACE を適用する場合は、事前に CREATE TABLE table_bk AS SELECT * FROM table でバックアップを取得してから実行してください。

リストア作業チェックリスト

# 作業 備考
1 対象テーブルの現在の件数・チェックサムを記録 restore_check テーブルに保存
2 対象テーブルのバックアップを作成 CREATE TABLE table_bk AS SELECT * FROM table
3 外部キー制約の依存関係を確認 USER_CONSTRAINTS で R 型を検索
4 リストアを実行(REMAP 推奨) impdp … remap_table=OLD:NEW
5 リストアデータを確認(件数・MINUS・値比較) 別名テーブルと本番を比較
6 MERGE で差分を本番に反映 COMMIT 前に SQL%ROWCOUNT を確認
7 リストア後の件数・チェックサムを確認 BEFORE/AFTER の比較
8 外部キー整合性を確認 孤立レコードがないことを確認
9 COMMIT 問題なければ確定
10 一時テーブル・バックアップテーブルを削除 DROP TABLE xxx_restore PURGE

よくある質問

Qtable_exists_action=SKIP だとデータが復元されません
ASKIP は「既存テーブルがあればスキップ」するため、テーブルが存在すると何も変わりません。既存テーブルにデータを追加したい場合は APPEND、データを入れ替えたい場合は TRUNCATE または REPLACE を使います。最も安全なのは REMAP_TABLE で別名リストア→MERGE で反映する方法です。
QREPLACE すると制約やインデックスはどうなりますか?
AREPLACE はテーブルを DROP してから再作成するため、制約・インデックス・トリガー・権限はダンプに含まれている範囲で再作成されます。ダンプ取得後に追加した制約やインデックスは失われます。テーブル構造を維持したい場合は content=DATA_ONLY + table_exists_action=TRUNCATE を使ってください。
QMERGE で反映中にエラーが出たらどうなりますか?
AMERGE は DML なので、COMMIT 前であれば ROLLBACK で全件取り消しできます。これが REMAP + MERGE 方式の最大のメリットです。TRUNCATE や REPLACE は DDL のため自動 COMMIT され、取り消しできません。
Q外部キー制約を無効化せずにリストアできますか?
AREMAP_TABLE で別名リストアすれば、既存の外部キー制約には影響しません。MERGE で反映するときに参照整合性が保たれていれば、制約を無効化する必要はありません。直接 REPLACE / TRUNCATE する場合は、外部キー制約を一時的に無効化するか、親テーブル→子テーブルの順にリストアしてください。
Qリストア後にデータが正しいことをどう確認しますか?
A(1) 件数比較: リストア前後の COUNT(*) を比較
(2) 差分確認: MINUS で追加・削除された行を確認
(3) チェックサム: ORA_HASH で全行のハッシュ値を比較
(4) 外部キー整合性: 孤立レコード(親なし子行)がないか確認
これらを自動化した検証スクリプトを用意しておくと、繰り返しのリストア作業が効率化されます。
Q大量データのテーブルを安全にリストアするコツは?
A(1) REMAP + MERGE の場合: MERGE を ROWNUM でバッチ分割(1 万件ずつ COMMIT)
(2) TRUNCATE + DATA_ONLY の場合: 事前にバックアップテーブルを作成してから実行
(3) パラレル: impdp の parallel パラメータでインポートを並列化
大量データでは CTAS でバックアップ → TRUNCATE + DATA_ONLY が最速です。

まとめ

テーブルリストア時のデータ保護方法をまとめます。

安全度 方法 説明
最も安全 REMAP_TABLE + MERGE 別名リストア→比較→MERGE で差分反映。ROLLBACK 可能
安全 APPEND + DATA_ONLY 既存データを維持して不足分を追加。主キー重複はスキップ
注意が必要 TRUNCATE + DATA_ONLY テーブル構造は維持されるが既存データは全削除。事前バックアップ必須
最も注意が必要 REPLACE テーブルを DROP して完全に再作成。事前バックアップ必須

テーブル単位のリストア方法の全体像は「指定テーブルのみリストアする方法」、Data Pump の基本は「Data Pump の使い方完全ガイド」、ORA-31684 エラーの対処は「ORA-31684 完全解説」も併せて参照してください。