読者です 読者をやめる 読者になる 読者になる

ストレージエンジン混在でレプリケーション

ストレージエンジンで MyISAMInnoDB が混在している環境でレプリケーションしたらどうなるか気になったのでやってみました。

前提条件

5.5.16 で、ステートメントベースでレプリケーションしてます。

テーブル定義

CREATE TABLE ii (
  id INT NOT NULL PRIMARY KEY
) ENGINE=innodb;

CREATE TABLE mm (
  id INT NOT NULL PRIMARY KEY
) ENGINE=myisam;

両方のテーブルを更新してコミット

BEGIN;

INSERT INTO ii VALUES (1);
INSERT INTO mm VALUES (1);
/* この時点ではまだバイナリログに書かれない */

COMMIT;
/* コミット時に↑のINSERTも含めてバイナリログに書かれる */

両方のテーブルを更新してロールバック

BEGIN;

INSERT INTO ii VALUES (1);
INSERT INTO mm VALUES (1);
/* この時点ではまだバイナリログに書かれない */

ROLLBACK;
/* ロールバックも含めてバイナリログに書かれる */


トランザクション中の更新は、トランザクションが完了した時点でバイナリログに記録されているようです。
ロールバックした場合も ROLLBACK も含めてバイナリログに記録されているので、↑の例のようにトランザクション中に非トランザクションテーブルを更新しても正しくレプリケーションされました*1


ただし・・・次のようなケースでレプリケーションが崩れてしまいました(インデントしているSQLは別セッションから実行するという意味です)。

BEGIN;

INSERT INTO ii VALUES (1);
INSERT INTO mm SELECT * FROM ii;
/* InnoDBテーブルを元にした更新を行う */

  INSERT INTO mm SELECT IFNULL(MAX(id)+1, 1) FROM mm;
  /* 別セッションでMyISAMテーブルを元にした更新を行う */

ROLLBACK;

トランザクションが完了するまでバイナリログに記録されないため、スレーブでは次の通り順番で実行されます。

BEGIN;
INSERT INTO mm SELECT IFNULL(MAX(id)+1, 1) FROM mm;
COMMIT;

BEGIN;
INSERT INTO ii VALUES (1);
INSERT INTO mm SELECT * FROM ii;
ROLLBACK;

実行順が変わったことでスレーブで一意制約エラーが発生してレプリケーションが止まります。
まぁそもそもストレージエンジンが混在したような状況が稀だし、混在して同じトランザクションで更新するとかあり得なさそうなので実際にこれが問題になることは無いだろうと思いますが・・・

ちなみに行ベースのレプリケーションだと、トランザクション内でもMyISAMテーブルは直ぐにレプリケーションされるし、↑のケースでも正しくレプリケーションされました。

*1:昔はロールバックした場合はバイナリログに記録されていなかったような気がしますが・・勘違い?