4種類のRMAN DUPLICATEでそれぞれ実際にデータベースをコピーする

## はじめに

RAM Duplicateコマンドは、バックアップ、リストアおよびリカバリを専門とする他のRMANコマンド群と異なり、クローンデータベースを作成することに特化しています。このコマンドを利用するとデータベースのコピーが驚くほど簡単に作成できるのですが、いろいろなバックアップ環境に対応できるようコマンドがフレキシブルになっているが故に、使用法が微妙にわかりにくくなっているのが難点です。
ここではRMAN Duplicateの４つの記述法を示し、それぞれの方法で実際にクローンデータベースを作成していくことで、使い方を説明しています。

## RMAN Duplicateの種類

前述の通りRMAN Duplicateは様々の状況に対応できるよう４つの使い方をサポートしています。 オラクルのマニュアルに記載されている図がわかりやすいですね。cf. [Database Backup and Recovery User's Guide ](https://docs.oracle.com/database/121/BRADV/rcmdupdb.htm#GUID-5B67EEA8-E89E-4B83-B9AF-97AACB0AE4E4__BGBBFIAD)

![RMAN Duplicate](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179587/e927de22-244b-f85c-7cd8-9ea50dff2c87.png)

まずDUPLICATEの大きな区分けとしてコピーソースが稼働中データベースなのかバックアップなのか、ですね。左上の稼働データベースから直接コピーする方法が１つ目になります。次にバックアップを使用する方法のうち、元データベースに接続するかしないか、で分かれます。こここで、バックアップがあるのにわざわざ元データベースに接続する必要があるのか？と思うかもしれませんが、元データベースからバックアップの保管場所等の情報を取得しているのです。そして、この元データベースに接続する方法が２つ目です。さらに、元データベースに接続しない場合には、リカバリーカタログに接続する方法と、どこにも接続しない方法があります。リカバリーカタログに接続するのが３番目。最後にどこにも接続しないのが４番目です。ちなみに10gや11.1で唯一サポートされているのが２番めの方法です。11gR2からすべての方法がサポートされました。

1. **From Active Database**
2. **From Backup With Target Connection**
3. **From Backup Without Target Connection With Recovery Catalog**
4. **From Backup Without Target Connection Without Recovery Catalog**

さて、バックアップをソースとしたコピーがなぜこんなに細分化されているかというと、上述の通りバックアップの保存場所やターゲットとなるバックアップセットの特定情報が必要だからなんですね。それぞれ以下の場所から情報を取得しています。

| Duplicateの種類        | バックアップの格納場所など                 | DBを特定する情報     |
| ---------------------- | ------------------------------------------ | -------------------- |
| Active Database        | 不要                                       | 接続先DBから取得     |
| Backup with Target DB  | ターゲットDBのコントロールファイルから取得 | ターゲットDBから取得 |
| Backup with Catalog DB | カタログDBから取得                         | コマンドラインで指定 |
| Backup only            | コマンドラインで保管場所を指定             | コマンドラインで指定 |



## RMAN Duplicateの接続先

Duplicateの種類により最大３つの接続先があります。どの場合でも必要となる必須接続は``AUXILIARY``のみです。

```
 rman AUXILIARY <CloneDB> TARGET <SourceDB> CATALOG <CatalogDB> 
```

| 句        | 接続先                         | 説明                                                         |
| --------- | ------------------------------ | ------------------------------------------------------------ |
| AUXILIARY | クローンデータベース**(必須)** | Active Databaseの場合のみユーザ名・パスワード必要。他の場合ローカル接続であれば"/"可。データベースはNOMOUNT起動であること。 |
| TARGET    | ソース(コピー元)データベース   | Active Databaseの場合必須。OPENまたはMOUNTであること。ただしアーカイブログモードでないDBをコピーする場合はMOUNTのみ。 |
| CATALOG   | RMANカタログデータベース       | 基本的にオプショナル                                         |



## RMAN Duplicateの記述法

RMAN Duplicateの４つの種類、それぞれの文法と説明です。RMAN Duplicateはリストアではなくコピーコマンドのため、必ずDBIDが変更されます。

### 1. Active Database

```
rman auxiliary sys/<pass>[@<conn>] target sys/<pass>@<conn>

DUPLICATE TARGET DATABASE TO <CloneDB> FROM ACTIVE DATABASE;
```

稼働中の元データベースに接続しそのままコピーします。ただし、元データベースが非アーカイブログモードの場合、MOUNT起動でなければなりません。11gまではクローンデータベースをリスナーに静的登録する必要がありましたが、12cからは不要です。ただし、``PASSWORD FILE``オプションを使用してパスワードファイルを同時にコピーする場合はこの限りではありません。同じく``FOR STANDBY``オプションも自動的にパスワードファイルをコピーするためリスナー登録が必要です。

また11gではImage Copyのみでしたが、12cから``USING [ COMPRESSED ] BACKUPSET``オプションが利用可能になり未使用領域をコピーしない方法も提供されました。

### 2. Backup With Target Connection

```
rman auxiliary / target sys/<pass>@<conn>

RMAN> DUPLICATE TARGET DATABASE TO <CloneDB>;
```

10g/11.1で唯一サポートされている方法です。バックアップの場所や元データベースの情報をデータベースそのものから取得するためコマンドラインから与える必要がありません。

### 3. Backup Without Target Connection With Recovery Catalog

```
rman auxiliary / catalog <user>/<pass>@<conn>

RMAN> DUPLICATE DATABASE <SourceDB> [ DBID <dbid> ] [ INCARNATION <key> ] TO <CloneDB>;
```

カタログDBに接続してバックアップ情報を得る方法ですが、DB名、DBID、INCARNATION等の元データベースの情報を与えてバックアップを特定する必要があります。

### 4. Backup Without Target Connection Without Recovery Catalog

```
rman auxiliary /

RMAN> DUPLICATE DATABASE [ <SourceDB> ] TO <CloneDB> BACKUP LOCATION ‘<directory path　or ASM diskgroup>’;
```

カタログDBの代わりにバックアップ保管場所を直接指定します。ファイルの場合はディレクトリ、ASMの場合はASM Diskgroup名です。バックアップ保管場所に元データベース以外のバックアップも含まれている場合は、カタログDB接続時と同じように、DB名等を与えてバックアップを特定します。



## RMAN Duplicateの共通オプション(抜粋)

| オプション       | 説明                                                         |
| ---------------- | ------------------------------------------------------------ |
| UNTIL TIME / SCN | ポイントインタイムの指定。(ただしActive Databaseでは不可)    |
| PFILE            | spfileの代わりに指定されたpfileを使用する                    |
| SKIP READONLY    | 読み取り専用テーブルスペースを除外する                       |
| SKIP TABLESPACE  | 指定したテーブルスペースを除外する。(system, sysaux, undoは除外されない) |
| TABLESPACE       | (11g以降) 指定したテーブルスペースのみリストアする。(system, sysaux, undoは自動追加) |
| SPFILE           | ソースデータベースからspfileをコピーして使用する             |
| LOGFILE          | Online Redo Logファイルを指定の場所に作成する                |
| NOFILENAMECHECK  | コピー元とコピー先のファイル名とパスが同じだと上書き不可としてエラー処理されるので、このエラーを出さないようにするオプション。別ホストに同じパスでコピーする場合に有用。 |
| NORESUME         | (11g以降) Duplicate失敗後再開せず、最初からやり直す。RESUME機能は有用ではあるのですが、テスト中に限って言えばバックアップを取り直した後にドツボにハマったりするので、常につけておくと良いオプションです :-)。 |
| NOOPEN           | (12c以降) クローンデータベースを作成後オープンしない。       |



## RMAN Duplicateのテスト

さて、この手の話は知識として知ってても実際に手を動かしてみないとなかなか会得できないものです。ということですべての種類のDUPLICATEを実行してみましょう！

### テスト環境 (18c)

環境は18cです。ソース側DBとして適当なデータベースを用意しますが、なるべく小さなDBの方が扱いやすいので、新しいDBを作っておきます。DBCAのサイレントモードを使うとお手軽です。またアーカイブログモードはテストのために有効にしておきます。(ちなみに``-memoryMgmtType``は12.2以降のオプション。それ以前は``-automaticMemoryManagement``)

```
dbca -silent \
-createDatabase -templateName General_Purpose.dbc \
-gdbname TESTDB -sid TESTDB -characterSet AL32UTF8 \
-sysPassword mysystem  -systemPassword mysystem \
-createAsContainerDatabase FALSE \
-memoryMgmtType AUTO_SGA -totalMemory 800 \
-storageType FS -datafileDestination "/u01/app/oradata/" \
-useOMF TRUE \
-redoLogFileSize 50 \
-emConfiguration NONE \
-ignorePreReqs \
-enableArchive TRUE \
-recoveryAreaDestination "/u01/app/oradata/" -recoveryAreaSize 5000
```

完了したらログインしてアーカイブログモードを確認します。

```sql
$ export ORACLE_SID=TESTDB

$ sqlplus / as sysdba
...
SQL> select name, log_mode from v$database;

NAME      LOG_MODE
--------- ------------
TESTDB    ARCHIVELOG
```

さらにリモート接続でDBA接続できることも確認しておきます。できない場合は、リスナーやパスワードファイルをチェックしましょう。

```
$ sqlplus sys/mysystem@server1/TESTDB as sysdba
...
SQL>
```

次に、クローン側の環境を作ります。クローン側はとりあえず実行ファイルさえあればなんとかなりますが、テストを簡潔にするためSPFILEを作っておきます。ソースからコピーして名前やパスを変更すればOK。好みにもよりますが、``db_create_file_dest``を設定してOMFを、また``db_recovery_file_dest``と``db_recovery_file_dest_size``を設定してFRAを有効にしておくとテストが捗ります。

```
*.compatible='18.0.0'
*.db_name='COPYDB'
*.db_block_size=8192
*.control_files='/u01/app/oradata/COPYDB/control1.dbf'
*.db_create_file_dest='/u01/app/oradata'
*.db_recovery_file_dest='/u01/app/oradata'
*.db_recovery_file_dest_size=500m
*.diagnostic_dest='/u01/app/oradba'
*.audit_file_dest='/u01/app/oradba/admin/COPYDB/adump'
*.remote_login_passwordfile='EXCLUSIVE'
*.pga_aggregate_target=200m
*.sga_target=600m
```

```
$ export ORACLE_SID=COPYDB

$ mkdir -p /u01/app/oradba/admin/COPYDB/adump

$ sqlplus / as sysdba
...
SQL> create spfile from pfile='COPYDB.pfile';
```



### テスト１. Active Database

まずはアクティブコピーからですね。稼働中のソースDBに接続してコピーします。バックアップは必要ありません。

11gの場合はクローン側データベースの静的リスナー登録が必要です。12c以降でも前述の通りPASSWORD FILEオプションを指定した場合や、Data Guardのスタンドバイとしてコピーする場合は静的リスナー登録が必要となります。

いずれにせよSYSのパスワードを持つパスワードファイルは事前に用意して置く必要があるので、ソース環境から手動でコピーして名前を変更するか、またはorapwdコマンドを用いてソースと同じパスワードで作成します。

```:パスワードファイルの作成
$ orapwd file=$ORACLE_HOME/dbs/orapwCOPYDB password=mysystem format=12
```

rmanを起動しクローン側DBをNOMOUNTで起動してDUPLICATEを実行します。SPFILEがなくてもRMANが適当なパラメータで起動してくれますが、その場合はDUPLICATEコマンドのオプションでSPFILEをコピーする必要があります。

```
$ export ORACLE_SID=COPYDB

$ rman auxiliary sys/mysystem target sys/mysystem@server1/TESTDB
...
connected to target database: TESTDB (DBID=2808694393)
connected to auxiliary database (not started)

RMAN> startup clone nomount;

Oracle instance started

Total System Global Area     629143384 bytes

Fixed Size                     8660824 bytes
Variable Size                243269632 bytes
Database Buffers             369098752 bytes
Redo Buffers                   8114176 bytes

RMAN> DUPLICATE TARGET DATABASE TO COPYDB FROM ACTIVE DATABASE;

Starting Duplicate Db at ......
using target database control file instead of recovery catalog
...
...
database opened
Finished Duplicate Db at ......

RMAN>
```

これでデータベースのコピーができました。何度やっても拍子抜けするくらい簡単ですね。

```sql
SQL> select name, log_mode, open_mode from v$database;

NAME      LOG_MODE     OPEN_MODE
--------- ------------ --------------------
COPYDB    ARCHIVELOG   READ WRITE
```

#### 静的リスナーの使用

ちなみに、静的リスナーを使用する場合はクローン側のlistener.oraで以下のようにクローンデータベースを宣言します。

```
SID_LIST_LISTENER =
  (SID_LIST =
    (SID_DESC =
      (GLOBAL_DBNAME = COPYDB)
      (SID_NAME = COPYDB)
      (ORACLE_HOME = /u01/app/oradba/18.3)
    )
  )
```

リスナーを再起動するとデータベースが起動していなくてもリスナーに登録されます。DBが起動されていないとDBの状態がわからないのでステータスはUNKNOWNとなっています。

```
$ lsnrctl reload

$ lsnrctl status
...
Service "COPYDB" has 1 instance(s).
  Instance "COPYDB", status UNKNOWN, has 1 handler(s) for this service...
```

RMANではauxiliaryにリスナー経由で接続します。これでソースからパスワードファイルのコピーができるようになりました。といってもauxiliaryに接続するためには、少なくともSYSのパスワードを持つパスワードファイルが必須なので事前に用意して置く必要があります。(ソース環境のパスワードファイルにはSYS以外のパスワードも登録されているかもしれないのでパスワードファイルのコピーは無意味というわけではありません)

```
$ orapwd file=$ORACLE_HOME/dbs/orapwCOPYDB password=mysystem format=12

$ rman auxiliary sys/mysystem@server2/COPYDB target sys/mysystem@server1/TESTDB
...
RMAN> startup clone nomount;
...
RMAN> DUPLICATE TARGET DATABASE TO COPYDB FROM ACTIVE DATABASE PASSWORD FILE;
```



### テスト2. Backup With Target Connection

次はソースDBに接続しつつ、バックアップからのクローン作成ですね。ソースDBからバックアップの保存場所などの情報を取得します。まずはソースデータベースのバックアップを作成します。OMFとFRAが有効なので、デフォルトでFRAディレクトリ下にautobackupとbackupsetディレクトが作られバックアップファイルが保存されます。

```
$ export ORACLE_SID=TESTDB

$ rman target /
...
connected to target database: TESTDB (DBID=2808694393)

RMAN> backup database include current controlfile plus archivelog;
...
RMAN> list backup;
...
```

では、リモートサーバにクローンデータベースを作ります。バックアップファイルがクローンDBのサーバから参照できない場合はローカルにコピーしておきます。またソースデータベースに接続している場合、RMANはターゲットの最新状態でクローンを作成しようとします。従ってソースの(バックアップされてない)アーカイブログがクローン側から参照できない場合は、``NOREDO``オプションまたは適切な``UNTIL SCN/TIME``オプションをつけてバックアップされていないアーカイブログを探しに行かないようにします。

```
$ export ORACLE_SID=COPYDB

$ rmanrl auxiliary / target sys/mysystem@server1/TESTDB
...
RMAN> startup clone nomount;
...
RMAN> DUPLICATE TARGET DATABASE TO COPYDB NOREDO;
...
database opened
Finished Duplicate Db at .....
RMAN> 
```



### テスト3. Backup Without Target Connection With Recovery Catalog

RMANカタログデータベースに接続してバックアップからクローンを作成します。このテストにはカタログデータベースが必要となるので、ちゃっちゃっと作っちゃいましょう。

##### カタログデータベースの作成

まず上記のアクティブコピーでRMANDBを作ります。次に下記の通りcatalog用スキーマをつくりRMANからカタログを作成します。まぁぶっちゃけカタログデータベースはこんだけです。

```
$ export ORACLE_SID=RMANDB

$ sqlplus / as sysdba
SQL> CREATE TABLESPACE catalog DATAFILE AUTOEXTEND ON MAXSIZE UNLIMITED;
SQL> CREATE USER catalog IDENTIFIED BY catalog DEFAULT TABLESPACE catalog TEMPORARY TABLESPACE temp QUOTA UNLIMITED ON catalog;
SQL> GRANT RECOVERY_CATALOG_OWNER TO catalog;

$ rman catalog catalog/catalog
...
connected to recovery catalog database

RMAN> create catalog;
```

では、ソースDBであるTESTDBをカタログに登録しましょう。RMANから``register database``コマンド一発です。

```
$ export ORACLE_SID=TESTDB

$ rman target / catalog catalog/catalog@server1/RMANDB
...
connected to target database: TESTDB (DBID=2808694393)
connected to recovery catalog database
...
RMAN> register database;
...
RMAN> list backup summary;
```

#### クローンDBの作成

以上で、環境は整いました。カタログデータベースに接続しつつバックアップからクローンを作ります。対象のバックアップを特定するためにここではデータベース名だけを指定していますが、カタログに同名の別DBが登録されていたり対象DBのログがリセットされていた場合は、前述の通りDBIDやINCARNATIONを指定する必要があるかもしれません。

````
$ export ORACLE_SID=COPYDB

$ rman auxiliary / catalog catalog/catalog@server1/RMANDB
...
RMAN> startup clone nomount;
...
RMAN> DUPLICATE DATABASE TESTDB TO COPYDB NORESUME;
...
database opened
Finished Duplicate Db at ......
````



### テスト4. Backup Without Target Connection Without Recovery Catalog

最後にどこにも接続せずにバックアップからクローンDBを作成します。バックアップ保存場所の情報がどこからも取得できないためLOCATION句を使って指定します。バックアップファイルは、サブディレクトリもちゃんと参照してくれるのでOMFの構造のままでも良いし、一箇所にまとめてコピーしておいても構いません。

```
$ export ORACLE_SID=COPYDB

$ rman auxiliary /
...
RMAN> startup clone nomount;
...
RMAN> DUPLICATE DATABASE TO COPYDB BACKUP LOCATION '/u01/app/oradata/TESTDB';
...
```

一番シンプルで簡単ですが、バックアップがテープにある場合は使えません。

#### SPFILEオプションを使用する

最後があまりにも簡単だったのでクローン側をパラメータファイル無しで起動してDUPLICATEでSPFILEを作る方法も試してみます。SPFILEオプションの``PARAMETER_VALUE_CONVERT``で変換文字列を指定して、あとは直接設定したいパラメータを羅列していくだけです。ちなみにSPFILEオプションはすべてDUPLICATEで使用可能ですが、クローンDBがすでにSPFILEを使用して起動している場合は使えません(PFILEはOK)。

```
$ rm -f $ORACLE_HOME/dbs/spfileCOPYDB.ora $ORACLE_HOME/dbs/initCOPYDB.ora

$ rman auxiliary /

RMAN> startup clone nomount;
startup failed: ORA-01078: failure in processing system parameters
LRM-00109: could not open parameter file '/u01/app/oradba/18.3/dbs/initCOPYDB.ora'

RMAN> DUPLICATE DATABASE TESTDB TO COPYDB BACKUP LOCATION '/u01/app/oradata'
SPFILE
PARAMETER_VALUE_CONVERT 'TESTDB','COPYDB'
SET DB_NAME 'COPYDB'
SET CONTROL_FILES '/u01/app/oradata/COPYDB/control1.ctl';
...
database opened
Finished Duplicate Db at ...
```

データベースがコピーされて、SPFILEもちゃんとできています。

```
$ ls $ORACLE_HOME/dbs/spfileCOPYDB.ora
/u01/app/oradba/18.3/dbs/spfileCOPYDB.ora
```

クローンデータベース側は所詮コピーなのでOMFがおすすめですが、そうでない場合は、`` DB_FILE_NAME_CONVERT``や``LOG_FILE_NAME_CONVERT``オプションを使用してそれぞれのパスの変更を指示する必要があるかもしれません。



## おわりに

RMAN Duplicateコマンドを使用することによって途轍もなく簡単にクローンデータベースを作成できるようになりました。Point-in-timeリカバリにも対応していますし、必要なテーブルスペースのみをリストアしてコピーデータベースの作成時間を短縮することもできます。これらのコピーはDuplicateコマンドを使用せずともRMANの他のコマンドを組み合わせることで可能は可能なのですが、いろいろ面倒な操作が必要となります。Duplicateコマンドは、以下のような様々な動作をワンショットで実行してれるので、ほんと便利です。

Duplicateがやってくれること

- ワンショットDBリストア＆リカバリ（spfileやcontrolfileの事前リストアが不要）
- 不要なテーブルスペースのリストアやリカバリをスキップ
- Point-in-timeリカバリ （Active Duplicateでは不可）
- DBファイル名やディレクトリパスの変更
- DB名およびDBIDの変更
- SPFILEのコピーおよびinitパラメータの変更
- バックアップなしでのコピー （Active Duplicate） 

以上です。