2010年6月11日金曜日

OracleベースのWebアプリをMySQLベースに移行した(1)

6月初めごろから始めたOracleベースのWebアプリケーションのMySQL化が完了しました。
BLOGへのエントリーがタイムリーでないのが、いまいちですが。。

基本的な作業タスクは以下の通りです。


・MySQL環境の構築
・データベースの移行(OracleからMySQLへ)
・Webアプリケーションの改変(基本的にはSQL文)


MySQLもRailsのチュートリアルで使用する程度で簡単にしか触ったことがなかったので本当にリアルに使っているWebアプリケーションが簡単に移行できるかは全くわかりませんでした。

実際にやってみると予想以上に簡単に移行できました。

工数的には4人日程度です。

アプリケーション規模は以下の通り

・テーブル数:18テーブル
・画面数:30画面
・CSV出力アプリ:1本

アプリケーションの概要はユーザマニュアル/管理者マニュアルを参照してください。

MySQLは、日本語情報もそこそこ多く、移行対象のWebアプリが使っているOracleの機能は、MySQLにも存在することが比較的簡単に知ることができて、実際に使ってみてもとても簡単でした。

ただし、日本語マニュアルに記載がないものがあるので、最新の英語マニュアルもチェックすると良いと思います。

この移行作業について何回かに分けてBLOGで紹介したいと思います。

#どこから記載するのがいいのかもいろいろ迷ったのですがMySQLはインストールされている状態で移行用のデータベース作成するMySQLシステムの設定から紹介したいと思います。

MySQL環境の構築


◆移行作業に必要な基本知識

・MySQLサービスの起動/停止は?(@Oracle:インスタンス起動とデータベースopen)

 mysqld スクリプトを使用します。

 起動・停止の例)
 # /etc/init.d/mysqld start
 # /etc/init.d/mysqld stop

 MySQLの推奨では、MySQL のサービスが障害で停止してしまっても自動的に再起動する mysqld_safe というスクリプトを使ってデータベースを起動させますが、更新系のアプリケーションで利用する場合は、自動的に再起動はしたくないので使いませんでした。参照系DBには良いかもしれませんね。

 # /usr/bin/mysqld_safe &
 
・利用するコマンドラインツールは?(@Oracle:sqlplus、sqlldr)

 mysqladmin、mysql、mysqlimport コマンドを利用します。

 インストール直後には root ユーザのパスワード設定で mysqladmin コマンドを使用します。

 # /usr/bin/mysqladmin -u root password 'new-password'

 rootパスワードを変更した後、mysql コマンドでログインしデータベース、ユーザ、権限付与、テーブル作成などを行い、mysqlimport でCSVデータをロードします。

・データベースのメタデータ情報はどうやって知るの?(@Oracle:ディクショナリビュー、DBA_xxx)

 MySQLには、information_schema データベースがあります。
 
 Oracleのメタ情報は、ディクショナリビュー(DBA_xxxx、ALL_xxx、USER_xxx)で確認しますが、

 MySQLのメタ情報は、information_schema で確認することができます。
 MySQLメタ情報は、Oracleのディクショナリビューのように膨大な情報ではないために把握するのは簡単ですね。
 information_schemaが保持しているテーブルは以下の通りです。
 それぞれのテーブル構造の確認もOracleでやるように mysql> desc table_name; で出来るんですね。

mysql> use information_schema
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
mysql> show tables;
+---------------------------------------+
| Tables_in_information_schema |
+---------------------------------------+
| CHARACTER_SETS |
| COLLATIONS |
| COLLATION_CHARACTER_SET_APPLICABILITY |
| COLUMNS |
| COLUMN_PRIVILEGES |
| KEY_COLUMN_USAGE |
| PROFILING |
| ROUTINES |
| SCHEMATA |
| SCHEMA_PRIVILEGES |
| STATISTICS |
| TABLES |
| TABLE_CONSTRAINTS |
| TABLE_PRIVILEGES |
| TRIGGERS |
| USER_PRIVILEGES |
| VIEWS |
+---------------------------------------+
17 rows in set (0.00 sec)

mysql> desc tables;
+-----------------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-----------------+--------------+------+-----+---------+-------+
| TABLE_CATALOG | varchar(512) | YES | | NULL | |
| TABLE_SCHEMA | varchar(64) | NO | | | |
| TABLE_NAME | varchar(64) | NO | | | |
| TABLE_TYPE | varchar(64) | NO | | | |
| ENGINE | varchar(64) | YES | | NULL | |
| VERSION | bigint(21) | YES | | NULL | |
| ROW_FORMAT | varchar(10) | YES | | NULL | |
| TABLE_ROWS | bigint(21) | YES | | NULL | |
| AVG_ROW_LENGTH | bigint(21) | YES | | NULL | |
| DATA_LENGTH | bigint(21) | YES | | NULL | |
| MAX_DATA_LENGTH | bigint(21) | YES | | NULL | |
| INDEX_LENGTH | bigint(21) | YES | | NULL | |
| DATA_FREE | bigint(21) | YES | | NULL | |
| AUTO_INCREMENT | bigint(21) | YES | | NULL | |
| CREATE_TIME | datetime | YES | | NULL | |
| UPDATE_TIME | datetime | YES | | NULL | |
| CHECK_TIME | datetime | YES | | NULL | |
| TABLE_COLLATION | varchar(64) | YES | | NULL | |
| CHECKSUM | bigint(21) | YES | | NULL | |
| CREATE_OPTIONS | varchar(255) | YES | | NULL | |
| TABLE_COMMENT | varchar(80) | NO | | | |
+-----------------+--------------+------+-----+---------+-------+
21 rows in set (0.00 sec)

mysql>


・データベースの初期化パラメータは?(@Oracle:初期化パラメータ(init.ora)、環境変数)

 /etc/my.cnf に設定します。

 Oracleの場合は、環境変数および初期化パラメータによってデータベースの初期化が行われます。
 同様にMySQLでは my.cnf という構成ファイルにパラメータを設定してシステムの初期化を行います。
 今回は以下のような最低限必要そうな設定をしました。

 1)サーバーの文字コードセットのデフォルト設定(character-set-server)

  Oracleの場合はデータベースの文字コードはcreate databaseで設定します。データベース作成後にalter database文で変更することも9iまでは可能だったと思いますが、現在では文が廃止されて専用のコマンドDatabase Character Set Scanner(CSSCAN)を使って検証し、CSALTERというPL/SQLのスクリプトで変更(またはexp/impなど)するなど実際の文字コードの変換は非常に面倒です。

  ただしMySQLの場合は、文字コードは大変柔軟に設定できるのですね。
  以下の順で設定が有効になります。
  カラム属性 > テーブル属性 > データベース属性 > my.cnf(character-set-server)

 2)照合順序の指定(collation-server)

  照合順序の指定とマニュアルにあるが日本語の場合にどうなるのかいまいちよくわかりません。
  サーバーの文字コードをutf8にすると照合順序のデフォルトは
  utf8_general_ciになるようです。
  blogなどを見てみるとカタカナとひらがなを同一視するような記述もありますね。

 3)ストレージエンジンの設定(default-storage-engine)

  ストレージエンジンとはI/Oの実装部分の仕様です。
  MySQLには複数のストレージエンジンがありますが、デフォルトはMyISAMというISAMファイルです。
  Oracleから移行するデータベースにはACID特性をサポートしたINNODBを指定します。
  INNODBは行レベルロックもサポートする仕様です。
  人によっては完全にサポートされていないという話も聞きますが。。何か情報があれば教えてください。

 4)クライアントからの接続セッションの初期設定(init_connect)

  Oracleでは初期化パラメータやalter sessionで接続しているクライアントのセッション構成を変更することが可能ですが、MySQLにもSETコマンドが存在します。このSETコマンドを init_connect 変数に記述することですべてのクライアントのセッションに適用することができます。
  ※ただし init_connect 変数への記述は、SUPER権限をもつユーザ(root)には適用されません。ここで指定したコマンドがエラーになりSUPERユーザの接続の妨害を防ぐためだそうです。

  このパラメータには、以下のコマンドを設定しました。

  ・クライアントの文字コードセットの指定
  ・トランザクションのコミット属性(autocommitをfalseへ)

   MySQLのコミット属性のデフォルト autocommit です。
   デフォルトではmysqlコマンドで発行するSQLもすべて1文ずつコミットされてしまいます。
   Oracleと同様の動きを期待する場合は、上記のパラメータでautocommitを無効にします。

MySQLのシステム変数の詳細は以下のマニュアルを参考にしてください。

参考:MySQLのシステム変数の詳細日本語マニュアル

********* /etc/my.cnf の内容 ************
[mysqld]
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
user=mysql

default-character-set = utf8
character-set-server = utf8
collation-server = utf8_general_ci
init_connect='SET autocommit=0; SET NAMES utf8'
default-storage-engine = INNODB

[mysqld_safe]
log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid
****************************************

※上記の1)-5)で説明したパラメータ以外はデフォルトで指定されています。
 datadir はMySQLにデータベースを作成した際に物理ファイルを配置するルートディレクトリを指定します。このディレクトリ配下にデータベース名のディレクトリが作成されてテーブルごとにテーブル名.frmというファイルが作成されます。


**** MySQLデータベースの物理ファイル例 ****
[root@ip-10-130-6-146 ~]# ls -al /var/lib/mysql/helpdesk
合計 256
drwx------ 2 mysql mysql 4096 2010-06-07 13:17 .
drwxr-xr-x 5 mysql mysql 4096 2010-06-15 13:38 ..
-rw-rw---- 1 mysql mysql 8726 2010-06-01 13:54 APSERVER_M.frm
-rw-rw---- 1 mysql mysql 8694 2010-06-01 13:03 COMPONENT_M.frm
-rw-rw---- 1 mysql mysql 8768 2010-06-01 13:03 CUSTOMER_M.frm
-rw-rw---- 1 mysql mysql 8696 2010-06-01 13:03 DB_M.frm
-rw-rw---- 1 mysql mysql 8626 2010-06-01 13:03 DOCTYPE_M.frm
-rw-rw---- 1 mysql mysql 13023 2010-06-03 10:40 DOC_M.frm
-rw-rw---- 1 mysql mysql 8965 2010-06-03 10:42 FAQ_M.frm
-rw-rw---- 1 mysql mysql 8558 2010-06-01 13:03 IPTBLS.frm
-rw-rw---- 1 mysql mysql 16857 2010-06-03 10:57 NEWS_M.frm
-rw-rw---- 1 mysql mysql 8675 2010-06-01 13:03 OS_M.frm
-rw-rw---- 1 mysql mysql 21019 2010-06-01 13:03 PRODUCT_M.frm
-rw-rw---- 1 mysql mysql 8629 2010-06-01 13:03 ROLE_M.frm
-rw-rw---- 1 mysql mysql 8633 2010-06-01 13:03 SUP_LEVEL_M.frm
-rw-rw---- 1 mysql mysql 8629 2010-06-01 13:03 SUP_TYPE_M.frm
-rw-rw---- 1 mysql mysql 9016 2010-06-03 10:56 TAR_HISTORY.frm
-rw-rw---- 1 mysql mysql 9825 2010-06-07 13:17 TAR_M.frm
-rw-rw---- 1 mysql mysql 8808 2010-06-01 13:03 TAR_STATUS_M.frm
-rw-rw---- 1 mysql mysql 13356 2010-06-01 13:03 USER_M.frm
-rw-rw---- 1 mysql mysql 61 2010-05-28 18:12 db.opt
[root@ip-10-130-6-146 ~]#
******************************

・設定したシステム変数の確認

my.cnf の指定が終わったらmysqlを再起動してシステム変数を確認してみましょう。

 show variables;


**** SUPER権限を持つ root ユーザで確認した例)****
[root@ip-10-130-6-146 ~]# mysql -u root -p
Enter password:

mysql> show variables like 'character_set%'; show variables like 'init_con%';
+--------------------------+----------------------------+
| Variable_name | Value |
+--------------------------+----------------------------+
| character_set_client | latin1 |
| character_set_connection | latin1 |
| character_set_database | utf8 |
| character_set_filesystem | binary |
| character_set_results | latin1 |
| character_set_server | utf8 |
| character_set_system | utf8 |
| character_sets_dir | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+
8 rows in set (0.00 sec)

+---------------+----------------------------------+
| Variable_name | Value |
+---------------+----------------------------------+
| init_connect | SET autocommit=0; SET NAMES utf8 |
+---------------+----------------------------------+
1 row in set (0.00 sec)
***************************************************

root ユーザはSUPER権限を保有するので init_connect に指定した文字コードの設定が無効になっているのがわかります。
一般ユーザでmysqlにログインして同様のコマンドを実行すると以下のようにクライアントの文字コードの設定もutf8になっているのがわかります。

***************************************************
mysql> show variables like 'character_set%'; show variables like 'init_con%';
+--------------------------+----------------------------+
| Variable_name | Value |
+--------------------------+----------------------------+
| character_set_client | utf8 |
| character_set_connection | utf8 |
| character_set_database | utf8 |
| character_set_filesystem | binary |
| character_set_results | utf8 |
| character_set_server | utf8 |
| character_set_system | utf8 |
| character_sets_dir | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+
8 rows in set (0.00 sec)

+---------------+----------------------------------+
| Variable_name | Value |
+---------------+----------------------------------+
| init_connect | SET autocommit=0; SET NAMES utf8 |
+---------------+----------------------------------+
1 row in set (0.00 sec)

mysql>
***************************************************


以上でやっとOracleのデータベースをMySQLデータベースに移行する環境が整いました。
次回は、テーブルの移行とデータのローディングについてエントリーしたいと思います。

0 件のコメント:

コメントを投稿