MySQL道普請便り

第40回 カラムのデータ型の異なる行ベースレプリケーションの挙動

この記事を読むのに必要な時間:およそ 4.5 分

MySQL 5.7以降からbinlog_formatオプションのデフォルトがROWになりました。MySQL5.6とそれ以前ではステートメントベースレプリケーション(SBR)がデフォルトでしたが,MySQL5.7以降からは行ベースレプリケーション(RBR)がデフォルトになったということです。SBRとRBRの違いについては第34回 行ベースレプリケーションの遅延についてをご確認ください。

今回は,slave_type_conversionsオプションによるカラムのデータ型の異なるRBRの挙動について紹介します。

slave_type_conversionsオプションとは

このオプションはRBRを使用するときにスレーブに対して設定するもので,カラムの型変換モードを制御します。マニュアルはslave_type_conversionsになります。デフォルトは''(空文字)であり,マスターとスレーブの間のカラムの型変換をしません。つまり,デフォルト設定のRBRではマスターとスレーブのカラムのデータ型が全て同じでなくてはならないということです。

では,マスターとスレーブ間でカラムのデータ型が異なるとどのような挙動になるか確認してみましょう。

マスターの設定

RBRの設定であることを確認します。

mysql> select @@binlog_format;
+-----------------+
| @@binlog_format |
+-----------------+
| ROW             |
+-----------------+
スレーブの設定

slave_type_conversionsがデフォルトの''(空文字)であることを確認します。

mysql> select @@slave_type_conversions;

+--------------------------+
| @@slave_type_conversions |
+--------------------------+
|                          |
+--------------------------+
マスターでt0テーブルを作成
mysql> CREATE TABLE `t0` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `col` varchar(5) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB;
スレーブでカラムcolのvarchar(5) から varchar(10)に変更
mysql> alter table t0 modify col varchar(10);

これで,マスターのカラムcolの型はvarchar(5)でスレーブのカラムcolの型はvarchar(10)という状態になります。ここでマスターで更新すると,カラムの型が違うためエラーが発生してレプリケーションが停止します。

マスターで更新
mysql> insert into t0(col) values ('ABCDE');
スレーブでレプリケーションエラー
Last_SQL_Error: Column 1 of table 'aa.t0' cannot be converted from type 'varchar(5)' to type 'varchar(10)'

slave_type_conversionsオプションにモードを設定することでこれを回避することができます。有効なモードは以下のようになります。

モード内容有効なバージョン
ALL_LOSSY不可逆変換を許可しますMySQL5.5以降
ALL_NON_LOSSY非不可逆変換を許可しますMySQL5.5以降
ALL_SIGNED昇格される整数型を符号付き値として扱いますMySQL5.6.13以降
ALL_UNSIGNED昇格される整数型を符号なし値として扱いますMySQL5.6.13以降
''(空文字)すべての変換を許可しませんMySQL5.5以降

このオプションは動的に変更可能ですが,レプリケーションの再起動が必要です(STOP SLAVEとSTART SLAVE)⁠

以下,各モードについて説明します。

ALL_LOSSY

このモードはスレーブのカラムの型がマスターのカラムの型よりも小さい場合,データを切り捨ててしまうかもしれない変換(不可逆変換)を許可します。Int型とBigint型や,varchar型とchar型などの互換性のある型であれば,レプリケーションされたデータをスレーブの型に合わせてデータを適合するということです。

たとえば,マスターがvarchar(20)でスレーブがvarchar(10)だった場合に,20文字のデータがレプリケーションされたときは10文字目までは格納して,それ以降は切り捨てて登録されます。マスターとスレーブ間でデータの不整合が起こる可能性のあるモードです。

ALL_LOSSYの動作

前述で使用したテーブルを使って試してみます。スレーブの型をvarchar(1)に変更しています。

スレーブで設定
mysql> select @@slave_type_conversions;

+--------------------------+
| @@slave_type_conversions |
+--------------------------+
| ALL_LOSSY                |
+--------------------------+

mysql> alter table t0 modify col varchar(1);
Query OK, 0 rows affected (0.00 sec)
マスターで更新
mysql> insert into t0(col) values ('ABCDE');
Query OK, 1 row affected (0.00 sec)

mysql> select * from t0;
+----+------+
| id | col  |
+----+------+
|  1 | ABCDE|
+----+------+
1 rows in set (0.00 sec)
スレーブで確認
mysql> select * from t0;
+----+------+
| id | col  |
+----+------+
|  1 | A    |
+----+------+
1 rows in set (0.00 sec)

このように,マスターでは更新した内容が,スレーブの型のvarchar(1)に切り詰められて登録されています。

著者プロフィール

北川健太郎(きたがわけんたろう)

LINE株式会社所属のデータベースエンジニア。担当はMySQLとOracle Database。好きなMySQLの機能はレプリケーションで,好きなOracleDatabaseの機能はログオントリガー。

Twitter:@keny_lala

コメント

コメントの記入