備忘録：db2move COPY によるDb2データベース間データ複製

## はじめに
db2move コマンドのCOPYオプションを利用すると、Db2データベース間で、1つ以上のスキーマをコピーすることができます。
スキーマ内に定義されるオブジェクト定義、データの中身、すべて一括コピーされます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/468682/632857ed-54d4-5be7-60b0-d788dedc70cc.png)



#### オブジェクト定義もデータもワンステップでコピーされる
データ自体の移行はもちろん、スキーマや表のオブジェクト定義も含めてコピーされるため、表、ビュー、シーケンスなどのオブジェクトを事前にターゲットDBに作成しておく必要はありません。
これは、保守期限の問題で新しいサーバに移行したいがシステム構築時の担当者はもう残っていなくてドキュメントも無くて… という現場でも使える、とてもうれしいデータ移行ツールなのではないでしょうか。

#### 中間ファイルなし(→移行のためのストレージ不要)
また、データは直接転送される仕組みでありExport/Importのような中間ファイルは生成されません。データ移行のためのストレージを別途確保する必要もないため、コストメリットもありそうです。

#### 移行先から実行可能
サービス提供中の現行本番システムに極力手を入れたくないものですが、db2move COPYは移行先データベースサーバで実行可能であるのも使い勝手が良いと思います(※逆にソース側では実行不可)

#### スキーマ名変更も可能
テスト環境など、1つのDBの中でスキーマを分けることで各自のテスト環境を確保することもあると思います。
db2move COPY では、コピー先でスキーマ名を変えることも可能です。
テスト用スキーマを1つ作成して、名前だけ変更して複製して他ユーザに展開する、といった使い方もできそうです。

#### 補足: db2moveは多機能便利ツール
db2move で実現できるのはスキーマコピーだけではなく、オプションを変更することでDB全体のデータ移行にも利用できます。
中身のデータも丸ごとコピーできるCOPYオプションが興味深かったため試してみました。
[[Db2] db2move によるデータベースの移行方法](https://www.ibm.com/support/pages/db2-db2move-%E3%81%AB%E3%82%88%E3%82%8B%E3%83%87%E3%83%BC%E3%82%BF%E3%83%99%E3%83%BC%E3%82%B9%E3%81%AE%E7%A7%BB%E8%A1%8C%E6%96%B9%E6%B3%95)


<br><br>
では、実際にスキーマコピーしてみます。

## 検証環境

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/468682/48cab45c-6a46-a787-cb42-af9dbbcd7cba.png)


**移行元(ソースDB)**

 * Linux
 * Db2 11.5.6
 * 移行対象スキーマ名：MOVTEST
 * 作成済オブジェクト：表、索引、ビュー、トリガー、シーケンス

**移行先(ターゲットDB)**

 * Windows 11
 * Db2 11.5.7
 * 移行対象スキーマ(MOVTEST)は無い状態で検証開始

バージョンが中途半端かつ不一致なのは手元にある環境をそのまま使ったためで、特に意図はありません。

## 検証ログ

### Step1. カタログ登録
今回は別サーバへのデータ移行となるため、
コマンド実行サーバであるターゲットDBからソースDBにTCP接続できるよう、ターゲットDB上にソースDBの接続情報をカタログ登録しておきます。
以下のコマンドは、ターゲットDB(Windows)上で実行します。

#### Step1-1. ノードカタログ

```
db2 catalog node tori remove <myhost> server <myport>
```

#### Step1-2. DBカタログ

```
db2 catalog database testdb at node tori
```

### Step2. スキーマコピー
db2moveコマンドを実行します。

```text:db2moveコマンド構文
db2move <移行元DB名> COPY -sn <コピー対象スキーマ名>
 -co TARGET_DB <ターゲットDB名> user <ターゲットDB接続ユーザ> using <パスワード>
 owner <オブジェクト所有者名>
 -u <ソースDB接続ユーザ> -p <パスワード>
```

```text:実行結果(標準出力)
C:\IBM\Db2_11.5.7\BIN>db2move TESTDB COPY -sn MOVTEST -co TARGET_DB MYDB user db2admin using xxxxxx owner movtest -u db2inst1 -p xxxxxx

Application code page not determined, using ANSI codepage 943

*****  DB2MOVE  *****

Action:  COPY

Start time:  Fri Feb 24 20:22:22 2023


All schema names matching:  MOVTEST;

Connecting to database TESTDB ... successful!  Server : DB2 Common Server V11.5.6

Copy schema MOVTEST to MOVTEST on the target database MYDB

Create DMT :  "SYSTOOLS"."DMT_641ad043d5fa1"

Binding package automatically ... C:\IBM\Db2_11.5.7\BND\DB2MOVE.BND ... successful!

Start Load Phase :


db2move finished successfully



Files generated:
-----------------
COPYSCHEMA.20230224202222.msg
LOADTABLE.20230224202222.MSG

Please delete these files when they are no longer needed.


End time:  Fri Feb 24 20:22:31 2023

C:\IBM\Db2_11.5.7\BIN>
```

"db2move finished successfully"と出力され、スキーマコピーが成功していることがわかります。
問題が起きた場合はエラー有と出力され、拡張子".ERR" ファイルも生成されます。

これで移行作業完了です！


### Step3. 移行オブジェクト / データ確認

#### 表
想定通りコピーされ、Valid(STATUS N=正常)状態となっています。

```sql:確認SQL
db2 "select tabschema, tabname, owner, type, status from syscat.tables where tabschema='MOVTEST' and type='T'"
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/468682/178f3688-a2a0-0422-356c-19ba4d3d1519.png)



データも参照できています。
```sql
db2 "select * from mov3"

C1          C2                                                                                                          
----------- -----------------------
          1 TEST-A                                                                                                      
          2 TEST-B                                                                                                      
          3 TEST-C                                                                                                                                                                                                  
  3 レコードが選択されました。

db2 "select * from mov4"

C1          C2                    C3
----------- --------------------- --------------------------
          1 SEQ-TEST1             2023-03-20-10.55.21.665789
          2 SEQ-TEST2             2023-03-20-10.56.30.583411

  2 レコードが選択されました。

```

#### 索引
索引も移行されています

```sql:確認SQL
db2 "select indschema, indname, owner, tabschema, tabname from syscat.indexes where indschema='MOVTEST'"
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/468682/3718c8a1-166c-2981-0092-7d6d640ef3b2.png)


#### ビュー
Valid状態で移行され、照会も可能です

```sql:確認SQL
db2 "select viewschema, viewname, owner, valid from syscat.views where viewschema='MOVTEST'"
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/468682/bbb6b7e7-0108-12de-9f07-53903d2220d2.png)

```sql
db2 "select * from view1"

C2                                                                                                                      
-------------------------
TEST-B                                                                                                                  
TEST-C                                                                                                                  
  2 レコードが選択されました。
```

#### トリガー
Valid状態(VALID列=Y)となっていて、ターゲットDBでも問題なく動作しています。

```sql:確認SQL
db2 "select trigschema, trigname, owner, tabschema, tabname, valid from syscat.triggers where trigschema='MOVTEST'"
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/468682/d57a8dba-0476-8d4b-a3aa-90b79732cc26.png)

MOV3表に1行INSERTされるごとに、INSERT実行時刻を別表に書きだすトリガーを作っておきました。
(こんなトリガーあっても意味ないですが、動作確認用ということでご容赦を..)
```sql:トリガー定義
db2 "create trigger movtest.trg3 after INSERT on movtest.mov3 for each row insert into movtest.logtbl3 values(current timestamp)"
DB20000I  The SQL command completed successfully.
```
スキーマコピー後、ターゲットDBでmov3表にINSERTすると、想定通り別表にも行が入ったため、トリガーは問題なく動作できていると思われます。

```sql:INSERT / SELECT結果
db2 "insert into mov3 values(11, 'NEW REC on win')"
DB20000I  SQL コマンドが正常に完了しました。

db2 "select * from mov3"

C1          C2                                                                                                          
----------- ----------------------
          1 TEST-A                                                                                                      
          2 TEST-B                                                                                                      
          3 TEST-C                                                                                                      
         11 NEW REC on win                                                                                              

  4 レコードが選択されました。


db2 "select * from logtbl3"

C1
--------------------------
2023-03-20-20.35.52.358000
2023-03-17-11.44.29.614972

  2 レコードが選択されました。
```

#### シーケンス
シーケンスもターゲットDBに移行されています。
また、次に払い出される順序値も、カタログへの照会で確認することができます。
```sql:確認SQL
db2 "select seqschema, seqname, owner, nextcachefirstvalue from syscat.sequences where seqschema='MOVTEST'"
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/468682/b10a056e-20d3-e8b1-36ae-69df0d8098eb.png)

さて nexcachefirstvalue=1 となっていますが、本来は26番となるはずです。

今回は、スキーマコピー前に、ソースDBでキャッシュを利用するシーケンスを作成していました。
 * 1番から採番開始
 * キャッシュ：25
 * mov4表のID(C1列)として1番2番まで採番した状態でスキーマコピー実行
     * 別セッションで次に払い出される値は26である状態で、スキーマコピーを開始していた
     * 本来、nexcachefirstvalue=26であってほしかった

```sql:シーケンス定義
db2 "CREATE SEQUENCE MOVTEST.SEQ1 START WITH 1 INCREMENT BY 1 NO MAXVALUE NO CYCLE CACHE 25"
```

頭の中がはてなマークで埋め尽くされていますが、一旦見なかったことにしてターゲットDBでmov4表にINSERTを実行した結果がこちらで、想定どおり、26番目から採番されています。
(シーケンスのnextValは、カタログでは確認できないんですかね？)

```sql:INSERT / SELECT結果
db2 "insert into mov4 values(next value for movtest.seq1, 'SEQ-TEST3 on win', current timestamp)"
DB20000I  SQL コマンドが正常に完了しました。

db2 "select * from mov4 order by c1"

C1          C2                    C3
----------- --------------------- -----------------------
          1 SEQ-TEST1             2023-03-20-10.55.21.665789
          2 SEQ-TEST2             2023-03-20-10.56.30.583411
         26 SEQ-TEST3 on win      2023-03-20-20.33.45.053000

  3 レコードが選択されました。

```

一瞬どきっとしましたが、シーケンスも問題なく移行できていそうで良かったです。

以上です。
コマンドひとつでオブジェクト定義もデータもコピーされ、非常に使いやすいツールでした！

## 参考情報

[db2move - データベース移動ツール・コマンド](https://www.ibm.com/docs/ja/db2/11.5?topic=commands-db2move-database-movement-tool)
[db2move ユーティリティーを使用したスキーマ・コピーの例](https://www.ibm.com/docs/ja/db2/11.5?topic=schemas-examples-schema-copy-by-using-db2move-utility)