OracleからMySQLへのデータベース移行では、ストアドプロシージャやSQL構文の違いに加え、データ型の変換や文字コードの互換性が重要な課題となります。本記事では、大容量データの効率的な移行手法として、高速エクスポートツールとMySQLのロード機能を組み合わせた一括移行と、ETLツール「Kettle」を活用した差分更新の実装方法について解説します。
データ型のマッピングと注意点
移行に先立ち、OracleとMySQLのデータ型の違いを吸収する必要があります。- 日付型の扱い
Oracleの
DATE型は日付と時刻(年月日時分秒)を保持しますが、MySQLのDATE型は日付のみ(YYYY-MM-DD)を保持します。時刻情報が含まれる場合、MySQLではDATETIME型またはTIMESTAMP型にマッピングする必要があります。範囲と機能を考慮し、基本的にはDATETIME型の使用が推奨されます。デフォルト値としてSYSDATEを使用している場合、MySQLではDEFAULT CURRENT_TIMESTAMPとして定義します。 - 数値型の扱い
Oracleの
NUMBER(p, 0)は精度が高く最大126桁まで扱えますが、MySQLのDECIMAL型は最大65桁です。桁数が大きい場合はDECIMAL(65, 0)とするか、範囲内であればBIGINT等への変換を検討します。 - 文字コード
MySQL側の文字セットは、絵文字などにも対応できるよう
utf8mb4を推奨します。
大量データの移行:SQL*Loader類似ツールとLOAD DATAの活用
テラバイトクラスのデータを扱う場合、GUIツールによるエクスポートは性能限界に達しやすく、サーバーへの直接出力も困難です。そこで、コマンドラインベースの高速エクスポートツール(sqluldr2等)を用いてCSV形式でデータを抽出し、MySQLのLOAD DATA INFILE構文で取り込む手法が有効です。
1. 環境設定とエクスポート
移行元のOracleデータベースへ接続するため、クライアント環境を整えます。tnsnames.oraの設定例:
ORACLE_SOURCE =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.1.100)(PORT = 1521))
(CONNECT_DATA =
(SERVER = DEDICATED)
(SERVICE_NAME = orcl)
)
)
環境変数を設定した上で、エクスポートツールを実行します。データ内に改行や区切り文字が含まれる可能性があるため、区切り文字には特殊文字(例:16進数の0x07)を指定し、データの整合性を担保します。
エクスポート実行コマンド例:
./sqluldr2_linux64.bin USER=scott/tiger@ORACLE_SOURCE \
QUERY="SELECT /*+ PARALLEL(4) */ * FROM large_transaction_table" \
FIELD=0x07 \
FILE=/data/export/transaction_data%B.csv \
LOG=/data/export/export.log \
SIZE=50MB \
SAFE=YES
ここで、SIZEパラメータでファイルサイズを分割することで、大容量ファイルの取り扱いリスクを軽減できます。
2. MySQLへのインポート
MySQLへのデータロードはLOAD DATA構文を使用します。並列処理でエクスポートされた複数のファイルを順次取り込みます。
LOAD DATA INFILE '/data/export/transaction_data001.csv'
INTO TABLE target_db.transaction_table
CHARACTER SET utf8mb4
FIELDS TERMINATED BY X'07'
ENCLOSED BY '"'
LINES TERMINATED BY '\n';
ETLツール「Kettle」による差分更新
一括移行後、稼働中のシステムで発生した差分データを同期するために、オープンソースのETLツールであるKettle(Pentaho Data Integration)を利用します。KettleはJavaベースでクロスプラットフォーム対応であり、ビジュアルエディタで変換処理を設計できます。差分更新ジョブの設計フロー
差分更新の核心は、新旧データソースを比較し、変更があったレコードのみを抽出・反映することです。- データソースの入力 「表入力」ステップを2つ配置し、それぞれ現在の生産データ(新データ)と移行済みのターゲットデータ(旧データ)への接続を定義します。
- データの整列 「マージ(Merge Rows)」ステップでデータを比較するためには、両方のデータセットが比較キー(主キーなど)でソートされている必要があります。「ソート」ステップを事前に配置します。
- マージ(差分検出)
「マージ(差分)」ステップを使用して新旧データを結合します。このステップでは以下のフラグフィールドを出力するように設定します。
identical: 変更なしchanged: データの変更ありnew: 新規レコードdeleted: 削除されたレコード
- 処理の分岐
「Switch / Case」ステップを利用し、フラグの値に応じて後続の処理を分岐させます。
new→ INSERT処理changed→ UPDATE処理deleted→ DELETE処理(または論理削除)
ジョブのスケジューリング
作成した変換ファイルを定期実行するために、ジョブファイルを作成し、OSのスケジューラから呼び出します。 Linux環境での実行スクリプト例:#!/bin/bash
export JAVA_HOME=/usr/lib/jvm/java-11
cd /opt/kettle/data-integration
./kitchen.sh \
-file=/opt/kettle/jobs/incremental_sync.kjb \
-level=Basic \
-log=/var/log/kettle/sync.log
MySQLにおけるコメントの一括付与
移行後のテーブル定義にコメントを付与する場合、メタデータテーブルを利用してALTER文を生成できます。SELECT
CONCAT(
'ALTER TABLE ', table_schema, '.', table_name,
' MODIFY COLUMN ', column_name, ' ', column_type,
IF(is_nullable = 'NO', ' NOT NULL', ''),
IF(column_default IS NOT NULL, CONCAT(' DEFAULT ', QUOTE(column_default)), ''),
' COMMENT ', QUOTE(column_comment), ';'
) AS alter_statement
FROM information_schema.columns
WHERE table_schema = 'target_db_name';
トラブルシューティング:空文字の扱い
Kettleはデフォルト設定で空文字列をNULLとして扱う傾向があります。これにより、NOT NULL制約のあるカラムへ空文字を挿入しようとしてエラーが発生することがあります。これを防ぐには、Kettleの設定ファイル(kettle.properties)に以下の行を追加します。
KETTLE_EMPTY_STRING_DIFFERS_FROM_NULL=Y
この設定により、空文字列とNULLが明示的に区別され、データ整合性の問題を回避できます。