MySQL 5.1.39リリース

出ました。今回はバグ修正が20件あり、そのうちパーティショニング機能に関するものが4件、レプリケーションに関するものが9件となっています。
今回のバグ修正のうちBug#28976、正確にはBug#28976を取り巻く状況は覚えておいた方が良いと思います。解説します。

 ステートメントベースのバイナリログを使用している場合、一つのトランザクション内でトランザクション対応のテーブルとトランザクション非対応のテーブルを両方更新するには、次のようにしなければなりません。まず最初にMyISAMなどトランザクション非対応のテーブルを更新し、次にInnoDBなどトランザクション対応のテーブルを更新します。
 なぜこうしなければならないのかというと、InnoDBMyISAMの順番で更新を行った場合、MyISAMテーブルの更新内容が他のコネクションから即座に見えるようになる一方で、この更新内容はCOMMITするまでバイナリログに書き込まれないためです。これはつまり、レプリケーションのマスタとスレーブの間で不整合が起こりうるということを意味しています。

不整合が起こる例を以下に示します。

conn1> begin;
conn1> insert into t_innodb values (1);
conn1> insert into t_myisam values (2);
conn2> insert into t_myisam select * from t_myisam;
conn1> commit;
conn1> select * from t_myisam;
 +------+
 | c1   |
 +------+
 |    2 |
 |    2 |
 +------+
2 rows in set (0.01 sec)

このときバイナリログは以下のようになります。conn2のINSERT文が即座にバイナリログに書き込まれるのに対し、conn1のINSERT文はCOMMITされるまで書き込まれないため、順番が入れ替わってしまいます。最終的にt_myisamテーブルには1レコードしか入っていないという状態になるので、結果としてスレーブのデータが壊れたり、バックアップからのリカバリが不可能になるといったトラブルが発生することになります。

insert into t_myisam select * from t_myisam;
BEGIN;
insert into t_innodb values (1);
insert into t_myisam values (2);
COMMIT;

ここまではMySQLの仕様です。この挙動はMySQL 5.1.39でも変わっていません。

 しかしながらいくつかのケースで、この状態が適切に扱われていませんでした。つまりこれまでは、あるSQL文がレプリケーションの整合性を保つ上で安全なのか安全ではないのかが、正しく判定されていませんでした。特に、トランザクション対応テーブルとトランザクション非対応テーブルを一度に更新する複数テーブルUPDATEや、トランザクション対応テーブルに仕掛けられたトリガによってトランザクション非対応のテーブルを更新するような処理(逆も同じです)が安全ではないということが判定できていませんでした。
 今回の修正で、一つのトランザクション内でトランザクション対応テーブルとトランザクション非対応テーブルを更新する際のレプリケーションの整合性に関する判定は、以下のように変更されました。ただし、これはステートメントベースのバイナリログを使用している場合に限ったものとなります。

  1. トランザクション対応テーブルを更新するより先に行われたトランザクション非対応テーブルの更新は、安全です
  2. トランザクション対応テーブルのみを更新する処理は、安全です
  3. トランザクション対応テーブルとトランザクション非対応テーブルの両方に影響する処理は、安全ではありません。これは、両方とも更新することとは限りません。例えば「INSERT INTO innodb_table SELECT * FROM myisam_table」は安全ではないとみなされます

ルール3は細かく見ていけば安全なパターンもあるのかもしれませんが、すべてまとめて安全ではないと判定する方に倒したということですね。
要するにそもそもMyISAMInnoDBを混在させて使うなという話なのですが、混在がやむを得ない構成として例えば以下のものが考えられます。

  • 基本的にInnoDBを用いながら、MyISAM全文検索機能を利用する構成
  • MyISAMテーブルを監査ログとして用いる構成。InnoDBのテーブルにトリガを仕掛けて、MyISAMのテーブルに監査ログをINSERTします。トランザクションがROLLBACKされても監査ログが残るところがポイントです

特に二つ目の監査ログとしての使い方は完全にルール違反になるので、厳しいですね。スレーブで監査ログが多少前後するのは問題ない場合もあるかもしれませんが、いずれにせよ慎重に検討する必要があるでしょう。
MySQL 5.4では行ベースのバイナリログを使用した場合に限り、トランザクション対応テーブルの更新とトランザクション非対応テーブルの更新が任意の順番で混在できるようになる予定です。現在WL#2687: Write non-transactional binlog events directly to binary logで作業が進められています。