そもそも、MariaDBが選択できるならそれも良いかも
今回は移行先がMySQLと決まってしまっていたため、仕方なかったが、MySQLと互換性のあるMariaDBを選択できるのであれば、MariaDBを選択したほうが楽と思われる。
なぜならMariaDBにはOracle互換モードというものがある為。
全体の流れ
今回Oracle→MySQL移行(コンバート、コピー)は、以下の流れでコンバートした。
- OracleからMySQL定義を移行する
- いくつかエラーとか出るから個別に対処する
- データを移行する
- MySQL側の定義を調整する
- 照合順序
- 文字コード
- 主キー
- UNIQUEキー
- 外部キー
- SEQUENCE
- MySQLの、AUTO_INCREMENT に変える
- または、SEQUENCEの仕組みをMySQL側に手動で作成する
「MySQL側の定義を調整する」は、順番としては定義の移行直後にすべきだが、あとから「あれも」「これも」設定しなければならないという感じでポロポロ出てきた。
その為、その都度MySQL側の定義を設定する。
MySQLの定義は、移行元のOracleのDDL(定義)が複雑であればあるほど、ツール一発で移行という訳には、2022年3月22日時点ではいかないので、手動で設定していって、できあがったものを正とする。
他のMySQL環境に作成したMySQL環境を移したいときはDUMPから移せばいい。
環境
それぞれのバージョン↓
- Oracleのバージョンは、12c
- MySQLのバージョンは、8.0
で実施した。
MySQLで大文字小文字を区別しない設定をした
Oracleでは大文字小文字を区別しなかったため、MySQLでも大文字小文字を区別しない設定にした。
lower_case_table_names
は、サーバーの初期化時にのみ構成できます。
なので、大文字小文字を区別しない設定をする場合は、最初に忘れず設定すること。
MySQL側の文字セットをutf8mb4に設定
以下追記。
[mysql]
default-character-set=utf8mb4
[mysqld]
character_set_server=utf8mb4
collation-server=utf8mb4_bin
(助かりました)
↓
設定確認。
MySQLに接続して、以下実行。
mysql> SHOW VARIABLES LIKE 'character_set%' -> ;
+--------------------------+----------------------------+
| Variable_name | Value |
+--------------------------+----------------------------+
| character_set_client | utf8mb4 |
| character_set_connection | utf8mb4 |
| character_set_database | utf8mb4 |
| character_set_filesystem | binary |
| character_set_results | utf8mb4 |
| character_set_server | utf8mb4 |
| character_set_system | utf8mb3 |
| character_sets_dir | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+
8 rows in set (0.01 sec)
mysql>
Oracle→MySQL 定義(DDL)の移行
一部うまく行かない所があったが、こちらのQiitaの記事どおりでうまく行った。(アザス!!)
- SQL DeveloperでOracleからDDLのみをエクスポート
- sqlinesでMySQL用にDDLをコンバート
- mysql -f -uroot DB名 < MySQL用のDDL で、MySQLにインポート
-
オプション -f (Force)をつけて実行しないと駄目だった
-
いくつかエラーが出たので以下に記載する。それ以外は、問題なく、OracleからMySQLへのデータ型は同等のものが割り振られていた(MySQL用のSQLクエリに記述されていた)。
sqlines優秀。
駄目だったもの1.Oracleでの、CREATE TABLE 時に PRALLEL 句がついてるもの
Oracleでの、CREATE TABLE 時の PRALLEL ってなに?
⇒https://docs.oracle.com/cd/E57425_01/121/SQLRF/statements_7002.htm
MySQL8 で、Parallel が使えるの(読み取りだけっぽい)innoDBみたい。
だが、インポート先のエンジンはinnoDBだったのでこの問題ではない。
とりあえず、DDLから手動でParallel句を削ってインポートしたら、
インポートできた。
駄目だったもの2. DECIMAL 型の第荷引数に負の数を指定している
MySQLのDECIMAL型
MySQLインポート時に以下のエラーが出てた。
ERROR 1064 (42000) at line 320: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '-2),
インポートに失敗した部分のデータ定義を確認すると、
`カラム名` DECIMAL(7,-2),
のようになってた。
DECIMAL[(M[,D])] [UNSIGNED] [ZEROFILL]
M は桁数の合計 (精度) で、D は小数点以下の桁数 (スケール) です。
小数点以下の桁数が「-2」っておかしい ってことでしょうな。
OracleのNumber型
インポートされたデータを、Oracle側で確認してみると、Number型だった。
"カラム名" NUMBER(7,-2),
負のスケールを指定すると、Oracle Databaseにより小数点の左側の指定した桁数で実際のデータが丸められます。たとえば、(7,-2)という指定は、表26-1に示されているとおり、Oracle Databaseによって100の位で丸めることを意味します。
Number型の第二引数で負数を指定すると、指定した桁で丸めるということらしい。
例えば、Number型の第二引数が「-2」の場合、100の桁で丸められるということだから、
7456124
↓
7456100
となる。
MySQLでも、指定した桁で数字を丸めるデータ型とかあるのか?
探してみたけど、見つからなかった。
対応としては、一旦、
NUMBER(7,-2) # Oracle
↓
DECIMAL(7,0) # MySQL
に変更して対応しようかとしたが、
データの利用目的を調べると、不要なテーブルということが分かったので、テーブルごと削除することで対応した。
OracleのDecimal型
ちなみにOracleでもDecimal型は第二引数に負数を指定できない。
scaleパラメータは、小数点の右側にくる桁数のことで、スケール変更係数と呼びます。デフォルト値は0(ゼロ)です(整数となります)。全体の桁数より大きい数は指定できますが、負数は指定できません。
次に例を示します。
sal DECIMAL (7,2)
駄目だったもの3. DECIMAL→DECIMAL変換で、そのまま移行すると引数の右辺が左辺より大きくなってエラー
詳細は割愛するが、Oracleで、decimal(4,9) だったものが、
MySQLでdecimal(4,9)になると、引数の右辺が左辺より大きくなる。この場合だと、9が4より大きくなるのでMySQLにインポートできずエラーになる。
以下を参考にした。
- Oralce
- https://docs.oracle.com/cd/E16338_01/server.112/b56299/sql_elements001.htm
- 1以上の数値の場合の取り扱いはどうなる?
- MySQL
対応としては、
Oracleの decimal(4,9) は、
MySQL側で、decimal(10,9)
にすることを考えたが、
データの利用目的を調べると、不要なテーブルということが分かったので、テーブルごと削除することで対応した。
Oracle→MySQL データの移行
実行環境の準備
まず、実行環境の準備。
- Oracleからのエクスポートに、sql*plus
- sqlplusの12以上(csv出力ができるVersion)
- MySQLへのインポートに、mysql-client
が必要なので、それぞれ用意する。
環境変数設定(sql*plus用)
$ export LANG = ja_JP.UTF–8
$ export NLS_LANG=Japanese_Japan.AL32UTF8
データ移行実行
前準備
MySQL側で、ファイルからのデータインポートを許可していない場合は、以下を参考に、一時的に許可実施する。
MySQL 8.0 で LOAD DATA INFILE LOCAL を利用するには、
サーバとクライアント両方で local-infile パラメータを ON にする必要がある
⇒https://mita2db.hateblo.jp/entry/2020/01/13/163218
サーバ側で設定。
$ mysql -uroot
↓
mysql> SET GLOBAL local_infile=on;
Query OK, 0 rows affected (0.00 sec)
mysql>
この設定はMySQLを切断するともとに戻る。
実行
githubに公開してくださっているシェルスクリプトに手を加えて実行した。
手を加えたものはこちらに置いた。
- githubから上記の「こちら」ダウンロード(git clone でも可)
- 以下のファイルを編集して自分の環境用に書き換える
- 1_ora-my-convert/env.txt
- sql*pulsのローカルマシン内のPath
- Oracleの接続情報
- MySQLの接続情報
- 1_ora-my-convert/wrap_table_record_oracle_to_mysql.sh
- 対象のテーブル名すべて
- 1行に1テーブル書く
- 対象のテーブル名すべて
- 2_ora-my-check/mysql-table-get.php
- 対象のテーブル名すべて
- 1行に1テーブル書く
- 対象のテーブル名すべて
- 1_ora-my-convert/env.txt
- シェルスクリプトに実行権付与
-
chmod + x 1_ora-my-convert/*.sh
-
- OracleからMySQLへデータ移行実行
-
cd 1_ora-my-convert/
-
./wrap_table_record_oracle_to_mysql.sh
-
: end: コマンドが見つかりません のエラー
: end: コマンドが見つかりません
っていうエラーが出るのは、データの件数が0件のため。
OracleもMySQLもデータが0件なら問題ない。
データ移行後確認
OracleとMySQLそれぞれからcsvファイルにエクスポートしたものを比較することにする。
- シェルスクリプトに実行権付与
-
chmod + x 2_ora-my-check/*.sh
-
MySQLのデータ取得
- MySQLからデータ取得(比較用)
-
cd 2_ora-my-check
-
php ./mysql-table-get.php
-
OracleとMySQLのデータたちを比較する
- OracleとMySQLのデータ比較
-
./chk.sh
- なにも表示されなければ問題ない。
- chk.shの最後の行で、diffコマンドをかけている。
- なにも表示されなければ問題ない。
-
Oracleからインポートできないデータがあった(データ欠損)
Oracleからインポートできないデータがあった。
これについては検証環境のOracleのDDLをいじることで対応した。
コメント