RDS for Oracleの非CDB構成のCDB構成への変更

# はじめに

Oracle Databaseはマルチテナント構成というコンテナDB(CDB)の中に複数のプラガブルDB(PDB)を持つ構成を取ることができます。（[マルチテナント・アーキテクチャについて](https://docs.oracle.com/cd/F19136_01/multi/introduction-to-the-multitenant-architecture.html#GUID-FC2EB562-ED31-49EF-8707-C766B6FE66B8)）
RDS for Oracle においては以前は非CDB構成(従来型のアーキテクチャ)からCDB構成への変換が行えませんでしたが、今回のアップデートでサポートされるようになりました （[Amazon RDS for Oracle now supports converting instances to CDB architecture](https://aws.amazon.com/jp/about-aws/whats-new/2023/06/amazon-rds-oracle-instances-cdb-architecture/)）

なお、元々本来Oracle社が提供しているCDB-PDB構成は、1つのCDBの中に複数のPDBを持つことが出きる、という構成でしたが、RDS for OracleのCDB-PDB構成は1つのCDBの中に1つのPDBしか持つことが出来ず、CDB-PDB構成のメリットを活かすことができないというものであり、これは今回のアップデートでも変更はありません。
CDB-PDB構成を取ることができる唯一のメリットは、21cにバージョンアップが可能、というものであり、今年中に出ると言われている次のLTS(Long Term Support)となるOracle 23cを見据えた機能となると推測しています。

ちなみに、[RDS Custom for Oracleという半マネージドなデータベースサービス](https://qiita.com/asahide/items/33e4706ab02f69ab427d)では、2022年11月に[Oracle Multitenantオプション（CDB-PDB構成）がサポート](https://aws.amazon.com/jp/about-aws/whats-new/2022/11/amazon-rds-custom-oracle-supports-oracle-multitenant/)され、Oracle Database 19c はコンテナベース (CDB) あたり最大3つのプラグ可能なデータベース (PDB) をサポートされるようになりました(※)。

(※)「ご自身のユースケースに該当するかどうかの判断は、各社の法務チームにお尋ねください」と記載されています

# CDB構成への変更を試してみた

非CDB構成のRDS for Oracleを確認します、今回はtestdb01というOracle SE2のデータベースを利用します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2313926/4eac6c2c-1bc1-539f-74ba-9304da86aac2.png)

この状態ですと、幾つかのコンテナDB関連のビュー等は存在しない／データがない状態であることが確認できます。
```SQL
$ sqlplus admin/xxxxxxxx@testdb01.xxxxxxxxxxxx.ap-northeast-1.rds.amazonaws.com:1521/testdb01
SQL> show con_name

CON_NAME
------------------------------
TESTDB01

SQL> select pdb_name, status fron cdb_pdbs;
select pdb_name, status fron cdb_pdbs
                             *
ERROR at line 1:
ORA-00923: FROM keyword not found where expected

SQL> select * from v$pdbs;

no rows selected
```

非CDB構成だと以下のように、21c以降にはアップグレードできない旨のメッセージが出ます。
![00-multi-pre-02.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2313926/061477dc-a77c-606c-60c0-7eca23cf142f.png)

データベースを選択し「変更」を押下すると「マルチテナントアーキテクチャ」を選択できるようになっています。マルチテナントアーキテクチャのボックスにチェックを入れると、DBエンジンの変更がグレーアウトされ、エンジンバージョンのアップグレードは同時にはできないようになっています。
![00-multi-pre-01-2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2313926/d734d729-7720-a42f-0fd3-1ca9ca89512e.png)

そのまま変更オペレーションに進むことができますが、[幾つか制限があり](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/oracle-multitenant.html#oracle-cdb-converting)、制限に該当するとエラーが出て変更ができません。(以下の例はオプショングループのタイムゾーンが違っていたため失敗)
![01-multi-03-NG.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2313926/ebd61ad5-2329-a033-6dd1-f5289535d4dc.png)

変更自体はオフラインで実行され、db.t3.smallで約1時間、db.m5.xlargeで約40分程度でした。(以下はdb.m5.xlargeの結果)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2313926/cd5375fe-81bf-cd98-a5f8-6d1f8a42ff86.png)

移行後は以下のような表示になり、CDB‐PDB構成となっていることが確認できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2313926/1a287946-04ee-00f1-96ce-e54bc16454d9.png)
（設定タブ）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2313926/3730ded5-77ec-dd4a-2720-fecc1d1f8b4e.png)

SQL*PLUSでは非CDB構成と同じ接続文字列で接続が可能です。また、コンテナDB関連のビュー等でPDB情報が一部確認できます。
```SQL
$ sqlplus admin/xxxxxxxx@testdb01.xxxxxxxxxxxx.ap-northeast-1.rds.amazonaws.com:1521/testdb01

SQL> show con_name

CON_NAME
------------------------------
TESTDB01

SQL> alter session set container=cdb$root;
ERROR:
ORA-01031: insufficient privileges

SQL> select pdb_id, pdb_name, dbid, status from cdb_pdbs;

    PDB_ID PDB_NAME         DBID STATUS
---------- ---------- ---------- ----------
         3 TESTDB01   xxxxxxxxxx NORMAL

SQL> select con_id, dbid, name, open_mode from v$pdbs;

    CON_ID       DBID NAME       OPEN_MODE
---------- ---------- ---------- ----------
         3 xxxxxxxxxx TESTDB01   READ WRITE

```

# まとめ
非CDB構成からCDB構成の変更を実施してみました。
RDSの場合には、CDB構成でも非CDB構成と全く違和感なく利用する事ができるため、構成変更時のダウンタイムは発生しますがアプリケーションの変更等は一切必要ありません。
来るべき23cに向けて、準備を行っておきましょう。

マルチAZ構成の時の動作も、シングルとほぼ同じとなり、ダウンタイムも同等でした。非CDBからCDB構成への変更はDB内部で変更が行われているため、当然の結果と考えられます。

#### おまけ

非CDBからCDBへの移行がどのように実施されているのかは内部の動きなので分かりませんが、alertログを見てみると少し状況が確認できます。以下にCDB移行前（1．alert_TESTDB01.log）と移行中（2．alert_RDSCDB.log）、移行完了時（3．alert_RDSCDB.log）のアラートログに残っている初期化パラメータの値になります。当然ながら移行前（1．）と移行後（3．）はほぼ同じパラメータになっていることが確認できます（パラメータグループ自体それぞれ非CDB、CDBのデフォルトでもある）。
移行中（2．）のタイミングで pdb_file_name_convert が設定されていたり、db_create_file_destがPDBSEEDを指していたりと、内部的には [AutoUpgradeによる非CDBからPDBへのアップグレードおよび変換](https://docs.oracle.com/cd/F19136_01/spucs/upgrading-oracle-database-autoupgrade.html#GUID-1A9651AE-854F-47F4-8BAE-166F0A35FB16) が実行されているものと想定されます。


```:1．非CDB構成時(alert_TESTDB01.log)
  processes                = 1652
  use_large_pages          = "ONLY"
  spfile                   = "/rdsdbbin/oracle/dbs/spfileTESTDB01.ora"
  filesystemio_options     = "setall"
  max_idle_blocker_time    = 0
  sga_target               = 11680M
  memory_target            = 0
  control_files            = "/rdsdbdata/db/TESTDB01_A/controlfile/control-01.ctl"
  compatible               = "19.0.0"
  log_archive_dest_1       = "location="/rdsdbdata/db/TESTDB01_A/arch/redolog", valid_for=(ALL_LOGFILES,ALL_ROLES)"
  log_archive_format       = "-%s-%t-%r.arc"
  archive_lag_target       = 300
  db_create_file_dest      = "/rdsdbdata/db"
  db_recovery_file_dest_size= 1G
  standby_file_management  = "AUTO"
  undo_tablespace          = "UNDO_T1"
  heat_map                 = "OFF"
  db_block_checking        = "MEDIUM"
  recyclebin               = "OFF"
  DBFIPS_140               = FALSE
  local_listener           = "(address=(protocol=tcp)(host=10.12.52.xxx)(port=1521))"
  job_queue_processes      = 50
  _kolfuseslf              = TRUE
  audit_file_dest          = "/rdsdbdata/admin/TESTDB01/adump"
  db_name                  = "TESTDB01"
  db_unique_name           = "TESTDB01_A"
  open_cursors             = 300
  pga_aggregate_target     = 2038083072
  max_string_size          = "STANDARD"
  _disable_directory_link_check= TRUE
  dg_broker_config_file1   = "/rdsdbdata/config/dr1TESTDB01.dat"
  dg_broker_config_file2   = "/rdsdbdata/config/dr2TESTDB01.dat"
  diagnostic_dest          = "/rdsdbdata/log"
  enable_pluggable_database= FALSE
```

```:2．CDB構成変更 1回目のrestart時(alert_RDSCDB.log)
  processes                = 150
  disk_asynch_io           = TRUE
  filesystemio_options     = "setall"
  sga_target               = 5G
  control_files            = "/rdsdbdata/db/cdb/RDSCDB_A/controlfile/control-01.ctl"
  db_block_size            = 8192
  compatible               = "19.0.0"
  log_archive_dest_1       = "location="/rdsdbdata/db/cdb/RDSCDB_A/arch/redolog",  valid_for=(ALL_LOGFILES,ALL_ROLES)"
  log_archive_format       = "-%s-%t-%r.arc"
  db_create_file_dest      = "/rdsdbdata/db/cdb/pdbseed"
  db_create_online_log_dest_1= "/rdsdbdata/db"
  db_recovery_file_dest_size= 1G
  undo_tablespace          = "UNDO_T1"
  _enable_secure_sub_role  = TRUE
  remote_login_passwordfile= "EXCLUSIVE"
  db_domain                = ""
  job_queue_processes      = 0
  audit_file_dest          = "/rdsdbdata/admin/RDSCDB/adump"
  audit_trail              = "DB"
  db_name                  = "RDSCDB"
  db_unique_name           = "RDSCDB_A"
  open_cursors             = 300
  pga_aggregate_target     = 170M
  max_string_size          = "STANDARD"
  diagnostic_dest          = "/rdsdbdata/log"
  enable_pluggable_database= TRUE
  pdb_file_name_convert    = "/rdsdbdata/db/cdb/RDSCDB/datafile"
  pdb_file_name_convert    = "/rdsdbdata/db/cdb/pdbseed"
  common_user_prefix       = ""
  max_pdbs                 = 3
```

```:3．CDB構成変更 最後のrestart時(alert_RDSCDB.log)
  processes                = 1652
  use_large_pages          = "ONLY"
  spfile                   = "/rdsdbbin/oracle/dbs/spfileRDSCDB.ora"
  filesystemio_options     = "setall"
  max_idle_blocker_time    = 0
  sga_target               = 11680M
  memory_target            = 0
  control_files            = "/rdsdbdata/db/cdb/RDSCDB_A/controlfile/control-01.ctl"
  compatible               = "19.0.0"
  log_archive_dest_1       = "location="/rdsdbdata/db/cdb/RDSCDB_A/arch/redolog", valid_for=(ALL_LOGFILES,ALL_ROLES)"
  log_archive_format       = "-%s-%t-%r.arc"
  archive_lag_target       = 300
  db_create_file_dest      = "/rdsdbdata/db/pdb"
  db_create_online_log_dest_1= "/rdsdbdata/db/cdb"
  db_recovery_file_dest_size= 1G
  standby_file_management  = "AUTO"
  undo_tablespace          = "UNDO_T1"
  heat_map                 = "OFF"
  db_block_checking        = "MEDIUM"
  recyclebin               = "OFF"
  DBFIPS_140               = FALSE
  local_listener           = "(address=(protocol=tcp)(host=10.12.52.xxx)(port=1521))"
  job_queue_processes      = 50
  _kolfuseslf              = TRUE
  audit_file_dest          = "/rdsdbdata/admin/RDSCDB/adump"
  db_name                  = "RDSCDB"
  db_unique_name           = "RDSCDB_A"
  open_cursors             = 300
  pga_aggregate_target     = 2038083072
  max_string_size          = "STANDARD"
  _disable_directory_link_check= TRUE
  dg_broker_config_file1   = "/rdsdbdata/config/dr1RDSCDB.dat"
  dg_broker_config_file2   = "/rdsdbdata/config/dr2RDSCDB.dat"
  diagnostic_dest          = "/rdsdbdata/log"
  enable_pluggable_database= TRUE
  noncdb_compatible        = TRUE
  common_user_prefix       = ""
  pdb_lockdown             = "RDSADMIN_PDB_LOCKDOWN"
```