Amazon RDS for Db2: S3からデータをロード(既存Db2からの移行)

LOADコマンドを使用して、Amazon S3上のデータファイルからAmazon RDS for Db2 データベースのテーブルにロードが可能です。
当記事ではS3上のExportファイルをAmazon RDS for Db2 データベースのテーブルにロードする方法を説明します。

公式ドキュメント:「[Amazon S3 からデータをロードして移行する](https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/UserGuide/db2-migration-load-from-s3.html)」の内容に基づいています、

# 前提
- 「[Amazon RDS for Db2: Amazon S3 にデータファイルを保存するための設定](https://qiita.com/nishikyon/items/e4f6d2113fdb6bf07777)」設定済み
- ロードするファイルを置く Amazon S3 バケットがロード先RDS for Db2 DB インスタンスと同じリージョンに作成済み

# 前準備: ロードするファイルを置く Amazon S3 バケットを指すストレージアクセスエイリアスをカタログ化
一度だけ実行すればよい設定です。
 ロード先RDS for Db2のDBのカタログ情報を登録していてDb2 CLPが使用できる環境からコマンドを実行します。

#### 1. ロード先RDS for Db2の DB インスタンスのAdminユーザー名とAdminパスワードを使用して、rdsadmin データベースに接続

以下のコマンドを実行します:
<admin_username> と <admin_password> を自分の情報に置き換えます。
```
db2 connect to rdsadmin user <admin_username> using <admin_password>
```

実行例:
```
db2 connect to rdsadmin user admin using P@ssw0rd
```

#### 1. ストアドプロシージャ [rdsadmin.catalog_storage_access](https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/UserGuide/db2-sp-managing-storage-access.html#db2-sp-catalog-storage-access)で S3 バケット ストレージアクセスエイリアスをカタログ化

以下のコマンドを実行します:
 <エイリアス名>, << s3バケット名>>, <アクセスするDb2のユーザー名>は自分の情報に置き換えます。
```
db2 "call rdsadmin.catalog_storage_access(?, '<エイリアス名>', '<s3バケット名>', 'USER', '<アクセスするDb2のユーザー名>')"
```
例：
```
db2 "call rdsadmin.catalog_storage_access(?, 'us_aws_s3', 'japan-db2-us', 'USER', 'admin')"
```

登録の確認：
以下のSQLで確認します

```sql
db2 "select task_id, task_type, lifecycle, 
    varchar(bson_to_json(task_input_params), 500) as task_params, 
    cast(task_output as varchar(500)) as task_output 
    from table(rdsadmin.get_task_status(null,null,null)) 
    where task_type in ('CATALOG_STORAGE_ACCESS') "
```
出力例

```
TASK_ID              TASK_TYPE                                          LIFECYCLE                                          TASK_PARAMS                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          TASK_OUTPUT
-------------------- -------------------------------------------------- -------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
                 101 CATALOG_STORAGE_ACCESS                             SUCCESS                                            { "ALIAS" : "us_aws_s3", "BUCKET" : "japan-db2-us", "GRANTEETYPE" : "USER", "GRANTEE" : "ADMIN" }                                                                                                                                                                                                                                                                                                                                                                                                                    2024-09-20T06:37:04.509Z Task execution has started.
2024-09-20T06:37:07.812Z Task Completed Successfully
```
該当コマンド実行日時の行にLIFECYCLEが`SUCCESS`でTASK_OUTPUTに`Task Completed Successfully`があればOKです。

# 0. 参考　S3なし、db2moveでのデータをexport/import して移行
参考までに、ソースのDb2とターゲットのRDS Db2のデータベースがTCP/IPで接続でき、db2 catalog databaseコマンドにより両方カタログされていてアクセスできる環境からであれば、`db2move`でS3を使わなくても移行できます。
ただしLOADコマンドの方が一般的にimportより速いので、データ量が多い場合には向いていません。

以下の環境での実行例です:
- ソースDb2サーバー上で実行
- ソースDb2: SAMPLE1
- ターゲットRDS for Db2: RDSTEST1でカタログ済み
- exportファイルのLOBPATH: `/tmp/db2move_data/20240927` (LOBがある場合はここに出力される)
- 移行するスキーマ: `test01`

コマンドを実行したフォルダーにスキーマtest01のデータがexportされます。LOBがあった場合は`/tmp/db2move_data/20240927`にexportされます。

### 0-1. ソースDb2に接続し、`db2move export`を実行
```
db2 connect to sample1
db2move sample1 export -sn test01 -l /tmp/db2move_data/20240927
```

出力例：

```
$ db2move sample1 export -sn test01 -l /tmp/db2move_data/20240927

Application code page not determined, using ANSI codepage 1208

*****  DB2MOVE  *****

Action:  EXPORT

Start time:  Mon Sep 23 15:23:00 2024


All schema names matching:  TEST01;

Connecting to database SAMPLE1 ... successful!  Server : DB2 Common Server V11.5.9

EXPORT:     14 rows from table "TEST01  "."DEPARTMENT"
EXPORT:     42 rows from table "TEST01  "."EMPLOYEE"

Disconnecting from database ... successful!

End time:  Mon Sep 23 15:23:00 2024
$
```





### 0-2. `db2move import`を実行

ターゲットRDS for Db2のユーザーIDは`admin`, passwordは`yyyyyyy`とします。
デフォルトでは表は作成されるので、事前に作成しておく必要はありません。

```
db2move RDSTEST1 import -u admin -p yyyyyyy -l /tmp/db2move_data/20240927
```

出力例：

```
$ db2move RDSTEST1 import -u admin -p yyyyyyy  -l /tmp/db2move_data/20240927

Application code page not determined, using ANSI codepage 1208

*****  DB2MOVE  *****

Action:  IMPORT

Start time:  Mon Sep 23 15:25:19 2024


Connecting to database RDSTEST1db2 ter ... successful!  Server : DB2 Common Server V11.5.9

* IMPORT:  table "TEST01  "."DEPARTMENT"
  -Rows read:         14
  -Inserted:          14
  -Rejected:           0
  -Committed:         14

* IMPORT:  table "TEST01  "."EMPLOYEE"
  -Rows read:         42
  -Inserted:          42
  -Rejected:           0
  -Committed:         42


Disconnecting from database ... successful!

End time:  Mon Sep 23 15:25:49 2024
$
```
無事importできました！


:::note info 
- db2moveに関する詳細はこちら👉「[[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)」
:::

:::note warn
- 注1：db2moveのCOPYオプション（中間ファイルなし）は、RDS for Db2では使用できません
   - 内部的にカーソル・ロードを使用しており、ターゲット側RDSローカルで実行する必要があるため
- 注2：db2move IMPORTアクションでは、デフォルトは REPLACE_CREATEであるため、ターゲットDBに表がない場合は表が自動的に作成されます。ただし、IMPORTのREPLACE_CREATオプションは非推奨で、将来的にはdb2lookを使用して事前に表を作成しておくことが推奨されます。
:::



# 1. S3にexportデータを作成
S3からデータをロードするには、当然S3にexportデータを配置する必要があります。
普通に上記で使用した`db2move export` あるいは単に`export`コマンドでローカルにexportデータを作成し、[AWS CLI](https://aws.amazon.com/jp/cli/)など何らかの方法でS3にそのデータを配置します。

またはS3に接続可能な環境であれば、SQLで外部表をS3に作成することで、直接S3に書き出すことも可能です。ここではこの方法でS3にexportデータを作成してみます。


#### CREATE EXTERNAL TABLE コマンド
参考: https://www.ibm.com/docs/ja/db2/11.5?topic=statements-create-table-external
```shell
db2 "CREATE EXTERNAL TABLE '<パスを含むファイル名>'    
USING ( DELIMITER ',' s3('<S3-endopoint>', 
  '<S3-access-key-ID>',
  '<S3-secret-access-key>', 
  '<bucket>'
))
AS SELECT * FROM <ソーステーブル名>";
```

`<>`で囲まれた部分は自分の値に置き換えます。 DELIMITERは`,`としています。
- `<パスを含むファイル名>`: 書き出し先のS3上でのパスを含むファイル名
- `<S3-endopoint>`: S3エンドポイント
- `<S3-access-key-ID>`: S3 キーID
- `<S3-secret-access-key>`: S3 アクセスキー
- `<bucket>`: バケット名

実行例:
ソースDBに接続後、実行します。
テーブル名`EMPLOYEE`をusリージョンのS3、バケット名`japan-db2-us`に`/external_tbl/EMPLOYEE.csv`というファイル名でデータファイルを作成。

```
db2 connect to sample1;
db2 "CREATE EXTERNAL TABLE '/external_tbl/EMPLOYEE.csv'    
USING (  DELIMITER ',' S3('s3.us-east-1.amazonaws.com', 
'xxxxxxxxxx', 'yyyyyyyyyy','japan-db2-us'))
AS SELECT * FROM EMPLOYEE";
```
実行後、S3を確認すると無事ファイルが作成されていました:
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294516/cf3e3755-5251-f685-76c8-76c1513b3b78.png)


# 2. S3からデータをロード
ではデータもできたので、S3からロードしてみます。
ロード先のテーブルは事前に作成しておく必要があります。

Db2 CLIで実行可能です。ロード先のRDS for Db2に接続してから実行します。 
`db2remote://`で[前準備](#前準備-ロードするファイルを置く-amazon-s3-バケットを指すストレージアクセスエイリアスをカタログ化)で作成したストレージアクセスエイリアスを指定します。
```
db2 "load from db2remote://<ストレージアクセスエイリアス>//<パスを含むファイル名> of DEL 
insert into <ロード先テーブル名>";
```
`<>`で囲まれた部分は自分の値に置き換えます。
- `<ストレージアクセスエイリアス>`: [前準備](#前準備-ロードするファイルを置く-amazon-s3-バケットを指すストレージアクセスエイリアスをカタログ化)で作成したエイリアス名
- `<パスを含むファイル名>`: 書き出し先のS3上でのパスを含むファイル名
- `<ロード先テーブル名>`: ロード先テーブル名



実行例:
ロード先のRDS for Db2に接続してから実行します。
`<ストレージアクセスエイリアス>`は`us_aws_s3`としています。
```
db2 connect to rdstest1 user admin using yyyyyyy;
db2 "load from db2remote://us_aws_s3//external_tbl/EMPLOYEE.csv of DEL 
insert into test01.EMPLOYEE";
```
出力例：
```
$ db2 connect to rdstest1 user admin using yyyyyyy；

   Database Connection Information

 Database server        = DB2/LINUXX8664 11.5.9.0
 SQL authorization ID   = ADMIN
 Local database alias   = RDSTEST1

$ db2 "load from db2remote://us_aws_s3//external_tbl/EMPLOYEE.csv of DEL insert into test01.EMPLOYEE";
SQL27966W  The DB2_LOAD_COPY_NO_OVERRIDE registry variable value
"NONRECOVERABLE" overrides the COPY NO parameter specified in the Load.

SQL3109N  The utility is beginning to load data from file
"db2remote://us_aws_s3//external_tbl/EMPLOYEE.csv".

SQL3500W  The utility is beginning the "LOAD" phase at time "09/24/2024
23:53:45.777930".

SQL3519W  Begin Load Consistency Point. Input record count = "0".

SQL3520W  Load Consistency Point was successful.

SQL3110N  The utility has completed processing.  "42" rows were read from the
input file.

SQL3519W  Begin Load Consistency Point. Input record count = "42".

SQL3520W  Load Consistency Point was successful.

SQL3515W  The utility has finished the "LOAD" phase at time "09/24/2024
23:53:45.871886".


Number of rows read         = 42
Number of rows skipped      = 0
Number of rows loaded       = 42
Number of rows rejected     = 0
Number of rows deleted      = 0
Number of rows committed    = 42

$
```
無事ロードできました！

LOBを含むの表のロードは「[RDS for Db2 テーブルへのデータのロード](https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/UserGuide/db2-migration-load-from-s3.html#db2-migration-load-from-s3-into-db-table)」の「Amazon S3 バケットを指すストレージアクセスエイリアスを使用して、LOAD コマンドを実行します。」の2番目の例を参考にしてください。ただ微妙に引用符が間違っていてそのままだと動かないので、正しくは以下となります：
```
db2 "call sysproc.admin_cmd('load from db2remote://my_s3_alias//my_table1_export.ixf of ixf
        lobs from db2remote://my_s3_alias// xml from db2remote://my_s3_alias//
        modified by lobsinfile implicitlyhiddeninclude identityoverride generatedoverride periodoverride transactionidoverride
        messages on server
        replace into my_schema.my_db2_table
                               nonrecoverable
        indexing mode incremental allow no access')"
```


:::note warn
- RDS for Db2へのLOADは、デフォルトNONRECOVERABLEオプションとなります。RDS for Db2は`DB2_LOAD_COPY_NO_OVERRIDE`のパラメータの値が`NONRECOVERABLE`になっているためです。
- NONRECOVERABLE LOADでは、LOAD後すぐにデータにアクセスできるが、その後ストレージ障害等により、 NONRECOVERABLE LOAD以前のDBバックアップよりRESTOREしてROLLFORWARDするとNONRECOVERABLE表はdrop pendingとなります。よってLOAD後には手動でRDSスナップショットを取得するか、LOADジョブの最後にRDSの自動バックアップを設定する運用を推奨します。

:::



以上です。