【Oracle】Data Pump でインデックスを除外してエクスポート・インポートする方法|EXCLUDE=INDEX・制約の扱い・再作成手順まで解説

【Oracle】Data Pump でインデックスを除外してエクスポート・インポートする方法|EXCLUDE=INDEX・制約の扱い・再作成手順まで解説 Oracle

Data Pump でスキーマやテーブルをインポートする際、インデックスの作成に全体の 50% 以上の時間がかかることがあります。インデックスを除外してインポートし、後から NOLOGGING + PARALLEL で再作成すれば、移行時間を大幅に短縮できます。

本記事では、EXCLUDE=INDEX で全インデックスを除外する方法、特定のインデックスだけ除外する方法、PK / UNIQUE 制約のインデックスの扱いsqlfile でインデックス DDL だけを抽出する方法、そしてインポート後の高速インデックス再作成手順まで解説します。

この記事でわかること
・EXCLUDE=INDEX で全インデックスを除外する方法(expdp / impdp)
・特定のインデックスだけ除外する方法(名前指定 / LIKE パターン)
・PK / UNIQUE 制約とインデックスの関係
・sqlfile でダンプからインデックス DDL だけ抽出する方法
・インポート後にインデックスを NOLOGGING + PARALLEL で高速再作成する手順
・transform パラメータでストレージ属性を変換する方法
スポンサーリンク

インデックスを除外するメリット

メリット 詳細
インポート時間の短縮 インデックス作成がインポート時間の 50% 以上を占めることがある。除外すればデータ投入が高速化
NOLOGGING での再作成が可能 インポート中のインデックス作成は LOGGING。後から NOLOGGING + PARALLEL で再作成した方が速い
不要インデックスの整理 移行先で不要なインデックスを見直す機会になる
エクスポートファイルの削減 インデックス DDL を含まない分、ダンプファイルがわずかに小さくなる

EXCLUDE=INDEX で全インデックスを除外する

expdp で除外(エクスポート時)

Shell(expdp: インデックスを除外)
# インデックスを除外してエクスポート
expdp hr/password \
    directory=DP_DIR \
    dumpfile=hr_no_index_%U.dmp \
    logfile=hr_no_index_exp.log \
    schemas=HR \
    exclude=INDEX \
    parallel=4

# ダンプにインデックス DDL が含まれない
# → impdp でもインデックスは作成されない

impdp で除外(インポート時)

Shell(impdp: インデックスを除外)
# ダンプにインデックスが含まれていても、インポート時に除外
impdp hr/password \
    directory=DP_DIR \
    dumpfile=hr_full_%U.dmp \
    logfile=hr_no_index_imp.log \
    schemas=HR \
    exclude=INDEX \
    parallel=4

# expdp 時に除外してもよいし、impdp 時に除外してもよい
# impdp 時に除外する方が柔軟(同じダンプで再利用可能)
expdp と impdp のどちらで除外すべきか
impdp 側で除外する方が推奨です。理由は以下の通りです。
・同じダンプファイルを「インデックスあり」「インデックスなし」の両方で使える
・後から sqlfile でインデックス DDL だけ抽出して再作成できる
・expdp で除外するとダンプからインデックス情報が完全に失われる

特定のインデックスだけ除外する

Shell(名前指定で特定インデックスを除外)
# 特定のインデックスだけ除外(IN 句で名前指定)
impdp hr/password \
    directory=DP_DIR \
    dumpfile=hr_full.dmp \
    schemas=HR \
    exclude=INDEX:\"IN ('IDX_EMP_DEPT', 'IDX_EMP_NAME')\"
parfile(parfile で指定: クォート問題を回避)
# exclude_index.par
directory=DP_DIR
dumpfile=hr_full.dmp
logfile=exclude_specific.log
schemas=HR
exclude=INDEX:"IN ('IDX_EMP_DEPT', 'IDX_EMP_NAME')"
Shell(LIKE パターンで除外)
# IDX_TMP_ で始まるインデックスだけ除外
impdp hr/password \
    directory=DP_DIR \
    dumpfile=hr_full.dmp \
    schemas=HR \
    exclude=INDEX:\"LIKE 'IDX_TMP_%'\"

INCLUDE で特定インデックスだけ含める(逆パターン)

Shell(特定インデックスだけインポート)
# インデックスだけインポート(テーブルデータなし)
impdp hr/password \
    directory=DP_DIR \
    dumpfile=hr_full.dmp \
    schemas=HR \
    include=INDEX

# ※ EXCLUDE と INCLUDE は同時に使えない

PK / UNIQUE 制約とインデックスの関係

EXCLUDE 指定 除外されるもの PK / UNIQUE のインデックス
EXCLUDE=INDEX 通常インデックスのみ 除外されない(制約と連動して自動作成)
EXCLUDE=INDEX,CONSTRAINT 通常インデックス + 全制約 制約ごと除外(インデックスも消える)
EXCLUDE=CONSTRAINT 全制約 PK / UNIQUE / FK / CHECK が除外される
EXCLUDE=INDEX だけでは PK / UNIQUE のインデックスは除外されない
PRIMARY KEY / UNIQUE 制約のインデックスは制約と連動して作成されるため、EXCLUDE=INDEX では除外されません。PK / UNIQUE インデックスも除外したい場合は EXCLUDE=INDEX,CONSTRAINT にしますが、制約自体も消えるため、インポート後に制約を手動で再作成する必要があります。
SQL(PK/UNIQUE インデックスの確認)
-- 制約に紐づくインデックスの確認
SELECT c.constraint_name, c.constraint_type,
       c.index_name, c.table_name
FROM user_constraints c
WHERE c.index_name IS NOT NULL
ORDER BY c.table_name;
-- constraint_type: P=PRIMARY KEY, U=UNIQUE

sqlfile でインデックス DDL を抽出する

ダンプファイルからインデックスの DDL だけを SQL ファイルに出力できます。インポート時にインデックスを除外し、後からこの DDL を実行して再作成する戦略に使います。

Shell(インデックス DDL を抽出)
# ダンプからインデックスの CREATE INDEX 文だけ出力
impdp hr/password \
    directory=DP_DIR \
    dumpfile=hr_full.dmp \
    include=INDEX \
    sqlfile=index_ddl.sql

# index_ddl.sql の内容:
# CREATE INDEX "HR"."IDX_EMP_DEPT" ON "HR"."EMPLOYEES" ("DEPARTMENT_ID") ...
# CREATE INDEX "HR"."IDX_EMP_NAME" ON "HR"."EMPLOYEES" ("LAST_NAME") ...

# 抽出した DDL を編集して NOLOGGING / PARALLEL を追加してから実行
sqlfile + 手動再作成が最も柔軟な方法
(1) impdp でインデックスを除外してデータだけインポート
(2) sqlfile でインデックス DDL を抽出
(3) DDL を編集して NOLOGGING / PARALLEL / ONLINE を追加
(4) 編集した DDL を実行してインデックスを高速再作成
この手順が移行時間を最も短縮できるパターンです。

インポート後のインデックス高速再作成

SQL(NOLOGGING + PARALLEL でインデックスを高速作成)
-- 通常の CREATE INDEX(遅い)
CREATE INDEX idx_emp_dept ON employees (department_id);

-- NOLOGGING + PARALLEL で高速作成
CREATE INDEX idx_emp_dept ON employees (department_id)
    NOLOGGING PARALLEL 4;

-- 作成後に LOGGING + NOPARALLEL に戻す(RMAN バックアップのため)
ALTER INDEX idx_emp_dept LOGGING;
ALTER INDEX idx_emp_dept NOPARALLEL;

-- ONLINE オプション(テーブルへの DML を許可しながら作成)
CREATE INDEX idx_emp_dept ON employees (department_id)
    NOLOGGING PARALLEL 4 ONLINE;
SQL(全インデックスを一括で高速再作成する PL/SQL)
-- sqlfile で抽出した DDL を元に一括実行するスクリプト
-- 方法: DBMS_METADATA でインデックス DDL を取得して NOLOGGING + PARALLEL を付与
BEGIN
    FOR rec IN (
        SELECT index_name FROM user_indexes
        WHERE index_name NOT IN (
            SELECT index_name FROM user_constraints WHERE index_name IS NOT NULL
        )  -- PK/UNIQUE 以外
    ) LOOP
        -- 既存インデックスがあれば一旦削除して再作成
        BEGIN
            EXECUTE IMMEDIATE 'DROP INDEX ' || rec.index_name;
        EXCEPTION WHEN OTHERS THEN NULL;
        END;
    END LOOP;
END;
/

-- その後、sqlfile で抽出した DDL に NOLOGGING PARALLEL 4 を追加して実行
-- @/oracle/dpdir/index_ddl_nologging.sql
オプション 効果 注意点
NOLOGGING REDO ログを最小化して高速作成 クラッシュ時に復旧不可。作成後にフルバックアップが必要
PARALLEL N N プロセスで並列にインデックスを作成 CPU / I/O リソースを消費
ONLINE テーブルへの DML を許可しながら作成 追加のオーバーヘッドでやや遅くなるが、可用性を維持

transform パラメータでストレージ属性を変換する

Shell(transform でインデックスの属性を制御)
# SEGMENT_ATTRIBUTES:N で元のストレージ属性を無視
# → デフォルトの表領域・エクステントサイズで作成される
impdp hr/password \
    directory=DP_DIR \
    dumpfile=hr_full.dmp \
    schemas=HR \
    transform=SEGMENT_ATTRIBUTES:N

# DISABLE_ARCHIVE_LOGGING:Y で NOLOGGING インポート(12c+)
impdp hr/password \
    directory=DP_DIR \
    dumpfile=hr_full.dmp \
    schemas=HR \
    transform=DISABLE_ARCHIVE_LOGGING:Y
transform 値 効果
SEGMENT_ATTRIBUTES:N 元の TABLESPACE / STORAGE 句を無視(移行先のデフォルトを使用)
STORAGE:N STORAGE 句のみ無視(TABLESPACE は維持)
DISABLE_ARCHIVE_LOGGING:Y インポート時のアーカイブログを抑制(12c+)

インデックス以外に除外できるオブジェクト

EXCLUDE 値 除外対象 除外する理由
INDEX 通常インデックス インポート高速化。後から再作成
CONSTRAINT PK / UNIQUE / FK / CHECK 制約 外部キーでインポートエラーが出る場合
REF_CONSTRAINT 外部キー制約のみ FK だけ除外して PK / UNIQUE は維持
TRIGGER トリガー インポート中にトリガーを発火させたくない場合
STATISTICS 統計情報 インポート後に再収集する場合
GRANT 権限付与 本番権限を持ち込みたくない場合
Shell(インデックス + 統計情報 + トリガーを除外: 最速パターン)
# 移行時間を最短にする組み合わせ
impdp system/password \
    directory=DP_DIR \
    dumpfile=hr_full_%U.dmp \
    schemas=HR \
    exclude=INDEX \
    exclude=STATISTICS \
    exclude=TRIGGER \
    parallel=4 \
    transform=DISABLE_ARCHIVE_LOGGING:Y

# インポート後に:
# (1) インデックスを NOLOGGING + PARALLEL で再作成
# (2) DBMS_STATS.GATHER_SCHEMA_STATS で統計収集
# (3) ALTER TABLE ... ENABLE ALL TRIGGERS でトリガー有効化

実務パターン集

パターン(1): 大規模テーブルの高速移行

Shell
# (1) エクスポート(通常通り)
expdp system/password \
    directory=DP_DIR \
    dumpfile=big_table_%U.dmp \
    tables=HR.LARGE_TABLE \
    parallel=4 compression=ALL

# (2) インデックス除外でインポート
impdp system/password \
    directory=DP_DIR \
    dumpfile=big_table_%U.dmp \
    exclude=INDEX exclude=STATISTICS \
    parallel=4 transform=DISABLE_ARCHIVE_LOGGING:Y

# (3) インデックス DDL を抽出
impdp system/password \
    directory=DP_DIR \
    dumpfile=big_table_%U.dmp \
    include=INDEX sqlfile=index_ddl.sql

# (4) DDL に NOLOGGING PARALLEL 4 を追加して実行
# @index_ddl_nologging.sql

# (5) 統計収集
# EXEC DBMS_STATS.GATHER_TABLE_STATS('HR', 'LARGE_TABLE');

パターン(2): 検証環境にインデックスなしでコピー

Shell
# 検証環境にはインデックスなしでコピー(テスト用)
impdp system/password \
    directory=DP_DIR \
    dumpfile=hr_full_%U.dmp \
    remap_schema=HR:TEST_HR \
    exclude=INDEX exclude=TRIGGER exclude=GRANT \
    parallel=4

# 検証に必要なインデックスだけ手動で作成

パターン(3): FK 制約でエラーが出る場合の対処

Shell
# FK 制約でインポートエラーが出る場合
# → FK だけ除外(PK は維持)
impdp system/password \
    directory=DP_DIR \
    dumpfile=hr_full_%U.dmp \
    schemas=HR \
    exclude=REF_CONSTRAINT

# インポート後に FK を手動で追加
# ALTER TABLE order_items ADD CONSTRAINT fk_oi_order
#     FOREIGN KEY (order_id) REFERENCES orders (order_id);

よくある質問

QEXCLUDE=INDEX で PK のインデックスも除外されますか?
Aされません。PK / UNIQUE 制約のインデックスは制約と連動して作成されるため、EXCLUDE=INDEX では除外対象外です。PK インデックスも除外したい場合は EXCLUDE=INDEX,CONSTRAINT を指定しますが、制約自体も消えるのでインポート後に手動で再作成が必要です。
Qexpdp と impdp のどちらで EXCLUDE すべきですか?
Aimpdp 側で EXCLUDE する方が推奨です。expdp で除外するとダンプからインデックス情報が完全に失われ、後から sqlfile でインデックス DDL を抽出できなくなります。impdp 側で除外すれば、同じダンプを別の用途にも再利用できます。
Qインデックスを除外するとどのくらい速くなりますか?
Aテーブルサイズとインデックス数によりますが、インポート時間が 30%〜70% 短縮されるケースが一般的です。特にインデックスが 5 個以上ある大テーブルでは効果が顕著です。後から NOLOGGING + PARALLEL で再作成すれば、インデックス込みの通常インポートよりも合計時間が短くなることが多いです。
QEXCLUDE=INDEX と EXCLUDE=CONSTRAINT の違いは?
AEXCLUDE=INDEX通常インデックスのみ除外(PK/UNIQUE のインデックスは残る)。EXCLUDE=CONSTRAINT全制約(PK / UNIQUE / FK / CHECK)を除外。両方指定(EXCLUDE=INDEX,CONSTRAINT)で通常インデックス + 全制約 + PK/UNIQUE インデックスが除外されます。
QNOLOGGING で作成したインデックスは RMAN で復旧できますか?
ANOLOGGING で作成した直後は REDO ログに記録されていないため、メディアリカバリ時に復旧できません。インデックス作成後に ALTER INDEX ... LOGGING に戻し、フルバックアップを取得してください。または、インデックスの DDL を保存しておけば再作成で対応できます。
Qインデックスだけ後からインポートできますか?
Aはい。INCLUDE=INDEX を指定すれば、同じダンプからインデックスだけインポートできます。
impdp ... include=INDEX
ただしテーブルが既に存在している必要があります。

まとめ

Data Pump でのインデックス除外・再作成の要点をまとめます。

やりたいこと パラメータ / コマンド
全インデックスを除外してインポート impdp … exclude=INDEX
特定インデックスだけ除外 exclude=INDEX:”IN (‘IDX_NAME’)”(parfile 推奨)
PK/UNIQUE インデックスも除外 exclude=INDEX,CONSTRAINT
FK 制約だけ除外 exclude=REF_CONSTRAINT
インデックス DDL を抽出 impdp … include=INDEX sqlfile=index_ddl.sql
高速再作成 CREATE INDEX … NOLOGGING PARALLEL N [ONLINE]
作成後に LOGGING に戻す ALTER INDEX idx LOGGING; ALTER INDEX idx NOPARALLEL
最速インポートの組み合わせ exclude=INDEX,STATISTICS,TRIGGER + transform=DISABLE_ARCHIVE_LOGGING:Y

Data Pump の基本は「Data Pump の使い方完全ガイド」、インデックスの作成・管理は「インデックスの作成・再構築・削除完全ガイド」も併せて参照してください。