チョットワカル Row-Based Replication・その4
こんにちわ。せじまです。
今回も replication の話をします。
はじめに
第四回です。
前回、 Row-Based Replication では Column の名前を意識していないことを確認しました。今回は Row-Based Replication で online schema change できないか、そのへん試してみましょう。
まずは厳重注意
これから記述する内容を本番環境で実施する場合、リスクをともないます。まずは検証環境で試しましょう。
いちおうまとめ
- master の方が Column が少なかった場合、 slave にしか存在していない Column の振る舞いは、 Worklog 5092 で規定されているようなものでした。デフォルトの値で更新されます。
- よって、 slave でtableの末尾に add column する程度なら動く気がします。公式ドキュメントにもそのような記述があります。16.4.1.10 Replication with Differing Table Definitions on Master and Slave
- ただ、 stored な generated column は、Row-Based Replication では binlog event で更新すべきようで、 slave で table の末尾に stored な generated column 追加しても、更新のたびに評価されるわけではないようです。
- RBRでは「式を評価するのは、式が発行されたmasterでのみ行う」って考え方なんでしょうね。
でははじめます
master/slave でこのような table があります
master
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
mysql> show create table takanori\G *************************** 1. row *************************** Table: takanori Create Table: CREATE TABLE `takanori` ( `id` int(11) NOT NULL AUTO_INCREMENT, `val1` int(11) NOT NULL, `val2` int(11) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci 1 row in set (0.00 sec) mysql> select @@server_id, @@version;select * from takanori; +-------------+-----------+ | @@server_id | @@version | +-------------+-----------+ | 1 | 8.0.18 | +-------------+-----------+ 1 row in set (0.00 sec) +----+------+-------+ | id | val1 | val2 | +----+------+-------+ | 1 | 1 | 10 | | 2 | 100 | 1000 | | 3 | 1 | 24000 | | 4 | 100 | 2000 | | 5 | 1 | 10 | | 6 | 100 | 100 | +----+------+-------+ 6 rows in set (0.00 sec) mysql> |
slave
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 |
mysql> show create table takanori\G *************************** 1. row *************************** Table: takanori Create Table: CREATE TABLE `takanori` ( `id` int(11) NOT NULL AUTO_INCREMENT, `val1` int(11) NOT NULL, `val2` int(11) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci 1 row in set (0.00 sec) mysql> select @@server_id, @@version;select * from takanori; +-------------+-----------+ | @@server_id | @@version | +-------------+-----------+ | 2 | 8.0.18 | +-------------+-----------+ 1 row in set (0.00 sec) +----+------+-------+ | id | val1 | val2 | +----+------+-------+ | 1 | 1 | 10 | | 2 | 100 | 1000 | | 3 | 1 | 24000 | | 4 | 100 | 2000 | | 5 | 1 | 10 | | 6 | 100 | 100 | +----+------+-------+ 6 rows in set (0.00 sec) mysql> show slave status\G *************************** 1. row *************************** Slave_IO_State: Waiting for master to send event Master_Host: 172.18.0.2 Master_User: repl Master_Port: 3306 Connect_Retry: 60 Master_Log_File: binlog.000029 Read_Master_Log_Pos: 155 Relay_Log_File: 8230d2822d2f-relay-bin.000012 Relay_Log_Pos: 363 Relay_Master_Log_File: binlog.000029 Slave_IO_Running: Yes Slave_SQL_Running: Yes Replicate_Do_DB: Replicate_Ignore_DB: Replicate_Do_Table: Replicate_Ignore_Table: Replicate_Wild_Do_Table: Replicate_Wild_Ignore_Table: Last_Errno: 0 Last_Error: Skip_Counter: 0 Exec_Master_Log_Pos: 155 Relay_Log_Space: 622 Until_Condition: None Until_Log_File: Until_Log_Pos: 0 Master_SSL_Allowed: No Master_SSL_CA_File: Master_SSL_CA_Path: Master_SSL_Cert: Master_SSL_Cipher: Master_SSL_Key: Seconds_Behind_Master: 0 Master_SSL_Verify_Server_Cert: No Last_IO_Errno: 0 Last_IO_Error: Last_SQL_Errno: 0 Last_SQL_Error: Replicate_Ignore_Server_Ids: Master_Server_Id: 1 Master_UUID: 385a832a-ef37-11e9-a332-0242ac120002 Master_Info_File: mysql.slave_master_info SQL_Delay: 0 SQL_Remaining_Delay: NULL Slave_SQL_Running_State: Slave has read all relay log; waiting for more updates Master_Retry_Count: 86400 Master_Bind: Last_IO_Error_Timestamp: Last_SQL_Error_Timestamp: Master_SSL_Crl: Master_SSL_Crlpath: Retrieved_Gtid_Set: Executed_Gtid_Set: Auto_Position: 0 Replicate_Rewrite_DB: Channel_Name: Master_TLS_Version: Master_public_key_path: Get_master_public_key: 0 Network_Namespace: 1 row in set (0.00 sec) mysql> |
slave に add column して INSERT
slave で末尾に add column します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
mysql> alter table takanori add column val30 int not null; Query OK, 0 rows affected (0.03 sec) Records: 0 Duplicates: 0 Warnings: 0 mysql> show create table takanori\G *************************** 1. row *************************** Table: takanori Create Table: CREATE TABLE `takanori` ( `id` int(11) NOT NULL AUTO_INCREMENT, `val1` int(11) NOT NULL, `val2` int(11) NOT NULL, `val30` int(11) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci 1 row in set (0.00 sec) mysql> select @@server_id, @@version;select * from takanori; +-------------+-----------+ | @@server_id | @@version | +-------------+-----------+ | 2 | 8.0.18 | +-------------+-----------+ 1 row in set (0.00 sec) +----+------+-------+-------+ | id | val1 | val2 | val30 | +----+------+-------+-------+ | 1 | 1 | 10 | 0 | | 2 | 100 | 1000 | 0 | | 3 | 1 | 24000 | 0 | | 4 | 100 | 2000 | 0 | | 5 | 1 | 10 | 0 | | 6 | 100 | 100 | 0 | +----+------+-------+-------+ 6 rows in set (0.00 sec) mysql> |
master でカラム名指定で INSERT します
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
mysql> insert into takanori (val1,val2) values (2,20),(300,3000); Query OK, 2 rows affected (0.01 sec) Records: 2 Duplicates: 0 Warnings: 0 mysql> select @@server_id, @@version;select * from takanori; +-------------+-----------+ | @@server_id | @@version | +-------------+-----------+ | 1 | 8.0.18 | +-------------+-----------+ 1 row in set (0.00 sec) +----+------+-------+ | id | val1 | val2 | +----+------+-------+ | 1 | 1 | 10 | | 2 | 100 | 1000 | | 3 | 1 | 24000 | | 4 | 100 | 2000 | | 5 | 1 | 10 | | 6 | 100 | 100 | | 7 | 2 | 20 | | 8 | 300 | 3000 | +----+------+-------+ 8 rows in set (0.00 sec) mysql> |
slaveにreplicationできます。masterに存在しないColumnには、デフォルトの値が入りました。この振る舞いは、WL#5092のDEFAULT VALUESの節に書かれているとおりですね。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
mysql> select @@server_id, @@version;select * from takanori; +-------------+-----------+ | @@server_id | @@version | +-------------+-----------+ | 2 | 8.0.18 | +-------------+-----------+ 1 row in set (0.00 sec) +----+------+-------+-------+ | id | val1 | val2 | val30 | +----+------+-------+-------+ | 1 | 1 | 10 | 0 | | 2 | 100 | 1000 | 0 | | 3 | 1 | 24000 | 0 | | 4 | 100 | 2000 | 0 | | 5 | 1 | 10 | 0 | | 6 | 100 | 100 | 0 | | 7 | 2 | 20 | 0 | | 8 | 300 | 3000 | 0 | +----+------+-------+-------+ 8 rows in set (0.00 sec) mysql> |
(slave に add column した状態で)UPDATE
update し、 replication することもできます。 RBR での update は、「何番目のColumnを更新するか」を指定しているだけなので
master
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
mysql> update takanori set val2=val2+2000 where id=3; Query OK, 1 row affected (0.02 sec) Rows matched: 1 Changed: 1 Warnings: 0 mysql> select @@server_id, @@version;select * from takanori; +-------------+-----------+ | @@server_id | @@version | +-------------+-----------+ | 1 | 8.0.18 | +-------------+-----------+ 1 row in set (0.00 sec) +----+------+-------+ | id | val1 | val2 | +----+------+-------+ | 1 | 1 | 10 | | 2 | 100 | 1000 | | 3 | 1 | 26000 | | 4 | 100 | 2000 | | 5 | 1 | 10 | | 6 | 100 | 100 | | 7 | 2 | 20 | | 8 | 300 | 3000 | +----+------+-------+ 8 rows in set (0.00 sec) mysql> |
slave
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
mysql> select @@server_id, @@version;select * from takanori; +-------------+-----------+ | @@server_id | @@version | +-------------+-----------+ | 2 | 8.0.18 | +-------------+-----------+ 1 row in set (0.00 sec) +----+------+-------+-------+ | id | val1 | val2 | val30 | +----+------+-------+-------+ | 1 | 1 | 10 | 0 | | 2 | 100 | 1000 | 0 | | 3 | 1 | 26000 | 0 | | 4 | 100 | 2000 | 0 | | 5 | 1 | 10 | 0 | | 6 | 100 | 100 | 0 | | 7 | 2 | 20 | 0 | | 8 | 300 | 3000 | 0 | +----+------+-------+-------+ 8 rows in set (0.00 sec) mysql> |
slave に Generated column 追加して INSERT や UPDATE
最近のMySQLは Generated column 使えるので、試しに slaveで Generated column 使ってみます 13.1.8.2 ALTER TABLE and Generated Columns
slave
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
mysql> alter table takanori drop column val30; Query OK, 0 rows affected (0.19 sec) Records: 0 Duplicates: 0 Warnings: 0 mysql> ALTER TABLE takanori ADD COLUMN val30 INT GENERATED ALWAYS AS (val1 + val2) STORED NOT NULL; Query OK, 8 rows affected (0.08 sec) Records: 8 Duplicates: 0 Warnings: 0 mysql> show create table takanori\G *************************** 1. row *************************** Table: takanori Create Table: CREATE TABLE `takanori` ( `id` int(11) NOT NULL AUTO_INCREMENT, `val1` int(11) NOT NULL, `val2` int(11) NOT NULL, `val30` int(11) GENERATED ALWAYS AS ((`val1` + `val2`)) STORED NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci 1 row in set (0.00 sec) mysql> select @@server_id, @@version;select * from takanori; +-------------+-----------+ | @@server_id | @@version | +-------------+-----------+ | 2 | 8.0.18 | +-------------+-----------+ 1 row in set (0.00 sec) +----+------+-------+-------+ | id | val1 | val2 | val30 | +----+------+-------+-------+ | 1 | 1 | 10 | 11 | | 2 | 100 | 1000 | 1100 | | 3 | 1 | 26000 | 26001 | | 4 | 100 | 2000 | 2100 | | 5 | 1 | 10 | 11 | | 6 | 100 | 100 | 200 | | 7 | 2 | 20 | 22 | | 8 | 300 | 3000 | 3300 | +----+------+-------+-------+ 8 rows in set (0.00 sec) mysql> |
master から insert したり update したりします
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
mysql> insert into takanori (val1,val2) values (2,20),(300,3000); Query OK, 2 rows affected (0.01 sec) Records: 2 Duplicates: 0 Warnings: 0 mysql> select @@server_id, @@version;select * from takanori; +-------------+-----------+ | @@server_id | @@version | +-------------+-----------+ | 1 | 8.0.18 | +-------------+-----------+ 1 row in set (0.00 sec) +----+------+-------+ | id | val1 | val2 | +----+------+-------+ | 1 | 1 | 10 | | 2 | 100 | 1000 | | 3 | 1 | 26000 | | 4 | 100 | 2000 | | 5 | 1 | 10 | | 6 | 100 | 100 | | 7 | 2 | 20 | | 8 | 300 | 3000 | | 9 | 2 | 20 | | 10 | 300 | 3000 | +----+------+-------+ 10 rows in set (0.00 sec) mysql> |
slave
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
mysql> select @@server_id, @@version;select * from takanori; +-------------+-----------+ | @@server_id | @@version | +-------------+-----------+ | 2 | 8.0.18 | +-------------+-----------+ 1 row in set (0.00 sec) +----+------+-------+-------+ | id | val1 | val2 | val30 | +----+------+-------+-------+ | 1 | 1 | 10 | 11 | | 2 | 100 | 1000 | 1100 | | 3 | 1 | 26000 | 26001 | | 4 | 100 | 2000 | 2100 | | 5 | 1 | 10 | 11 | | 6 | 100 | 100 | 200 | | 7 | 2 | 20 | 22 | | 8 | 300 | 3000 | 3300 | | 9 | 2 | 20 | 0 | | 10 | 300 | 3000 | 0 | +----+------+-------+-------+ 10 rows in set (0.00 sec) mysql> |
master で update
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
mysql> update takanori set val2=val2+2000 where id=3; Query OK, 1 row affected (0.01 sec) Rows matched: 1 Changed: 1 Warnings: 0 mysql> update takanori set val2=val2+2000 where id=8; Query OK, 1 row affected (0.01 sec) Rows matched: 1 Changed: 1 Warnings: 0 mysql> select @@server_id,@@version;select * from takanori where id in (3,8); +-------------+-----------+ | @@server_id | @@version | +-------------+-----------+ | 1 | 8.0.18 | +-------------+-----------+ 1 row in set (0.00 sec) +----+------+-------+ | id | val1 | val2 | +----+------+-------+ | 3 | 1 | 28000 | | 8 | 300 | 5000 | +----+------+-------+ 2 rows in set (0.00 sec) mysql> |
slave
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
mysql> select @@server_id,@@version;select * from takanori where id in (3,8); +-------------+-----------+ | @@server_id | @@version | +-------------+-----------+ | 2 | 8.0.18 | +-------------+-----------+ 1 row in set (0.00 sec) +----+------+-------+-------+ | id | val1 | val2 | val30 | +----+------+-------+-------+ | 3 | 1 | 28000 | 26001 | | 8 | 300 | 5000 | 3300 | +----+------+-------+-------+ 2 rows in set (0.00 sec) mysql> |
なるほど。Generated columnでは不整合が発生しました。
master で Generated column 追加して INSERT や UPDATE
STORED な generated column への更新は、RBRでは binlog の event として master から降ってこないといけないようですね。
slave で drop column したのち、 master から add column して試してみます。
slave
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
mysql> alter table takanori drop column val30; Query OK, 0 rows affected (0.10 sec) Records: 0 Duplicates: 0 Warnings: 0 mysql> select @@server_id, @@version;select * from takanori; +-------------+-----------+ | @@server_id | @@version | +-------------+-----------+ | 2 | 8.0.18 | +-------------+-----------+ 1 row in set (0.00 sec) +----+------+-------+ | id | val1 | val2 | +----+------+-------+ | 1 | 1 | 10 | | 2 | 100 | 1000 | | 3 | 1 | 28000 | | 4 | 100 | 2000 | | 5 | 1 | 10 | | 6 | 100 | 100 | | 7 | 2 | 20 | | 8 | 300 | 5000 | | 9 | 2 | 20 | | 10 | 300 | 3000 | +----+------+-------+ 10 rows in set (0.00 sec) mysql> show create table takanori\G *************************** 1. row *************************** Table: takanori Create Table: CREATE TABLE `takanori` ( `id` int(11) NOT NULL AUTO_INCREMENT, `val1` int(11) NOT NULL, `val2` int(11) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci 1 row in set (0.00 sec) mysql> |
master
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
mysql> ALTER TABLE takanori ADD COLUMN val3 INT GENERATED ALWAYS AS (val1 + val2) STORED NOT NULL; Query OK, 10 rows affected (0.10 sec) Records: 10 Duplicates: 0 Warnings: 0 mysql> show create table takanori\G *************************** 1. row *************************** Table: takanori Create Table: CREATE TABLE `takanori` ( `id` int(11) NOT NULL AUTO_INCREMENT, `val1` int(11) NOT NULL, `val2` int(11) NOT NULL, `val3` int(11) GENERATED ALWAYS AS ((`val1` + `val2`)) STORED NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci 1 row in set (0.00 sec) mysql> select @@server_id, @@version;select * from takanori; +-------------+-----------+ | @@server_id | @@version | +-------------+-----------+ | 1 | 8.0.18 | +-------------+-----------+ 1 row in set (0.00 sec) +----+------+-------+-------+ | id | val1 | val2 | val3 | +----+------+-------+-------+ | 1 | 1 | 10 | 11 | | 2 | 100 | 1000 | 1100 | | 3 | 1 | 28000 | 28001 | | 4 | 100 | 2000 | 2100 | | 5 | 1 | 10 | 11 | | 6 | 100 | 100 | 200 | | 7 | 2 | 20 | 22 | | 8 | 300 | 5000 | 5300 | | 9 | 2 | 20 | 22 | | 10 | 300 | 3000 | 3300 | +----+------+-------+-------+ 10 rows in set (0.00 sec) mysql> |
slave
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
mysql> show create table takanori\G *************************** 1. row *************************** Table: takanori Create Table: CREATE TABLE `takanori` ( `id` int(11) NOT NULL AUTO_INCREMENT, `val1` int(11) NOT NULL, `val2` int(11) NOT NULL, `val3` int(11) GENERATED ALWAYS AS ((`val1` + `val2`)) STORED NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci 1 row in set (0.00 sec) mysql> select @@server_id, @@version;select * from takanori; +-------------+-----------+ | @@server_id | @@version | +-------------+-----------+ | 2 | 8.0.18 | +-------------+-----------+ 1 row in set (0.00 sec) +----+------+-------+-------+ | id | val1 | val2 | val3 | +----+------+-------+-------+ | 1 | 1 | 10 | 11 | | 2 | 100 | 1000 | 1100 | | 3 | 1 | 28000 | 28001 | | 4 | 100 | 2000 | 2100 | | 5 | 1 | 10 | 11 | | 6 | 100 | 100 | 200 | | 7 | 2 | 20 | 22 | | 8 | 300 | 5000 | 5300 | | 9 | 2 | 20 | 22 | | 10 | 300 | 3000 | 3300 | +----+------+-------+-------+ 10 rows in set (0.00 sec) mysql> |
binlog_row_image=full
master
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
mysql> insert into takanori (val1,val2) values (2,20),(300,3000); Query OK, 2 rows affected (0.01 sec) Records: 2 Duplicates: 0 Warnings: 0 mysql> update takanori set val2=val2+2000 where id=3; Query OK, 1 row affected (0.02 sec) Rows matched: 1 Changed: 1 Warnings: 0 mysql> select @@server_id, @@version;select * from takanori; +-------------+-----------+ | @@server_id | @@version | +-------------+-----------+ | 1 | 8.0.18 | +-------------+-----------+ 1 row in set (0.00 sec) +----+------+-------+-------+ | id | val1 | val2 | val3 | +----+------+-------+-------+ | 1 | 1 | 10 | 11 | | 2 | 100 | 1000 | 1100 | | 3 | 1 | 30000 | 30001 | | 4 | 100 | 2000 | 2100 | | 5 | 1 | 10 | 11 | | 6 | 100 | 100 | 200 | | 7 | 2 | 20 | 22 | | 8 | 300 | 5000 | 5300 | | 9 | 2 | 20 | 22 | | 10 | 300 | 3000 | 3300 | | 11 | 2 | 20 | 22 | | 12 | 300 | 3000 | 3300 | +----+------+-------+-------+ 12 rows in set (0.01 sec) mysql> |
slave
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
mysql> select @@server_id, @@version;select * from takanori; +-------------+-----------+ | @@server_id | @@version | +-------------+-----------+ | 2 | 8.0.18 | +-------------+-----------+ 1 row in set (0.00 sec) +----+------+-------+-------+ | id | val1 | val2 | val3 | +----+------+-------+-------+ | 1 | 1 | 10 | 11 | | 2 | 100 | 1000 | 1100 | | 3 | 1 | 30000 | 30001 | | 4 | 100 | 2000 | 2100 | | 5 | 1 | 10 | 11 | | 6 | 100 | 100 | 200 | | 7 | 2 | 20 | 22 | | 8 | 300 | 5000 | 5300 | | 9 | 2 | 20 | 22 | | 10 | 300 | 3000 | 3300 | | 11 | 2 | 20 | 22 | | 12 | 300 | 3000 | 3300 | +----+------+-------+-------+ 12 rows in set (0.00 sec) mysql> |
mysqlbinlog -vv で確認すると
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 |
$ ./mysqlbinlog /var/lib/mysql/binlog.000031 -vv /*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=1*/; /*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/; DELIMITER /*!*/; # at 4 #191112 6:41:27 server id 1 end_log_pos 124 CRC32 0x80b81408 Start: binlog v 4, server v 8.0.18 created 191112 6:41:27 # Warning: this binlog is either in use or was not closed properly. BINLOG ' F1TKXQ8BAAAAeAAAAHwAAAABAAQAOC4wLjE4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAEwANAAgAAAAABAAEAAAAYAAEGggAAAAICAgCAAAACgoKKioAEjQA CgEIFLiA '/*!*/; # at 124 #191112 6:41:27 server id 1 end_log_pos 155 CRC32 0xec3c007c Previous-GTIDs # [empty] # at 155 #191112 6:41:45 server id 1 end_log_pos 234 CRC32 0x82ecf8c4 Anonymous_GTID last_committed=0 sequence_number=1 rbr_only=yes original_committed_timestamp=1573540905364290 immediate_commit_timestamp=1573540905364290 transaction_length=311 /*!50718 SET TRANSACTION ISOLATION LEVEL READ COMMITTED*//*!*/; # original_commit_timestamp=1573540905364290 (2019-11-12 06:41:45.364290 UTC) # immediate_commit_timestamp=1573540905364290 (2019-11-12 06:41:45.364290 UTC) /*!80001 SET @@session.original_commit_timestamp=1573540905364290*//*!*/; /*!80014 SET @@session.original_server_version=80018*//*!*/; /*!80014 SET @@session.immediate_server_version=80018*//*!*/; SET @@SESSION.GTID_NEXT= 'ANONYMOUS'/*!*/; # at 234 #191112 6:41:45 server id 1 end_log_pos 309 CRC32 0x08695b67 Query thread_id=9 exec_time=0 error_code=0 SET TIMESTAMP=1573540905/*!*/; SET @@session.pseudo_thread_id=9/*!*/; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=0, @@session.unique_checks=1, @@session.autocommit=1/*!*/; SET @@session.sql_mode=1168113696/*!*/; SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/; /*!\C latin1 *//*!*/; SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=255/*!*/; SET @@session.lc_time_names=0/*!*/; SET @@session.collation_database=DEFAULT/*!*/; /*!80011 SET @@session.default_collation_for_utf8mb4=255*//*!*/; BEGIN /*!*/; # at 309 #191112 6:41:45 server id 1 end_log_pos 366 CRC32 0x7491f9eb Table_map: `test`.`takanori` mapped to number 101 # at 366 #191112 6:41:45 server id 1 end_log_pos 435 CRC32 0x0f184969 Write_rows: table id 101 flags: STMT_END_F BINLOG ' KVTKXRMBAAAAOQAAAG4BAAAAAGUAAAAAAAEABHRlc3QACHRha2Fub3JpAAQDAwMDAAABAQDr+ZF0 KVTKXR4BAAAARQAAALMBAAAAAGUAAAAAAAEAAgAE/wALAAAAAgAAABQAAAAWAAAAAAwAAAAsAQAA uAsAAOQMAABpSRgP '/*!*/; ### INSERT INTO `test`.`takanori` ### SET ### @1=11 /* INT meta=0 nullable=0 is_null=0 */ ### @2=2 /* INT meta=0 nullable=0 is_null=0 */ ### @3=20 /* INT meta=0 nullable=0 is_null=0 */ ### @4=22 /* INT meta=0 nullable=0 is_null=0 */ ### INSERT INTO `test`.`takanori` ### SET ### @1=12 /* INT meta=0 nullable=0 is_null=0 */ ### @2=300 /* INT meta=0 nullable=0 is_null=0 */ ### @3=3000 /* INT meta=0 nullable=0 is_null=0 */ ### @4=3300 /* INT meta=0 nullable=0 is_null=0 */ # at 435 #191112 6:41:45 server id 1 end_log_pos 466 CRC32 0x499d20f0 Xid = 274 COMMIT/*!*/; # at 466 #191112 6:41:51 server id 1 end_log_pos 545 CRC32 0xf86e4c18 Anonymous_GTID last_committed=1 sequence_number=2 rbr_only=yes original_committed_timestamp=1573540911064593 immediate_commit_timestamp=1573540911064593 transaction_length=321 /*!50718 SET TRANSACTION ISOLATION LEVEL READ COMMITTED*//*!*/; # original_commit_timestamp=1573540911064593 (2019-11-12 06:41:51.064593 UTC) # immediate_commit_timestamp=1573540911064593 (2019-11-12 06:41:51.064593 UTC) /*!80001 SET @@session.original_commit_timestamp=1573540911064593*//*!*/; /*!80014 SET @@session.original_server_version=80018*//*!*/; /*!80014 SET @@session.immediate_server_version=80018*//*!*/; SET @@SESSION.GTID_NEXT= 'ANONYMOUS'/*!*/; # at 545 #191112 6:41:51 server id 1 end_log_pos 629 CRC32 0x7ff0c37e Query thread_id=9 exec_time=0 error_code=0 SET TIMESTAMP=1573540911/*!*/; BEGIN /*!*/; # at 629 #191112 6:41:51 server id 1 end_log_pos 686 CRC32 0xd52a4759 Table_map: `test`.`takanori` mapped to number 101 # at 686 #191112 6:41:51 server id 1 end_log_pos 756 CRC32 0x04dd11e1 Update_rows: table id 101 flags: STMT_END_F BINLOG ' L1TKXRMBAAAAOQAAAK4CAAAAAGUAAAAAAAEABHRlc3QACHRha2Fub3JpAAQDAwMDAAABAQBZRyrV L1TKXR8BAAAARgAAAPQCAAAAAGUAAAAAAAEAAgAE//8AAwAAAAEAAABgbQAAYW0AAAADAAAAAQAA ADB1AAAxdQAA4RHdBA== '/*!*/; ### UPDATE `test`.`takanori` ### WHERE ### @1=3 /* INT meta=0 nullable=0 is_null=0 */ ### @2=1 /* INT meta=0 nullable=0 is_null=0 */ ### @3=28000 /* INT meta=0 nullable=0 is_null=0 */ ### @4=28001 /* INT meta=0 nullable=0 is_null=0 */ ### SET ### @1=3 /* INT meta=0 nullable=0 is_null=0 */ ### @2=1 /* INT meta=0 nullable=0 is_null=0 */ ### @3=30000 /* INT meta=0 nullable=0 is_null=0 */ ### @4=30001 /* INT meta=0 nullable=0 is_null=0 */ # at 756 #191112 6:41:51 server id 1 end_log_pos 787 CRC32 0x06f73187 Xid = 275 COMMIT/*!*/; SET @@SESSION.GTID_NEXT= 'AUTOMATIC' /* added by mysqlbinlog */ /*!*/; DELIMITER ; # End of log file /*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/; /*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=0*/; $ |
binlog_row_image=minimal
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
mysql> set session binlog_row_image=minimal; Query OK, 0 rows affected (0.00 sec) mysql> select @@server_id, @@version;select * from takanori; +-------------+-----------+ | @@server_id | @@version | +-------------+-----------+ | 1 | 8.0.18 | +-------------+-----------+ 1 row in set (0.00 sec) +----+------+-------+-------+ | id | val1 | val2 | val3 | +----+------+-------+-------+ | 1 | 1 | 10 | 11 | | 2 | 100 | 1000 | 1100 | | 3 | 1 | 30000 | 30001 | | 4 | 100 | 2000 | 2100 | | 5 | 1 | 10 | 11 | | 6 | 100 | 100 | 200 | | 7 | 2 | 20 | 22 | | 8 | 300 | 5000 | 5300 | | 9 | 2 | 20 | 22 | | 10 | 300 | 3000 | 3300 | | 11 | 2 | 20 | 22 | | 12 | 300 | 3000 | 3300 | +----+------+-------+-------+ 12 rows in set (0.00 sec) mysql> insert into takanori (val1,val2) values (2,20),(300,3000); Query OK, 2 rows affected (0.01 sec) Records: 2 Duplicates: 0 Warnings: 0 mysql> update takanori set val2=val2+2000 where id=3; Query OK, 1 row affected (0.01 sec) Rows matched: 1 Changed: 1 Warnings: 0 mysql> select @@server_id, @@version;select * from takanori; +-------------+-----------+ | @@server_id | @@version | +-------------+-----------+ | 1 | 8.0.18 | +-------------+-----------+ 1 row in set (0.00 sec) +----+------+-------+-------+ | id | val1 | val2 | val3 | +----+------+-------+-------+ | 1 | 1 | 10 | 11 | | 2 | 100 | 1000 | 1100 | | 3 | 1 | 32000 | 32001 | | 4 | 100 | 2000 | 2100 | | 5 | 1 | 10 | 11 | | 6 | 100 | 100 | 200 | | 7 | 2 | 20 | 22 | | 8 | 300 | 5000 | 5300 | | 9 | 2 | 20 | 22 | | 10 | 300 | 3000 | 3300 | | 11 | 2 | 20 | 22 | | 12 | 300 | 3000 | 3300 | | 13 | 2 | 20 | 22 | | 14 | 300 | 3000 | 3300 | +----+------+-------+-------+ 14 rows in set (0.00 sec) mysql> |
slave
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
mysql> select @@server_id, @@version;select * from takanori; +-------------+-----------+ | @@server_id | @@version | +-------------+-----------+ | 2 | 8.0.18 | +-------------+-----------+ 1 row in set (0.00 sec) +----+------+-------+-------+ | id | val1 | val2 | val3 | +----+------+-------+-------+ | 1 | 1 | 10 | 11 | | 2 | 100 | 1000 | 1100 | | 3 | 1 | 32000 | 32001 | | 4 | 100 | 2000 | 2100 | | 5 | 1 | 10 | 11 | | 6 | 100 | 100 | 200 | | 7 | 2 | 20 | 22 | | 8 | 300 | 5000 | 5300 | | 9 | 2 | 20 | 22 | | 10 | 300 | 3000 | 3300 | | 11 | 2 | 20 | 22 | | 12 | 300 | 3000 | 3300 | | 13 | 2 | 20 | 22 | | 14 | 300 | 3000 | 3300 | +----+------+-------+-------+ 14 rows in set (0.00 sec) mysql> |
mysqlbinlog -vv は
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 |
$ ./mysqlbinlog /var/lib/mysql/binlog.000032 -vv /*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=1*/; /*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/; DELIMITER /*!*/; # at 4 #191112 6:45:07 server id 1 end_log_pos 124 CRC32 0x1fff9ca8 Start: binlog v 4, server v 8.0.18 created 191112 6:45:07 # Warning: this binlog is either in use or was not closed properly. BINLOG ' 81TKXQ8BAAAAeAAAAHwAAAABAAQAOC4wLjE4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAEwANAAgAAAAABAAEAAAAYAAEGggAAAAICAgCAAAACgoKKioAEjQA CgGonP8f '/*!*/; # at 124 #191112 6:45:07 server id 1 end_log_pos 155 CRC32 0x0d01c6ed Previous-GTIDs # [empty] # at 155 #191112 6:45:30 server id 1 end_log_pos 234 CRC32 0x732171d2 Anonymous_GTID last_committed=0 sequence_number=1 rbr_only=yes original_committed_timestamp=1573541130135794 immediate_commit_timestamp=1573541130135794 transaction_length=311 /*!50718 SET TRANSACTION ISOLATION LEVEL READ COMMITTED*//*!*/; # original_commit_timestamp=1573541130135794 (2019-11-12 06:45:30.135794 UTC) # immediate_commit_timestamp=1573541130135794 (2019-11-12 06:45:30.135794 UTC) /*!80001 SET @@session.original_commit_timestamp=1573541130135794*//*!*/; /*!80014 SET @@session.original_server_version=80018*//*!*/; /*!80014 SET @@session.immediate_server_version=80018*//*!*/; SET @@SESSION.GTID_NEXT= 'ANONYMOUS'/*!*/; # at 234 #191112 6:45:30 server id 1 end_log_pos 309 CRC32 0xa2aaa020 Query thread_id=9 exec_time=0 error_code=0 SET TIMESTAMP=1573541130/*!*/; SET @@session.pseudo_thread_id=9/*!*/; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=0, @@session.unique_checks=1, @@session.autocommit=1/*!*/; SET @@session.sql_mode=1168113696/*!*/; SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/; /*!\C latin1 *//*!*/; SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=255/*!*/; SET @@session.lc_time_names=0/*!*/; SET @@session.collation_database=DEFAULT/*!*/; /*!80011 SET @@session.default_collation_for_utf8mb4=255*//*!*/; BEGIN /*!*/; # at 309 #191112 6:45:30 server id 1 end_log_pos 366 CRC32 0x45dbe94c Table_map: `test`.`takanori` mapped to number 101 # at 366 #191112 6:45:30 server id 1 end_log_pos 435 CRC32 0x0a0a27af Write_rows: table id 101 flags: STMT_END_F BINLOG ' ClXKXRMBAAAAOQAAAG4BAAAAAGUAAAAAAAEABHRlc3QACHRha2Fub3JpAAQDAwMDAAABAQBM6dtF ClXKXR4BAAAARQAAALMBAAAAAGUAAAAAAAEAAgAEDwANAAAAAgAAABQAAAAWAAAAAA4AAAAsAQAA uAsAAOQMAACvJwoK '/*!*/; ### INSERT INTO `test`.`takanori` ### SET ### @1=13 /* INT meta=0 nullable=0 is_null=0 */ ### @2=2 /* INT meta=0 nullable=0 is_null=0 */ ### @3=20 /* INT meta=0 nullable=0 is_null=0 */ ### @4=22 /* INT meta=0 nullable=0 is_null=0 */ ### INSERT INTO `test`.`takanori` ### SET ### @1=14 /* INT meta=0 nullable=0 is_null=0 */ ### @2=300 /* INT meta=0 nullable=0 is_null=0 */ ### @3=3000 /* INT meta=0 nullable=0 is_null=0 */ ### @4=3300 /* INT meta=0 nullable=0 is_null=0 */ # at 435 #191112 6:45:30 server id 1 end_log_pos 466 CRC32 0xfd10bcdf Xid = 301 COMMIT/*!*/; # at 466 #191112 6:45:42 server id 1 end_log_pos 545 CRC32 0x430100c7 Anonymous_GTID last_committed=1 sequence_number=2 rbr_only=yes original_committed_timestamp=1573541142240435 immediate_commit_timestamp=1573541142240435 transaction_length=301 /*!50718 SET TRANSACTION ISOLATION LEVEL READ COMMITTED*//*!*/; # original_commit_timestamp=1573541142240435 (2019-11-12 06:45:42.240435 UTC) # immediate_commit_timestamp=1573541142240435 (2019-11-12 06:45:42.240435 UTC) /*!80001 SET @@session.original_commit_timestamp=1573541142240435*//*!*/; /*!80014 SET @@session.original_server_version=80018*//*!*/; /*!80014 SET @@session.immediate_server_version=80018*//*!*/; SET @@SESSION.GTID_NEXT= 'ANONYMOUS'/*!*/; # at 545 #191112 6:45:42 server id 1 end_log_pos 629 CRC32 0xe20b65a1 Query thread_id=9 exec_time=0 error_code=0 SET TIMESTAMP=1573541142/*!*/; BEGIN /*!*/; # at 629 #191112 6:45:42 server id 1 end_log_pos 686 CRC32 0xd9b9a4e2 Table_map: `test`.`takanori` mapped to number 101 # at 686 #191112 6:45:42 server id 1 end_log_pos 736 CRC32 0xe7c66ed1 Update_rows: table id 101 flags: STMT_END_F BINLOG ' FlXKXRMBAAAAOQAAAK4CAAAAAGUAAAAAAAEABHRlc3QACHRha2Fub3JpAAQDAwMDAAABAQDipLnZ FlXKXR8BAAAAMgAAAOACAAAAAGUAAAAAAAEAAgAEAQwAAwAAAAAAfQAAAX0AANFuxuc= '/*!*/; ### UPDATE `test`.`takanori` ### WHERE ### @1=3 /* INT meta=0 nullable=0 is_null=0 */ ### SET ### @3=32000 /* INT meta=0 nullable=0 is_null=0 */ ### @4=32001 /* INT meta=0 nullable=0 is_null=0 */ # at 736 #191112 6:45:42 server id 1 end_log_pos 767 CRC32 0x497cc9eb Xid = 302 COMMIT/*!*/; SET @@SESSION.GTID_NEXT= 'AUTOMATIC' /* added by mysqlbinlog */ /*!*/; DELIMITER ; # End of log file /*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/; /*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=0*/; $ |
補足
WL#3915: Fewer columns on slave という WorkLog を見ると、力強く次のように書いてあり
It should be possible to replicate a table that has more columns on the master
than on the slave, i.e., there are M columns in the table on the master and N
columns in the table on the slave and M > N.When replicating in this manner, the contents of the extra columns on the master
is lost, but replication will accept the situation and keep running.
WorkLog 3259 は公開されていないようですが、 WL#3915 には次のようにも書いてあるので
This work is related to WL#3259 (RBR with more columns on slave than on master)
in that implementation of this worklog is necessary to support on-line table
definition changes (a.k.a., "schema upgrade") when using circular replication.
Row-Based Replication で、 master と slave の Column の数が一致していなくても replication できるべきだと、 MySQL の Replication teamは考えているようです。
個人的見解のような補足
ここでもう一度 WL#5092: RBR: Options for writing partial or full row images in RBR events を振り返ってみましょう。次のような記述がありました。
165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 |
NOTE ---- As a side remark, there was another option considered: - reversible means PKE and changed columns in before and after image Nevertheless, it was decided that this will not be implemented for now, as there is no practical use for it (think Undo operations). So, for not risking to get the user confused, and because the 'noblob' option supersedes this one, we will put this on hold. Decision was made over Skype meeting: - attendees: Alfranio, Mats and Luís - date: 09/09/09 (11:00 am CEST) |
binlog_format=ROW な binlog には AI と BI があるので、 binlog 使ってデータを巻き戻すことが可能ではないか、という話ですが
- master と slave の Column の数が違っても replication できる
- master ないし slave にしか存在しない generated column があった場合、 binlog でその更新をケアできるのか
- MySQLのバージョンが古かった場合、型変換できるのか。あるいは、 binlog を適用使用しているバージョンで、更新対象のColumnの型はサポートされているか
- DMLはともかく、DDLはどうするのか
といったあたり踏まえると、binlog_format=ROW を熟知していないと、混乱を招く機能ではないかなぁと思います。
Alfranio、 Mats、Luís の三人は、reversible より noblob の方がユーザにとってメリットがあると考えてくれたのでしょう。個人的に、良い決断だったのではないかと思います。
今日はこれまで
今回はちょっとヤンチャなことをしてみました。 master と slave でテーブル定義が異なっていても、Row-based Replication はできるようですが、 STORED な Generated Column は、その限りではないようですね。
次回は、Row-based Replication で Column の型チェックが行われるところなどを見てみましょう。