Data Pump でスキーマやテーブルをインポートする際、インデックスの作成に全体の 50% 以上の時間がかかることがあります。インデックスを除外してインポートし、後から NOLOGGING + PARALLEL で再作成すれば、移行時間を大幅に短縮できます。
本記事では、EXCLUDE=INDEX で全インデックスを除外する方法、特定のインデックスだけ除外する方法、PK / UNIQUE 制約のインデックスの扱い、sqlfile でインデックス DDL だけを抽出する方法、そしてインポート後の高速インデックス再作成手順まで解説します。
この記事でわかること
・EXCLUDE=INDEX で全インデックスを除外する方法(expdp / impdp)
・特定のインデックスだけ除外する方法(名前指定 / LIKE パターン)
・PK / UNIQUE 制約とインデックスの関係
・sqlfile でダンプからインデックス DDL だけ抽出する方法
・インポート後にインデックスを NOLOGGING + PARALLEL で高速再作成する手順
・transform パラメータでストレージ属性を変換する方法
・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 で除外するとダンプからインデックス情報が完全に失われる
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 制約のインデックスは制約と連動して作成されるため、
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 を実行してインデックスを高速再作成
この手順が移行時間を最も短縮できるパターンです。
(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 の違いは?
A
EXCLUDE=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 の使い方完全ガイド」、インデックスの作成・管理は「インデックスの作成・再構築・削除完全ガイド」も併せて参照してください。

