ちょっと硬派なコンピュータフリークのBlogです。

カスタム検索

2009-02-16

MyISAMからInnoDBへ切り替えるときの注意点

MySQLを使い始めて間もない人がよく陥る罠の中に、気づくと使ってるストレージエンジンがMyISAMだった!ということがある。デフォルトのストレージエンジンはMyISAMなので、MySQLに詳しくない人たちが比較的陥りやすい罠なのだ。そもそもストレージエンジンという概念自体がMySQL独自のものなので仕方のない話である。MyISAMは素晴らしいストレージエンジン(たとえばこのYahoo!の中の人による投稿で言われているように)であるが、長所もあれば短所もある。例えば、
  • トランザクション対応ではない。
  • クラッシュセーフではない。
  • 更新と参照が入り乱れた場合の同時実行性能がよくない。
  • テーブルが大きく(数億行とか)なるとINSERTの性能が劣化する。
などなど。特に前者の2つが問題で、アトミックな操作が必要なところでロジックを実装出来なかったり、サーバがクラッシュした時にデータがお亡くなりになったりして喪に服する羽目になったりするなど、気づいたときにはもう遅い!という事態になってしまうので注意が必要だ。

とはいえ、MyISAMは非常に使いやすい上に高速なストレージエンジンであり、全文検索機能やテーブル圧縮など他のエンジンにはない特徴を備えているので、意図的にMyISAM上でアプリケーションを作り込んでいる場合には何ら問題はない。しかし意図しない場合は問題であり、早急にInnoDBなど他のストレージエンジンへの移行を検討する必要がある。

MyISAMからの乗り換えで筆頭に上がるのはInnoDBであるが、二つのストレージエンジンはまったく違う特性を備えているので移行には注意が必要である。ストレージエンジンのメリットは、データの格納に関するロジックを抽象化して用途に応じて透過的に変更できることであり、異なるストレージエンジンを使っても同じSQL文でテーブルのデータへアクセスできることであるが、それぞれのストレージエンジンには癖があり、特に機能面やエラー処理に差異が見受けられるのもまた事実である。前置きが長くなったが、今日はMyISAMからInnoDBに移行する際にどんなことに注意しないといけないのか?ということについて概要を紹介する。

1. InnoDBの方がデータサイズが大きい

InnoDBのデータ領域は16KBごとにページ化されており、さらにMVCCのためのメタデータ(タイムスタンプや削除フラグなど)を行ごとに持っているため、消費するデータサイズは大きくなってしまう。消費するディスクスペースはMyISAMの2〜3倍を見込んでおくといいだろう。

2. トランザクション対応

MyISAMの場合、クエリが失敗するのは何か致命的なエラーが起こった場合であることが多いのであまり重要視されていない。そのため、エラー処理はしっかりと実装されてない場合が多いのではないだろうか。しかしながら、トランザクションに対応しているRDBMSまたはストレージエンジンでは、潜在的にデッドロックが発生してしまう。そのため、高負荷時にはトランザクションが頻繁にデッドロックを起こすということが想定されるので、そのためのエラー処理が重要になる。

また、もっと基本的なことであるが、AUTO COMMITモードを使用していないときには、COMMITを明示的に発行する処理が必要になる。

3. 更新処理でMyISAMとInnoDBを混在させない

InnoDBはデッドロック検知機能があり、デッドロックが発生した場合には即座に片方のトランザクションをロールバックすることができる。しかし、InnoDBとMyISAMを混在している場合、MyISAM側の挙動はInnoDBからは見えないので、デッドロックが検知できない場合がある。(しかしその場合も一定時間でタイムアウトするので安心して欲しい。)

このような理由があるので混在は望ましくない。

4. 全文検索機能がない

MyISAMの独創的かつ特徴的な機能として全文検索機能がある。MyISAMの全文検索はデフォルトでは日本語対応していないが、Sennaを使えばモウマンタイである。しかしInnoDBでは英語であるか日本語であるかに係わらず、全文検索が利用出来ない。

また、全文検索ほど利用する頻度は高くないが、空間インデックスを利用出来るのもMyISAMだけである。

5. InnoDBでは全く異なるチューニングが必要

MyISAMではkey_buffer_sizeやmyisam_sort_buffer_sizeのチューニングが必要であるが、InnoDBではinnodb_buffer_pool_sizeやログサイズ、その他各種バッファサイズのチューニングが必要になる。しかも、それらの値を調整するストラテジはMyISAMとは全然違う。

6.PRIMARY KEYの扱い

InnoDBはクラスタインデックスを用いてデータが格納されている。そのため、PRIMARY KEYを用いた検索はとっても高速であるが、セカンダリインデックスを利用した検索はそれほど速くない。また、セカンダリインデックスのリーフノードにはPRIMARY KEYの値が格納される。そのため、サイズが大きなカラム(VARCHARなど)をPRIMARY KEYにしてしまうと、無駄なディスク領域を消費してしまうので注意が必要だ。VARCHARなどの文字列は数値よりも比較にかかる計算コストが高いので、文字列をPRIMARY KEYにするのは避けるべきである。

また、明示的にPRIMARY KEYを作成しない場合には、内部的に6バイトのROWIDがPRIMARY KEYとして作成されるが、これは無駄な領域であるので極力PRIMARY KEYを明示的につけるようにしよう。

7. バックアップ

MyISAMではmysqlhotcopyコマンドを使って高速にバックアップをとることができるが、InnoDBでは別の方法を用いる必要がある。InnoDB Hot Backupは高速だが有料である。mysqldumpは時間が掛かってしまう。レプリケーションを用いるとマスターに負荷をかけずにバックアップをとることができるが、サーバーの台数が増えてしまう。悩ましいところであるが、ベストなバックアップ方法を選択しよう。

8. データ移行作業

アプリケーションのロジックを変更しなければならないので、ストレージエンジンの変更だけでなくアプリケーションの入れ替え作業も同時に実施しなければならない場合が多い。従って移行作業はサービス停止が前提となる。レプリケーションをうまく使えばダウンタイムを最小化することが可能であるが、異なるストレージエンジン間でのレプリケーションには制限があるので、事前にしっかりとテストをしておく必要があるだろう。(RBRを利用すれば多少制限はマシになる)移行そのものはALTER TABLE tbl ENGINE=InnoDBで行うと良い。

もちろん、どのストレージエンジンを使うかということを、アプリケーションの要件に合わせて選定するのがベストであるが、うっかりMyISAMでアプリケーションを組んでしまった!という場合もあるだろう。そんな人の参考になれば幸いである。

0 コメント:

コメントを投稿