見出し画像

OracleDB検証 | Oracle Data Dump expdp/impdp の動作検証

はじめに

はじめまして、SHIFT でインフラコンサルタントをしている k.toku です。

システム更改プロジェクトにおいて、現行のデータセンターから Oracle Database のデータを新データセンターへ移行するため、Oracle Data Pump のコマンドライン・クライアントである expdp/impdp を使う必要がありました。
本プロジェクトでは過去にも同様のデータ移行を行った経験がありましたが、当時はまだ Oracle のバージョンが低かったために exp/imp を使用しており、プロジェクトとしては expdp/impdp 使用する初めてのケースとなりました。
ところが、この expdp/impdp、調べてみるとかなり奥が深いことが判明。ディレクトリオブジェクト権限の適切な設定と、コマンドオプションの適切な設定が必要であることが分かり、事前に環境を準備し、動作を検証してみることにしました。

環境構築については、n.hik 氏執筆の「OracleDB検証 | ローカルPCにOracleDB検証環境を導入」を参照ください。ここではその環境の上で行った動作検証について記述していきます。

準備作業編

システム権限でデータベースに接続後、ユーザ DUMP_TESTUSER を作成し、CONNECT 権限、CREATE TABLE 権限を付与し、表領域 USERS を使えるようにします。 また、ディレクトリオブジェクト DIROBJ を定義します。

※以下のコマンド群は、sys (SYSDBA) でデータベースに接続したウ ンドウ、ユーザ DUMP_TESTUSER でデータベースに接続したウィンドウ、OS シェルプロンプトの 3種類のウィンドウを使い分ける必要がありますので、
それぞれ、段落の直前に (sys)、(DUMP_TESTUSER)、(OS) と表記することで区別します。

(sys)

# sqlplus sys/XXXXXXXX@XEPDB1 AS SYSDBA
SQL*Plus: Release 18.0.0.0.0 - Production on Wed Jul 27 02:34:54 2022
Version 18.4.0.0.0
Copyright (c) 1982, 2018, Oracle.  All rights reserved.
Connected to:
Oracle Database 18c Express Edition Release 18.0.0.0.0 - Production
Version 18.4.0.0.0

SQL> CREATE USER DUMP_TESTUSER IDENTIFIED BY "XXXXXXXX" DEFAULT TABLESPACE USERS TEMPORARY TABLESPACE TEMP;
User created.

SQL> GRANT CONNECT TO DUMP_TESTUSER;
Grant succeeded.

SQL> GRANT CREATE TABLE TO DUMP_TESTUSER;
Grant succeeded.

SQL> ALTER USER DUMP_TESTUSER QUOTA UNLIMITED ON USERS;
User altered.

SQL> CREATE OR REPLACE DIRECTORY DIROBJ AS '/opt/oracle/oradata/work/dirobj';
Directory created.

ユーザ DUMP_TESTUSER で接続後、テーブル TESTTABLE を作成し、レコードを追加します。

(DUMP_TESTUSER)

# sqlplus DUMP_TESTUSER/XXXXXXXX@XEPDB1;
SQL*Plus: Release 18.0.0.0.0 - Production on Wed Jul 27 02:35:36 2022
Version 18.4.0.0.0
Copyright (c) 1982, 2018, Oracle.  All rights reserved.
Connected to:
Oracle Database 18c Express Edition Release 18.0.0.0.0 - Production
Version 18.4.0.0.0

SQL> CREATE TABLE TESTTABLE (
2 VAR1 NUMBER(8),
3 VAR2 NUMBER(8)
4 );
Table created.

SQL> INSERT INTO TESTTABLE VALUES ('1000','10');
1 row created.

SQL> COMMIT;
Commit complete.

SQL> SELECT * FROM TESTTABLE;
      VAR1       VAR2
---------- ----------
      1000         10

テーブルが作成され、レコードが追加されていることが確認できました。

エクスポート編

ここからは expdp を使ったエクスポートを実行してみます。
まず、ディレクトリオブジェクト DITOBJ への READ 権限および WRITE 権限をユーザ DUMP_TESTUSER に付与します。
(sys)

SQL> GRANT READ, WRITE ON DIRECTORY DIROBJ TO DUMP_TESTUSER;
Grant succeeded.

SQL> COLUMN GRANTEE FORMAT A15
SQL> COLUMN TABLE_NAME FORMAT A15
SQL> COLUMN PRIVILEGE FORMAT A20
SQL> SELECT GRANTEE, TABLE_NAME, PRIVILEGE FROM DBA_TAB_PRIVS WHERE TABLE_NAME='DIROBJ';
GRANTEE         TABLE_NAME      PRIVILEGE
--------------- --------------- --------------------
DUMP_TESTUSER   DIROBJ          READ
DUMP_TESTUSER   DIROBJ          WRITE

権限が付与されました。この状態でエクスポートを実行します。
なお、expdp コマンドの引数、オプションの意味は以下の通りです。

DUMP_TESTUSER/XXXXXXXX: ユーザ/パスワード
XEPDB1: 接続文字列(データベースインスタンス)
TABLES: インポート対象テーブル(テーブル単位でエクスポートするときに指定)
DIRECTORY: エクスポート先のディレクトリオブジェクト
DUMPFILE: ダンプファイル名
LOGFILE: ログファイル名

(OS)

# expdp DUMP_TESTUSER/XXXXXXXX@XEPDB1 TABLES=TESTTABLE DIRECTORY=DIROBJ DUMPFILE=data.dmp LOGFILE=export.log
Export: Release 18.0.0.0.0 - Production on Wed Jul 27 02:37:03 2022
Version 18.4.0.0.0
Copyright (c) 1982, 2018, Oracle and/or its affiliates.  All rights reserved.
Connected to: Oracle Database 18c Express Edition Release 18.0.0.0.0 - Production
Starting "DUMP_TESTUSER"."SYS_EXPORT_TABLE_01":  DUMP_TESTUSER/********@XEPDB1 TABLES=TESTTABLE DIRECTORY=DIROBJ DUMPFILE=data.dmp LOGFILE=export.log 
Processing object type TABLE_EXPORT/TABLE/TABLE_DATA
Processing object type TABLE_EXPORT/TABLE/STATISTICS/TABLE_STATISTICS
Processing object type TABLE_EXPORT/TABLE/STATISTICS/MARKER
Processing object type TABLE_EXPORT/TABLE/TABLE
. . exported "DUMP_TESTUSER"."TESTTABLE"                 5.585 KB       1 rows
Master table "DUMP_TESTUSER"."SYS_EXPORT_TABLE_01" successfully loaded/unloaded
******************************************************************************
Dump file set for DUMP_TESTUSER.SYS_EXPORT_TABLE_01 is:
  /opt/oracle/oradata/work/dirobj/data.dmp
Job "DUMP_TESTUSER"."SYS_EXPORT_TABLE_01" successfully completed at Wed Jul 27 02:37:27 2022 elapsed 0 00:00:20

# ls -l
total 176
-rw-r----- 1 oracle oinstall 176128 Jul 27 02:37 data.dmp
-rw-r----- 1 oracle oinstall   1089 Jul 27 02:37 export.log

エクスポートに成功し、ダンプファイル、ログファイルが作成されていることが確認できました。
さてここで、DUMP_TESTUSER から READ, WRITE 権限を剥奪して expdp を実行してみることにします。
(sys)

SQL> REVOKE READ, WRITE ON DIRECTORY DIROBJ FROM DUMP_TESTUSER;
Revoke succeeded.

SQL> SELECT GRANTEE, TABLE_NAME, PRIVILEGE FROM DBA_TAB_PRIVS WHERE TABLE_NAME='DIROBJ';
no rows selected

(OS)

# expdp DUMP_TESTUSER/XXXXXXXX@XEPDB1 TABLES=TESTTABLE DIRECTORY=DIROBJ DUMPFILE=data1.dmp LOGFILE=export1.log
Export: Release 18.0.0.0.0 - Production on Wed Jul 27 02:38:14 2022
Version 18.4.0.0.0
Copyright (c) 1982, 2018, Oracle and/or its affiliates.  All rights reserved.
Connected to: Oracle Database 18c Express Edition Release 18.0.0.0.0 - Production
ORA-39002: invalid operation
ORA-39070: Unable to open the log file.
ORA-39087: directory name DIROBJ is invalid

# ls -l
total 176
-rw-r----- 1 oracle oinstall 176128 Jul 27 02:37 data.dmp
-rw-r----- 1 oracle oinstall   1089 Jul 27 02:37 export.log

READ, WRITE 権限がなくなると expdp に失敗することが確認できました。またこのとき、ダンプファイル (data1.dmp)、ログファイル (export1.log) とも作成されていません。
(ログファイルでは失敗は確認できないということですね。)
さて、READ, WRITE 権限はどちらも expdp に必要なのでしょうか? エクスポートなので WRITE 権限だけあれば成功するように思えますが、それぞれ片方だけ付けて実行してみることにします。まずは READ 権限から。
(sys)

SQL> GRANT READ ON DIRECTORY DIROBJ TO DUMP_TESTUSER;
Grant succeeded.

SQL> SELECT GRANTEE, TABLE_NAME, PRIVILEGE FROM DBA_TAB_PRIVS WHERE TABLE_NAME='DIROBJ';
GRANTEE         TABLE_NAME      PRIVILEGE
--------------- --------------- --------------------
DUMP_TESTUSER   DIROBJ          READ

(OS)

# expdp DUMP_TESTUSER/XXXXXXXX@XEPDB1 TABLES=TESTTABLE DIRECTORY=DIROBJ DUMPFILE=data1.dmp LOGFILE=export1.log
Export: Release 18.0.0.0.0 - Production on Wed Jul 27 02:38:43 2022
Version 18.4.0.0.0
Copyright (c) 1982, 2018, Oracle and/or its affiliates.  All rights reserved.
Connected to: Oracle Database 18c Express Edition Release 18.0.0.0.0 - Production
ORA-39002: invalid operation
ORA-39070: Unable to open the log file.
ORA-31631: privileges are required

# ls -l
total 176
-rw-r----- 1 oracle oinstall 176128 Jul 27 02:37 data.dmp
-rw-r----- 1 oracle oinstall   1089 Jul 27 02:37 export.log

エクスポートに失敗しました。なお、先の READ, WRITE 両権限がないときと比べて、3つ目のエラーが ORA-39087: directory name DIROBJ is invalid(=ディレクトリオブジェクト名が無効)から ORA-31631: privileges are required(=特権が必要)に変わっているのが確認できます。
次に WRITE 権限のみにして実行してみます。
(sys)

SQL> REVOKE READ ON DIRECTORY DIROBJ FROM DUMP_TESTUSER;
Revoke succeeded.

SQL> GRANT WRITE ON DIRECTORY DIROBJ TO DUMP_TESTUSER;
Grant succeeded.

SQL> SELECT GRANTEE, TABLE_NAME, PRIVILEGE FROM DBA_TAB_PRIVS WHERE TABLE_NAME='DIROBJ';
GRANTEE         TABLE_NAME      PRIVILEGE
--------------- --------------- --------------------
DUMP_TESTUSER   DIROBJ          WRITE

(OS)

# expdp DUMP_TESTUSER/XXXXXXXX@XEPDB1 TABLES=TESTTABLE DIRECTORY=DIROBJ DUMPFILE=data1.dmp LOGFILE=export1.log
Export: Release 18.0.0.0.0 - Production on Wed Jul 27 02:39:19 2022
Version 18.4.0.0.0

Copyright (c) 1982, 2018, Oracle and/or its affiliates.  All rights reserved.

Connected to: Oracle Database 18c Express Edition Release 18.0.0.0.0 - Production
ORA-39002: invalid operation
ORA-39070: Unable to open the log file.
ORA-31631: privileges are required

# ls -l
total 176
-rw-r----- 1 oracle oinstall 176128 Jul 27 02:37 data.dmp
-rw-r----- 1 oracle oinstall   1089 Jul 27 02:37 export.log

同じく、WRITE 権限のみでは失敗しました。3つ目のエラーは READ 権限のみのときに同じ ORA-31631 でした。
expdp のためにはユーザに対するディレクトリオブジェクト権限として、READ, WRITE の両方とも必要であることが確認できました。
さてここで、後で使うダンプファイル (data2.dmp) を作成するための準備を先にしておきます。
(DUMP_TESTUSER)

SQL> INSERT INTO TESTTABLE VALUES ('2000','20');
1 row created.

SQL> COMMIT;
Commit complete.

SQL> SELECT * FROM TESTTABLE;
      VAR1       VAR2
---------- ----------
      1000         10
      2000         20

expdp でもう1点、特定のユーザ (DUMP_TESTUSER) ではなく、PUBLIC に対する READ, WRITE 権限による expdp の実行可否について確認しておきます。PUBLIC に権限を与えることで一般ユーザ自身に権限が無くても expdp/impdp が実行可能かの確認です。
(sys)

SQL> REVOKE WRITE ON DIRECTORY DIROBJ FROM DUMP_TESTUSER;
Revoke succeeded.

SQL> SELECT GRANTEE, TABLE_NAME, PRIVILEGE FROM DBA_TAB_PRIVS WHERE TABLE_NAME='DIROBJ';
no rows selected

SQL> GRANT READ, WRITE ON DIRECTORY DIROBJ TO PUBLIC;
Grant succeeded.

SQL> SELECT GRANTEE, TABLE_NAME, PRIVILEGE FROM DBA_TAB_PRIVS WHERE TABLE_NAME='DIROBJ';
GRANTEE         TABLE_NAME      PRIVILEGE
--------------- --------------- --------------------
PUBLIC          DIROBJ          READ
PUBLIC          DIROBJ          WRITE

(OS)

# expdp DUMP_TESTUSER/XXXXXXXX@XEPDB1 TABLES=TESTTABLE DIRECTORY=DIROBJ DUMPFILE=data2.dmp LOGFILE=export2.log
Export: Release 18.0.0.0.0 - Production on Wed Jul 27 02:40:32 2022
Version 18.4.0.0.0
Copyright (c) 1982, 2018, Oracle and/or its affiliates.  All rights reserved.
Connected to: Oracle Database 18c Express Edition Release 18.0.0.0.0 - Production
Starting "DUMP_TESTUSER"."SYS_EXPORT_TABLE_01":  DUMP_TESTUSER/********@XEPDB1 TABLES=TESTTABLE DIRECTORY=DIROBJ DUMPFILE=data2.dmp LOGFILE=export2.log 
Processing object type TABLE_EXPORT/TABLE/TABLE_DATA
Processing object type TABLE_EXPORT/TABLE/STATISTICS/TABLE_STATISTICS
Processing object type TABLE_EXPORT/TABLE/STATISTICS/MARKER
Processing object type TABLE_EXPORT/TABLE/TABLE
. . exported "DUMP_TESTUSER"."TESTTABLE"                 5.593 KB       2 rows
Master table "DUMP_TESTUSER"."SYS_EXPORT_TABLE_01" successfully loaded/unloaded
******************************************************************************
Dump file set for DUMP_TESTUSER.SYS_EXPORT_TABLE_01 is:
  /opt/oracle/oradata/work/dirobj/data2.dmp
Job "DUMP_TESTUSER"."SYS_EXPORT_TABLE_01" successfully completed at Wed Jul 27 02:40:50 2022 elapsed 0 00:00:16

# ls -l
total 356
-rw-r----- 1 oracle oinstall 176128 Jul 27 02:37 data.dmp
-rw-r----- 1 oracle oinstall 176128 Jul 27 02:40 data2.dmp
-rw-r----- 1 oracle oinstall   1089 Jul 27 02:37 export.log
-rw-r----- 1 oracle oinstall   1092 Jul 27 02:40 export2.log

PUBLIC に対する READ, WRITE 権限でもエクスポートに成功することが確認できました。
ここで、このあとに実施するインポート編の準備として、テーブルの削除、および、PUBLIC に対する READ, WRITE 権限の剥奪をしておきます。
(DUMP_TESTUSER)

SQL> DROP TABLE TESTTABLE;
Table dropped.

SQL> SELECT TABLE_NAME, TABLESPACE_NAME FROM USER_TABLES ORDER BY TABLE_NAME;
no rows selected

(sys)

SQL> REVOKE READ, WRITE ON DIRECTORY DIROBJ FROM PUBLIC;
Revoke succeeded.

SQL> SELECT GRANTEE, TABLE_NAME, PRIVILEGE FROM DBA_TAB_PRIVS WHERE TABLE_NAME='DIROBJ';
no rows selected

インポート編

まずユーザ DUMP_TESTUSER に何も権限がない状態で impdp を実行してみます。(おそらく失敗します。)
impdp コマンドの引数、オプションの意味は以下の通りです。

DUMP_TESTUSER/XXXXXXXX: ユーザ/パスワード
XEPDB1: 接続文字列(データベースインスタンス)
TABLES: インポート対象テーブル(テーブル単位でエクスポートするときに指定)
DIRECTORY: インポート元のディレクトリオブジェクト
DUMPFILE: ダンプファイル名
LOGFILE: ログファイル名

(OS)

# impdp DUMP_TESTUSER/XXXXXXXX@XEPDB1 TABLES=TESTTABLE DIRECTORY=DIROBJ DUMPFILE=data.dmp LOGFILE=import.log
Import: Release 18.0.0.0.0 - Production on Wed Jul 27 02:41:57 2022
Version 18.4.0.0.0
Copyright (c) 1982, 2018, Oracle and/or its affiliates.  All rights reserved.
Connected to: Oracle Database 18c Express Edition Release 18.0.0.0.0 - Production
ORA-39002: invalid operation
ORA-39070: Unable to open the log file.
ORA-39087: directory name DIROBJ is invalid

# ls -l
total 356
-rw-r----- 1 oracle oinstall 176128 Jul 27 02:37 data.dmp
-rw-r----- 1 oracle oinstall 176128 Jul 27 02:40 data2.dmp
-rw-r----- 1 oracle oinstall   1089 Jul 27 02:37 export.log
-rw-r----- 1 oracle oinstall   1092 Jul 27 02:40 export2.log

予想通りインポートに失敗しました。この場合もログファイル (import.log) は作られないようです。

このあと順に、READ 権限のみ、WRITE 権限のみ、READ, WRITE 両権限、を付与して impdp を実行し、挙動を確認してみることにします。まずは READ 権限のみの場合から。
(sys)

SQL> GRANT READ ON DIRECTORY DIROBJ TO DUMP_TESTUSER;
Grant succeeded.

SQL> SELECT GRANTEE, TABLE_NAME, PRIVILEGE FROM DBA_TAB_PRIVS WHERE TABLE_NAME='DIROBJ';
GRANTEE         TABLE_NAME      PRIVILEGE
--------------- --------------- --------------------
DUMP_TESTUSER   DIROBJ          READ

(OS)

# impdp DUMP_TESTUSER/XXXXXXXX@XEPDB1 TABLES=TESTTABLE DIRECTORY=DIROBJ DUMPFILE=data.dmp LOGFILE=import.log
Import: Release 18.0.0.0.0 - Production on Wed Jul 27 02:42:26 2022
Version 18.4.0.0.0
Copyright (c) 1982, 2018, Oracle and/or its affiliates.  All rights reserved.
Connected to: Oracle Database 18c Express Edition Release 18.0.0.0.0 - Production
ORA-39002: invalid operation
ORA-39070: Unable to open the log file.
ORA-31631: privileges are required

# ls -l
total 356
-rw-r----- 1 oracle oinstall 176128 Jul 27 02:37 data.dmp
-rw-r----- 1 oracle oinstall 176128 Jul 27 02:40 data2.dmp
-rw-r----- 1 oracle oinstall   1089 Jul 27 02:37 export.log
-rw-r----- 1 oracle oinstall   1092 Jul 27 02:40 export2.log

インポートに失敗しました。 expdp のときと同様に、権限がなにも無かったときに比べ 3つ目のエラーが ORA-39087 から ORA-31631 に変わっています。 続いて WRITE 権限のみでやってみます。
(sys)

SQL> REVOKE READ ON DIRECTORY DIROBJ FROM DUMP_TESTUSER;
Revoke succeeded.

SQL> GRANT WRITE ON DIRECTORY DIROBJ TO DUMP_TESTUSER;
Grant succeeded.

SQL> SELECT GRANTEE, TABLE_NAME, PRIVILEGE FROM DBA_TAB_PRIVS WHERE TABLE_NAME='DIROBJ';
GRANTEE         TABLE_NAME      PRIVILEGE
--------------- --------------- --------------------
DUMP_TESTUSER   DIROBJ          WRITE

(OS)

# impdp DUMP_TESTUSER/XXXXXXXX@XEPDB1 TABLES=TESTTABLE DIRECTORY=DIROBJ DUMPFILE=data.dmp LOGFILE=import.log
Import: Release 18.0.0.0.0 - Production on Wed Jul 27 02:42:57 2022
Copyright (c) 1982, 2018, Oracle and/or its affiliates.  All rights reserved.
Connected to: Oracle Database 18c Express Edition Release 18.0.0.0.0 - Production
ORA-39002: invalid operation
ORA-39070: Unable to open the log file.
ORA-31631: privileges are required

# ls -l
total 356
-rw-r----- 1 oracle oinstall 176128 Jul 27 02:37 data.dmp
-rw-r----- 1 oracle oinstall 176128 Jul 27 02:40 data2.dmp
-rw-r----- 1 oracle oinstall   1089 Jul 27 02:37 export.log
-rw-r----- 1 oracle oinstall   1092 Jul 27 02:40 export2.log

同じくインポートに失敗しました。3つ目のエラーは READ 権限のみのときに同じ ORA-31631 です。 最後に READ, WRITE 両権限を付与して impdp を実行してみます。
(sys)

SQL> GRANT READ ON DIRECTORY DIROBJ TO DUMP_TESTUSER;
Grant succeeded.

SQL> SELECT GRANTEE, TABLE_NAME, PRIVILEGE FROM DBA_TAB_PRIVS WHERE TABLE_NAME='DIROBJ';
GRANTEE         TABLE_NAME      PRIVILEGE
--------------- --------------- --------------------
DUMP_TESTUSER   DIROBJ          READ
DUMP_TESTUSER   DIROBJ          WRITE

(OS)

# impdp DUMP_TESTUSER/XXXXXXXX@XEPDB1 TABLES=TESTTABLE DIRECTORY=DIROBJ DUMPFILE=data.dmp LOGFILE=import.log
Import: Release 18.0.0.0.0 - Production on Wed Jul 27 02:43:25 2022
Version 18.4.0.0.0
Copyright (c) 1982, 2018, Oracle and/or its affiliates.  All rights reserved.
Connected to: Oracle Database 18c Express Edition Release 18.0.0.0.0 - Production
Master table "DUMP_TESTUSER"."SYS_IMPORT_TABLE_01" successfully loaded/unloaded
Starting "DUMP_TESTUSER"."SYS_IMPORT_TABLE_01":  DUMP_TESTUSER/********@XEPDB1 TABLES=TESTTABLE DIRECTORY=DIROBJ DUMPFILE=data.dmp LOGFILE=import.log 
Processing object type TABLE_EXPORT/TABLE/TABLE
Processing object type TABLE_EXPORT/TABLE/TABLE_DATA
. . imported "DUMP_TESTUSER"."TESTTABLE"                 5.585 KB       1 rows
Processing object type TABLE_EXPORT/TABLE/STATISTICS/TABLE_STATISTICS
Processing object type TABLE_EXPORT/TABLE/STATISTICS/MARKER
Job "DUMP_TESTUSER"."SYS_IMPORT_TABLE_01" successfully completed at Wed Jul 27 02:43:50 2022 elapsed 0 00:00:24

# ls -l
total 356
-rw-r----- 1 oracle oinstall 176128 Jul 27 02:37 data.dmp
-rw-r----- 1 oracle oinstall 176128 Jul 27 02:40 data2.dmp
-rw-r----- 1 oracle oinstall   1089 Jul 27 02:37 export.log
-rw-r----- 1 oracle oinstall   1092 Jul 27 02:40 export2.log
-rw-r----- 1 oracle oinstall    911 Jul 27 02:43 import.log

impdp も READ, WRITE 権限両方揃って、ようやくインポートに成功しました。 テーブルの中身を確認してみます。
(DUMP_TESTUSER)

SQL> SELECT * FROM TESTTABLE;
      VAR1       VAR2
---------- ----------
      1000         10

テーブルが作成され、データがインポートできていることが確認できました。
続いてエクスポートのときと同様、PUBLIC に対する権限での動きについても確認しておきます。
(sys)

SQL> REVOKE READ, WRITE ON DIRECTORY DIROBJ FROM DUMP_TESTUSER;
Revoke succeeded.

SQL> GRANT READ, WRITE ON DIRECTORY DIROBJ TO PUBLIC;
Grant succeeded.

SQL> SELECT GRANTEE, TABLE_NAME, PRIVILEGE FROM DBA_TAB_PRIVS WHERE TABLE_NAME='DIROBJ';
GRANTEE         TABLE_NAME      PRIVILEGE
--------------- --------------- --------------------
PUBLIC          DIROBJ          READ
PUBLIC          DIROBJ          WRITE

テーブルを削除し、impdp を実行します。
(DUMP_TESTUSER)

SQL> DROP TABLE TESTTABLE;
Table dropped.

SQL> SELECT TABLE_NAME, TABLESPACE_NAME FROM USER_TABLES ORDER BY TABLE_NAME;
no rows selected

(OS)

# impdp DUMP_TESTUSER/XXXXXXXX@XEPDB1 TABLES=TESTTABLE DIRECTORY=DIROBJ DUMPFILE=data.dmp LOGFILE=import2.log
Import: Release 18.0.0.0.0 - Production on Wed Jul 27 02:45:29 2022
Version 18.4.0.0.0
Copyright (c) 1982, 2018, Oracle and/or its affiliates.  All rights reserved.
Connected to: Oracle Database 18c Express Edition Release 18.0.0.0.0 - Production
Master table "DUMP_TESTUSER"."SYS_IMPORT_TABLE_01" successfully loaded/unloaded
Starting "DUMP_TESTUSER"."SYS_IMPORT_TABLE_01":  DUMP_TESTUSER/********@XEPDB1 TABLES=TESTTABLE DIRECTORY=DIROBJ DUMPFILE=data.dmp LOGFILE=import2.log 
Processing object type TABLE_EXPORT/TABLE/TABLE
Processing object type TABLE_EXPORT/TABLE/TABLE_DATA
. . imported "DUMP_TESTUSER"."TESTTABLE"                 5.585 KB       1 rows
Processing object type TABLE_EXPORT/TABLE/STATISTICS/TABLE_STATISTICS
Processing object type TABLE_EXPORT/TABLE/STATISTICS/MARKER
Job "DUMP_TESTUSER"."SYS_IMPORT_TABLE_01" successfully completed at Wed Jul 27 02:45:53 2022 elapsed 0 00:00:21

# ls -l
total 356
-rw-r----- 1 oracle oinstall 176128 Jul 27 02:37 data.dmp
-rw-r----- 1 oracle oinstall 176128 Jul 27 02:40 data2.dmp
-rw-r----- 1 oracle oinstall   1089 Jul 27 02:37 export.log
-rw-r----- 1 oracle oinstall   1092 Jul 27 02:40 export2.log
-rw-r----- 1 oracle oinstall    911 Jul 27 02:43 import.log
-rw-r----- 1 oracle oinstall    912 Jul 27 02:45 import2.log

(DUMP_TESTUSER)

SQL> SELECT * FROM TESTTABLE;
      VAR1       VAR2
---------- ----------
      1000         10

インポートに成功しました。

このテーブルが存在する状態で再度 impdp を実行してみます。
インポートファイルは impdp 後のテーブルがどのように変わるか確認できるよう data2.dmp を使います。
(OS)

# impdp DUMP_TESTUSER/XXXXXXXX@XEPDB1 TABLES=TESTTABLE DIRECTORY=DIROBJ DUMPFILE=data2.dmp LOGFILE=import3.log
Import: Release 18.0.0.0.0 - Production on Wed Jul 27 02:46:26 2022
Version 18.4.0.0.0
Copyright (c) 1982, 2018, Oracle and/or its affiliates.  All rights reserved.
Connected to: Oracle Database 18c Express Edition Release 18.0.0.0.0 - Production
Master table "DUMP_TESTUSER"."SYS_IMPORT_TABLE_01" successfully loaded/unloaded
Starting "DUMP_TESTUSER"."SYS_IMPORT_TABLE_01":  DUMP_TESTUSER/********@XEPDB1 TABLES=TESTTABLE DIRECTORY=DIROBJ DUMPFILE=data2.dmp LOGFILE=import3.log 
Processing object type TABLE_EXPORT/TABLE/TABLE
ORA-39151: Table "DUMP_TESTUSER"."TESTTABLE" exists. All dependent metadata and data will be skipped due to table_exists_action of skip
Processing object type TABLE_EXPORT/TABLE/TABLE_DATA
Processing object type TABLE_EXPORT/TABLE/STATISTICS/TABLE_STATISTICS
Processing object type TABLE_EXPORT/TABLE/STATISTICS/MARKER
Job "DUMP_TESTUSER"."SYS_IMPORT_TABLE_01" completed with 1 error(s) at Wed Jul 27 02:46:32 2022 elapsed 0 00:00:04

# ls -l
total 356
-rw-r----- 1 oracle oinstall 176128 Jul 27 02:37 data.dmp
-rw-r----- 1 oracle oinstall 176128 Jul 27 02:40 data2.dmp
-rw-r----- 1 oracle oinstall   1089 Jul 27 02:37 export.log
-rw-r----- 1 oracle oinstall   1092 Jul 27 02:40 export2.log
-rw-r----- 1 oracle oinstall    911 Jul 27 02:43 import.log
-rw-r----- 1 oracle oinstall    912 Jul 27 02:45 import2.log
-rw-r----- 1 oracle oinstall    973 Jul 27 02:46 import3.log

(DUMP_TESTUSER)

SQL> SELECT * FROM TESTTABLE;
      VAR1       VAR2
---------- ----------
      1000         10

テーブルの値は impdp 実行前と変わりません。つまり、インポートはスキップされたことになります。

さてここからは、impdp のオプションの1つである TABLE_EXISTS_ACTION について、その指定値による動きの違いについて見ていくことにします。 TABLE_EXISTS_ACTION オプションは名前の通り、すでにテーブルが存在する場合に impdp の挙動を制御するものです。

まずは TABLE_EXISTS_ACTION=TRUNCATE を試してみます。 上記のテーブルの状態で data2.dmp を TRUNCATE でインポートしてみます。
(OS)

# impdp DUMP_TESTUSER/XXXXXXXX@XEPDB1 TABLES=TESTTABLE DIRECTORY=DIROBJ DUMPFILE=data2.dmp LOGFILE=import4.log TABLE_EXISTS_ACTION=TRUNCATE
Import: Release 18.0.0.0.0 - Production on Wed Jul 27 02:47:07 2022
Version 18.4.0.0.0
Copyright (c) 1982, 2018, Oracle and/or its affiliates.  All rights reserved.
Connected to: Oracle Database 18c Express Edition Release 18.0.0.0.0 - Production
Master table "DUMP_TESTUSER"."SYS_IMPORT_TABLE_01" successfully loaded/unloaded
Starting "DUMP_TESTUSER"."SYS_IMPORT_TABLE_01":  DUMP_TESTUSER/********@XEPDB1 TABLES=TESTTABLE DIRECTORY=DIROBJ DUMPFILE=data2.dmp LOGFILE=import4.log TABLE_EXISTS_ACTION=TRUNCATE 
Processing object type TABLE_EXPORT/TABLE/TABLE
Table "DUMP_TESTUSER"."TESTTABLE" exists and has been truncated. Data will be loaded but all dependent metadata will be skipped due to table_exists_action of truncate
Processing object type TABLE_EXPORT/TABLE/TABLE_DATA
. . imported "DUMP_TESTUSER"."TESTTABLE"                 5.593 KB       2 rows
Processing object type TABLE_EXPORT/TABLE/STATISTICS/TABLE_STATISTICS
Processing object type TABLE_EXPORT/TABLE/STATISTICS/MARKER
Job "DUMP_TESTUSER"."SYS_IMPORT_TABLE_01" successfully completed at Wed Jul 27 02:47:16 2022 elapsed 0 00:00:07

# ls -l
total 356
-rw-r----- 1 oracle oinstall 176128 Jul 27 02:37 data.dmp
-rw-r----- 1 oracle oinstall 176128 Jul 27 02:40 data2.dmp
-rw-r----- 1 oracle oinstall   1089 Jul 27 02:37 export.log
-rw-r----- 1 oracle oinstall   1092 Jul 27 02:40 export2.log
-rw-r----- 1 oracle oinstall    911 Jul 27 02:43 import.log
-rw-r----- 1 oracle oinstall    912 Jul 27 02:45 import2.log
-rw-r----- 1 oracle oinstall    973 Jul 27 02:46 import3.log
-rw-r----- 1 oracle oinstall   1109 Jul 27 02:47 import4.log

(DUMP_TESTUSER)

SQL> SELECT * FROM TESTTABLE;
      VAR1       VAR2
---------- ----------
      1000         10
      2000         20

インポートに成功し、テーブルの内容が置き換えられていることが確認できます。 次は APPEND を試します。
(OS)

# impdp DUMP_TESTUSER/XXXXXXXX@XEPDB1 TABLES=TESTTABLE DIRECTORY=DIROBJ DUMPFILE=data.dmp LOGFILE=import5.log TABLE_EXISTS_ACTION=APPEND
Import: Release 18.0.0.0.0 - Production on Wed Jul 27 02:47:49 2022
Version 18.4.0.0.0
Copyright (c) 1982, 2018, Oracle and/or its affiliates.  All rights reserved.
Connected to: Oracle Database 18c Express Edition Release 18.0.0.0.0 - Production
Master table "DUMP_TESTUSER"."SYS_IMPORT_TABLE_01" successfully loaded/unloaded
Starting "DUMP_TESTUSER"."SYS_IMPORT_TABLE_01":  DUMP_TESTUSER/********@XEPDB1 TABLES=TESTTABLE DIRECTORY=DIROBJ DUMPFILE=data.dmp LOGFILE=import5.log TABLE_EXISTS_ACTION=APPEND 
Processing object type TABLE_EXPORT/TABLE/TABLE
Table "DUMP_TESTUSER"."TESTTABLE" exists. Data will be appended to existing table but all dependent metadata will be skipped due to table_exists_action of append
Processing object type TABLE_EXPORT/TABLE/TABLE_DATA
. . imported "DUMP_TESTUSER"."TESTTABLE"                 5.585 KB       1 rows
Processing object type TABLE_EXPORT/TABLE/STATISTICS/TABLE_STATISTICS
Processing object type TABLE_EXPORT/TABLE/STATISTICS/MARKER
Job "DUMP_TESTUSER"."SYS_IMPORT_TABLE_01" successfully completed at Wed Jul 27 02:47:58 2022 elapsed 0 00:00:06

# ls -l
total 356
-rw-r----- 1 oracle oinstall 176128 Jul 27 02:37 data.dmp
-rw-r----- 1 oracle oinstall 176128 Jul 27 02:40 data2.dmp
-rw-r----- 1 oracle oinstall   1089 Jul 27 02:37 export.log
-rw-r----- 1 oracle oinstall   1092 Jul 27 02:40 export2.log
-rw-r----- 1 oracle oinstall    911 Jul 27 02:43 import.log
-rw-r----- 1 oracle oinstall    912 Jul 27 02:45 import2.log
-rw-r----- 1 oracle oinstall    973 Jul 27 02:46 import3.log
-rw-r----- 1 oracle oinstall   1109 Jul 27 02:47 import4.log
-rw-r----- 1 oracle oinstall   1101 Jul 27 02:47 import5.log

(DUMP_TESTUSER)

SQL> SELECT * FROM TESTTABLE;
      VAR1       VAR2
---------- ----------
      1000         10
      2000         20
      1000         10

インポートに成功し、テーブルにレコードが追加されたことが確認できます。 次は SKIP を試します。
(OS)

# impdp DUMP_TESTUSER/XXXXXXXX@XEPDB1 TABLES=TESTTABLE DIRECTORY=DIROBJ DUMPFILE=data.dmp LOGFILE=import6.log TABLE_EXISTS_ACTION=SKIP
Import: Release 18.0.0.0.0 - Production on Wed Jul 27 02:48:24 2022
Version 18.4.0.0.0
Copyright (c) 1982, 2018, Oracle and/or its affiliates.  All rights reserved.
Connected to: Oracle Database 18c Express Edition Release 18.0.0.0.0 - Production
Master table "DUMP_TESTUSER"."SYS_IMPORT_TABLE_01" successfully loaded/unloaded
Starting "DUMP_TESTUSER"."SYS_IMPORT_TABLE_01":  DUMP_TESTUSER/********@XEPDB1 TABLES=TESTTABLE DIRECTORY=DIROBJ DUMPFILE=data.dmp LOGFILE=import6.log TABLE_EXISTS_ACTION=SKIP 
Processing object type TABLE_EXPORT/TABLE/TABLE
Table "DUMP_TESTUSER"."TESTTABLE" exists. All dependent metadata and data will be skipped due to table_exists_action of skip
Processing object type TABLE_EXPORT/TABLE/TABLE_DATA
Processing object type TABLE_EXPORT/TABLE/STATISTICS/TABLE_STATISTICS
Processing object type TABLE_EXPORT/TABLE/STATISTICS/MARKER
Job "DUMP_TESTUSER"."SYS_IMPORT_TABLE_01" successfully completed at Wed Jul 27 02:48:27 2022 elapsed 0 00:00:02

# ls -l
total 356
-rw-r----- 1 oracle oinstall 176128 Jul 27 02:37 data.dmp
-rw-r----- 1 oracle oinstall 176128 Jul 27 02:40 data2.dmp
-rw-r----- 1 oracle oinstall   1089 Jul 27 02:37 export.log
-rw-r----- 1 oracle oinstall   1092 Jul 27 02:40 export2.log
-rw-r----- 1 oracle oinstall    911 Jul 27 02:43 import.log
-rw-r----- 1 oracle oinstall    912 Jul 27 02:45 import2.log
-rw-r----- 1 oracle oinstall    973 Jul 27 02:46 import3.log
-rw-r----- 1 oracle oinstall   1109 Jul 27 02:47 import4.log
-rw-r----- 1 oracle oinstall   1101 Jul 27 02:47 import5.log
-rw-r----- 1 oracle oinstall    983 Jul 27 02:48 import6.log

(DUMP_TESTUSER)

SQL> SELECT * FROM TESTTABLE;
      VAR1       VAR2
---------- ----------
      1000         10
      2000         20
      1000         10

インポートはスキップされ、テーブルの内容はそのままです。(実際にこのオプションを使うケースは無さそうに思いますが。)
最後に REPLACE を試します。
(OS)

# impdp DUMP_TESTUSER/XXXXXXXX@XEPDB1 TABLES=TESTTABLE DIRECTORY=DIROBJ DUMPFILE=data2.dmp LOGFILE=import7.log TABLE_EXISTS_ACTION=REPLACE
Import: Release 18.0.0.0.0 - Production on Wed Jul 27 02:49:02 2022
Version 18.4.0.0.0
Copyright (c) 1982, 2018, Oracle and/or its affiliates.  All rights reserved.
Connected to: Oracle Database 18c Express Edition Release 18.0.0.0.0 - Production
Master table "DUMP_TESTUSER"."SYS_IMPORT_TABLE_01" successfully loaded/unloaded
Starting "DUMP_TESTUSER"."SYS_IMPORT_TABLE_01":  DUMP_TESTUSER/********@XEPDB1 TABLES=TESTTABLE DIRECTORY=DIROBJ DUMPFILE=data2.dmp LOGFILE=import7.log TABLE_EXISTS_ACTION=REPLACE 
Processing object type TABLE_EXPORT/TABLE/TABLE
Processing object type TABLE_EXPORT/TABLE/TABLE_DATA
. . imported "DUMP_TESTUSER"."TESTTABLE"                 5.593 KB       2 rows
Processing object type TABLE_EXPORT/TABLE/STATISTICS/TABLE_STATISTICS
Processing object type TABLE_EXPORT/TABLE/STATISTICS/MARKER
Job "DUMP_TESTUSER"."SYS_IMPORT_TABLE_01" successfully completed at Wed Jul 27 02:49:23 2022 elapsed 0 00:00:19

# ls -l
total 356
-rw-r----- 1 oracle oinstall 176128 Jul 27 02:37 data.dmp
-rw-r----- 1 oracle oinstall 176128 Jul 27 02:40 data2.dmp
-rw-r----- 1 oracle oinstall   1089 Jul 27 02:37 export.log
-rw-r----- 1 oracle oinstall   1092 Jul 27 02:40 export2.log
-rw-r----- 1 oracle oinstall    911 Jul 27 02:43 import.log
-rw-r----- 1 oracle oinstall    912 Jul 27 02:45 import2.log
-rw-r----- 1 oracle oinstall    973 Jul 27 02:46 import3.log
-rw-r----- 1 oracle oinstall   1109 Jul 27 02:47 import4.log
-rw-r----- 1 oracle oinstall   1101 Jul 27 02:47 import5.log
-rw-r----- 1 oracle oinstall    983 Jul 27 02:48 import6.log
-rw-r----- 1 oracle oinstall    941 Jul 27 02:49 import7.log

(DUMP_TESTUSER)

SQL> SELECT * FROM TESTTABLE;
      VAR1       VAR2
---------- ----------
      1000         10
      2000         20

インポートに成功し、テーブルの内容が置き換えられていることが確認できました。

結果だけみると TRUNCATE と同じに見えますが、注目したいのはインポートにかかった時間です。impdp 実行時の最終行に "elapsed" として時間が表示されていますが、TRUNCATE が 7秒であったのに対して、REPLACE では 19秒かかっています。

これは TRUNCATE ではテーブルを TRUNCATE(全消去)してからデータをインポートするのに対して、REPLACE ではテーブル自体を一旦 DROP(削除)してからインポートすることに由来しているものと考えられます。
より正確にはデータ量を変えたり、複数回実行してみたりする必要がありますが、たった 1回の試行においても約 2.7倍の差がついており、明確な性能差がみられました。

まとめ

  • expdp, impdp とも、実行ユーザに対してディレクトリオブジェクト権限 READ, WRITE の両方が必要

  • 実行ユーザに READ, WRITE 権限がなくても、PUBLIC に対して READ, WRITE 権限があれば expdp, impdp を実行可能

  • impdp では、すでに対象のテーブルが存在する場合はインポートはスキップされる

  • impdp のオプションで TABLE_EXISTS_ACTION=APPEND とすると、テーブルが存在していてもデータが追加の形でインポートされる

  • impdp のオプションで TABLE_EXISTS_ACTION=TRUNCATE または TABLE_EXISTS_ACTION=REPLACE とすると、インポート時にテーブルが存在していても一旦削除され、新たにデータがインポートされる。ただし、TRUCATE の方が性能が良い(今回の条件において)

以上、ディレクトリオブジェクト権限の状態による expdp/impdp の実行可否と、impdp を実行する際の TABLE_EXISTS_ACTION オプション指定値による挙動の違いについて確認をしてきました。
expdp/impdp を使用する際の参考にして頂ければ幸いです。


執筆者プロフィール:k.toku
国内大手メーカーにて、デスクトップパブリッシング、Eコマース、災害対策等のアプリ開発、および、ミッションクリティカルシステムの運用サポートに従事。 サーバ、ストレージからOS、ミドルウェアまで幅広い運用対応経験を持つ。 SHIFTに移籍後はインフラ関連のコンサル、テスト設計などに携わっている。

お問合せはお気軽に
https://service.shiftinc.jp/contact/

SHIFTについて(コーポレートサイト)
https://www.shiftinc.jp/

SHIFTのサービスについて(サービスサイト)
https://service.shiftinc.jp/

SHIFTの導入事例
https://service.shiftinc.jp/case/

お役立ち資料はこちら
https://service.shiftinc.jp/resources/

SHIFTの採用情報はこちら 
https://recruit.shiftinc.jp/career/