MySQL复制之深入理解binlog_format及表字段顺序的重要性

我们知道binlog的格式有rbr,sbr还有mbr。

mbr不需多说,就是优先sbr,实在不行就rbr。

那么sbr怎么理解?根据文档来看,就是master端将执行的sql语句直接写入binlog里。slave端在重演时也执行一遍这些sql语句。

这就是sbr的意思。

听起来好像sbr真的能100%保证master和slave一致?

那可不一定了!

比如我们在master端执行如下sql:

mysql> set @@session.binlog_format=statement;
Query OK, 0 rows affected (0.00 sec)

mysql> insert into t2(uid) values(uuid());
Query OK, 1 row affected, 1 warning (0.28 sec)

mysql> select * from t2;
+—-+————————————–+
| id | uid                                  |
+—-+————————————–+
|  1 | 602d9a9d-f187-11e5-a634-5c260a17ccde |
+—-+————————————–+
1 rows in set (0.00 sec)

mysql>

而在slave端,我们查询t2表时,发现:

mysql> select * from t2;
+—-+————————————–+
| id | uid                                  |
+—-+————————————–+
|  1 | 60549b1b-f187-11e5-803d-5c260a17ccde |
+—-+————————————–+
1 rows in set (0.00 sec)

mysql>

你看,红色部分表示master端和slave的uid值明显不一致。

所以很容易得出结论,sbr的binlog的复制环境是不安全,无法保证100%的数据一致性。

由于sbr是master端将sql语句写入binlog文件,而不管这个语句是否在master端引起更改。所以slave端接收到的event也是sql语句。

也就是说,在sbr里,master端执行了什么样子的sql语句,那么在slave端也要执行同样的SQL语句。

这就会有一个现象是,同一个语句在master没有引起更改,而在slave重演时引起了更改。或者两端都引起了更改,但是两端的更改不一致。

而rbr呢?

在rbr中,如果一个语句在master没有引起更改,那么这个语句是不会被binlog的。也就是说这个语句不会被重演到slave端。

什么样的语句是不会引起更改的语句?比如:

mysql> SELECT * FROM t1;
+—-+——+——-+
| id | name | score |
+—-+——+——-+
|  1 | za   |    12 |
|  2 | za   |    13 |
|  3 | za   |    19 |
|  4 | za   |    50 |
|  5 | zb   |     9 |
|  6 | zb   |    89 |
|  7 | zb   |    90 |
+—-+——+——-+
7 rows in set (0.00 sec)

mysql> UPDATE t1
    -> SET t1.`score`=12
    -> WHERE t1.`id`=1;
Query OK, 0 rows affected (0.00 sec)
Rows matched: 1  Changed: 0  Warnings: 0

mysql>

我们试图更改的行,更改前和更改后是一致的。所以Changed: 0  。

这条语句在rbr模式下,就不会被binlog,也就不会被重演到slave端。因为他并没有引起行更改。

我们继续讨论rbr较sbr的复制安全性问题,请看:

在master端

mysql> set @@session.binlog_format=row;
Query OK, 0 rows affected (0.00 sec)

mysql> use test
Database changed
mysql> truncate table t2;
Query OK, 0 rows affected (0.29 sec)

mysql> insert into t2(uid) values(uuid());
Query OK, 1 row affected (0.34 sec)

mysql> select * from t2;
+—-+————————————–+
| id | uid                                  |
+—-+————————————–+
|  1 | f130ebcb-f187-11e5-a634-5c260a17ccde |
+—-+————————————–+
1 row in set (0.00 sec)

mysql>

而我们查询下slave端的数据:

mysql> use test
Database changed
mysql> select * from t2;
Empty set (0.00 sec)

mysql> select * from t2;
+—-+————————————–+
| id | uid                                  |
+—-+————————————–+
|  1 | f130ebcb-f187-11e5-a634-5c260a17ccde |
+—-+————————————–+
1 row in set (0.00 sec)

mysql>

根据红色部分,我们得出,基于rbr的复制是安全的。

但是rbr的复制真的就那么安全吗?

答案是:呵呵。

为什么是呵呵呢,请往下面继续看。

我们假设这么一个场景,小张是dba,应开发人员小王的要求在生产库的master端建了表t1:

C:\>mysql
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 6
Server version: 5.7.11-log MySQL Community Server (GPL)

Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type ‘help;’ or ‘\h’ for help. Type ‘\c’ to clear the current input statement.

mysql> select @@session.binlog_format;
+————————-+
| @@session.binlog_format |
+————————-+
| STATEMENT               |
+————————-+
1 row in set (0.00 sec)

mysql> set @@session.binlog_format=row;
Query OK, 0 rows affected (0.00 sec)

mysql> drop table if exists t1;
ERROR 1046 (3D000): No database selected
mysql> use test
Database changed
mysql> drop table if exists t1;
Query OK, 0 rows affected (0.23 sec)

mysql> CREATE TABLE t1 (
    ->   id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
    ->   a VARCHAR (5),
    ->   b VARCHAR (5),
    ->   c VARCHAR (5),
    ->   d VARCHAR (5)
    -> );
Query OK, 0 rows affected (0.29 sec)

mysql> desc t1;
+——-+————+——+—–+———+—————-+
| Field | Type       | Null | Key | Default | Extra          |
+——-+————+——+—–+———+—————-+
| id    | int(11)    | NO   | PRI | NULL    | auto_increment |
| a     | varchar(5) | YES  |     | NULL    |                |
| b     | varchar(5) | YES  |     | NULL    |                |
| c     | varchar(5) | YES  |     | NULL    |                |
| d     | varchar(5) | YES  |     | NULL    |                |
+——-+————+——+—–+———+—————-+
5 rows in set (0.00 sec)

mysql>

这个表很明显,正确地被复制到了slave端:

mysql> use test
Database changed
mysql> desc t1;
+——-+————+——+—–+———+—————-+
| Field | Type       | Null | Key | Default | Extra          |
+——-+————+——+—–+———+—————-+
| id    | int(11)    | NO   | PRI | NULL    | auto_increment |
| a     | varchar(5) | YES  |     | NULL    |                |
| b     | varchar(5) | YES  |     | NULL    |                |
| c     | varchar(5) | YES  |     | NULL    |                |
| d     | varchar(5) | YES  |     | NULL    |                |
+——-+————+——+—–+———+—————-+
5 rows in set (0.01 sec)

mysql>

然后小王很高兴地往t1表里插入若干条数据,当然这发生在master端:

mysql> use test;
Database changed

mysql> select @@session.binlog_format;
+————————-+
| @@session.binlog_format |
+————————-+
| ROW                        |
+————————-+
1 row in set (0.00 sec)

mysql> INSERT INTO `test`.`t1` (`a`, `b`, `c`, `d`) VALUES(‘a1′,’b2′,’c3′,’d4’);
Query OK, 1 row affected (0.11 sec)

mysql> INSERT INTO `test`.`t1` (`a`, `b`, `c`, `d`) VALUES(‘a11′,’b22′,’c33′,’d44’);
Query OK, 1 row affected (0.10 sec)

mysql> select * from t1;
+—-+——+——+——+——+
| id | a    | b    | c    | d    |
+—-+——+——+——+——+
|  1 | a1   | b2   | c3   | d4   |
|  2 | a11  | b22  | c33  | d44  |
+—-+——+——+——+——+
2 rows in set (0.00 sec)

mysql>

很明显,这也被正确地复制到了slave端:

mysql> select * from t1;
+—-+——+——+——+——+
| id | a    | b    | c    | d    |
+—-+——+——+——+——+
|  1 | a1   | b2   | c3   | d4   |
|  2 | a11  | b22  | c33  | d44  |
+—-+——+——+——+——+
2 rows in set (0.00 sec)

mysql>

但是,但是,有天dba小张在维护slave数据库时不小心把t1表的字段顺序调整了,注意是slave端的操作:

mysql> ALTER TABLE `test`.`t1`
    ->   CHANGE `d` `d` VARCHAR(5) CHARSET utf8 COLLATE utf8_general_ci NULL  AFTER `a`,
    ->   CHANGE `c` `c` VARCHAR(5) CHARSET utf8 COLLATE utf8_general_ci NULL  AFTER `d`,
    ->   CHANGE `b` `b` VARCHAR(5) CHARSET utf8 COLLATE utf8_general_ci NULL  AFTER `c`;
Query OK, 0 rows affected (0.56 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> select * from t1;
+—-+——+——+——+——+
| id | a    | d    | c    | b    |
+—-+——+——+——+——+
|  1 | a1   | d4   | c3   | b2   |
|  2 | a11  | d44  | c33  | b22  |
+—-+——+——+——+——+
2 rows in set (0.00 sec)

mysql>

注意字段顺序由a,b,c,d变成了a,d,c,b。

ok,你认为此时复制会不会失败?会吗?

来看看,小王继续在mater端插入数据:

mysql> INSERT INTO `test`.`t1` (`a`, `b`, `c`, `d`) VALUES(‘a111′,’b222′,’c333′,’d444’);
Query OK, 1 row affected (0.09 sec)

mysql> select * from t1;
+—-+——+——+——+——+
| id | a    | b    | c    | d    |
+—-+——+——+——+——+
|  1 | a1   | b2   | c3   | d4   |
|  2 | a11  | b22  | c33  | d44  |
|  3 | a111 | b222 | c333 | d444 |
+—-+——+——+——+——+
3 rows in set (0.00 sec)

mysql>

而slave端的复制状态呢?失败了吗?我们看看状态:

mysql> show slave status\G
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 192.168.1.77
                  Master_User: backup
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: mysql-bin.000035
          Read_Master_Log_Pos: 4265
               Relay_Log_File: host_name-relay-bin.000016
                Relay_Log_Pos: 4478
        Relay_Master_Log_File: mysql-bin.000035
             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: 4265
              Relay_Log_Space: 6875
              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: 2
                  Master_UUID: e2e2f927-e75c-11e5-ac89-5c260a17ccde
             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: e2e2f927-e75c-11e5-ac89-5c260a17ccde:7371-7396
            Executed_Gtid_Set: 1cced57b-e75e-11e5-b742-5c260a17ccde:1-24,
e2e2f927-e75c-11e5-ac89-5c260a17ccde:1-7396

                Auto_Position: 1
         Replicate_Rewrite_DB:
                 Channel_Name:
           Master_TLS_Version:
1 row in set (0.00 sec)

mysql>

我靠,复制正常进行,没有出错。我们来看看slave端t1表的数据:

mysql> select a,b,c,d from t1;
+——+——+——+——+
| a    | b    | c    | d    |
+——+——+——+——+
| a1   | b2   | c3   | d4   |
| a11  | b22  | c33  | d44  |
| a111 | d444 | c333 | b222 |
+——+——+——+——+
3 rows in set (0.00 sec)

mysql>

mysql> select * from t1;
+—-+——+——+——+——+
| id | a    | d    | c    | b    |
+—-+——+——+——+——+
|  1 | a1   | d4   | c3   | b2   |
|  2 | a11  | d44  | c33  | b22  |
|  3 | a111 | b222 | c333 | d444 |
+—-+——+——+——+——+
3 rows in set (0.00 sec)

mysql>

尼玛,啥情况?小王在master插入的数据明明是a=a111,b=b222,c=c333,d=d444.

但是被复制到slave端之后,变成了a=a111,b=d444,c=c333,d=b222。

呵呵,rbr复制出错了。有木有?

你可能会觉得,不是rbr复制出错,而是小张偷偷地调整了t1表的字段顺序导致的。

嗯,的确也是这样。由于slave端的表结构字段顺序变了,所以复制实际上已经出错了。

这就是为什么mysql数据库的表的字段顺序很重要的原因。

那么,我们回过头来猜猜,在master端和slave端字段顺序不同的情况下,sbr能不能保证正确复制呢?继续看

mysql> set @@session.binlog_format=statement;
Query OK, 0 rows affected (0.00 sec)

mysql> INSERT INTO `test`.`t1` (`a`, `b`, `c`, `d`) VALUES(‘a1111′,’b2222′,’c3333′,’d4444’);
Query OK, 1 row affected (0.35 sec)

mysql> select a,b,c,d from t1;
+——-+——-+——-+——-+
| a     | b     | c     | d     |
+——-+——-+——-+——-+
| a1    | b2    | c3    | d4    |
| a11   | b22   | c33   | d44   |
| a111  | b222  | c333  | d444  |
| a1111 | b2222 | c3333 | d4444 |
+——-+——-+——-+——-+
4 rows in set (0.00 sec)

mysql>

而在slave端我们看看结果:

mysql> select a,b,c,d from t1;
+——-+——-+——-+——-+
| a     | b     | c     | d     |
+——-+——-+——-+——-+
| a1    | b2    | c3    | d4    |
| a11   | b22   | c33   | d44   |
| a111  | d444  | c333  | b222  |
| a1111 | b2222 | c3333 | d4444 |
+——-+——-+——-+——-+
4 rows in set (0.00 sec)

mysql> select * from t1;
+—-+——-+——-+——-+——-+
| id | a     | d     | c     | b     |
+—-+——-+——-+——-+——-+
|  1 | a1    | d4    | c3    | b2    |
|  2 | a11   | d44   | c33   | b22   |
|  3 | a111  | b222  | c333  | d444  |
|  4 | a1111 | d4444 | c3333 | b2222 |
+—-+——-+——-+——-+——-+
4 rows in set (0.00 sec)

mysql>

记录被正确复制,有木有?答案是有的。

因为sbr是将sql语句原封不动地写入binlog文件(所以被原封不动地重演到slave端)。但是rbr呢?

我们可以使用工具mysqlbinlog来看看binlog文件就知道了:

mysql> flush logs;
Query OK, 0 rows affected (0.30 sec)

mysql> show master status\g
+——————+———-+————–+——————+———————————————+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set                           |
+——————+———-+————–+——————+———————————————+
| mysql-bin.000036 |      194 |              |                  | e2e2f927-e75c-11e5-ac89-5c260a17ccde:1-7397 |
+——————+———-+————–+——————+———————————————+
1 row in set (0.00 sec)

mysql>

切换到新的binlog文件上,并且当前binlog是36号文件。

在sbr模式下:

mysql> set @session.binlog_format=’statement’;
Query OK, 0 rows affected (0.00 sec)

mysql> INSERT INTO `test`.`t1` (`a`, `b`, `c`, `d`) VALUES(‘az’,’bz’,’cz’,’dz’);
Query OK, 1 row affected (0.07 sec)

mysql> flush logs;
Query OK, 0 rows affected (0.30 sec)

mysql>

我们看看36号binlog文件:

D:\Program Files\mysql-5.7.11-winx64\data>mysqlbinlog -v mysql-bin.000036
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=1*/;
/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
DELIMITER /*!*/;
# at 4
#160324 14:43:24 server id 2  end_log_pos 123 CRC32 0x5f231a1b  Start: binlog v 4, server v 5.7.11-log created 160324 14:43:24
BINLOG ‘
jIzzVg8CAAAAdwAAAHsAAAAAAAQANS43LjExLWxvZwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAEzgNAAgAEgAEBAQEEgAAXwAEGggAAAAICAgCAAAACgoKKioAEjQA
ARsaI18=
‘/*!*/;
# at 123
#160324 14:43:24 server id 2  end_log_pos 194 CRC32 0xf8ccad7f  Previous-GTIDs
# e2e2f927-e75c-11e5-ac89-5c260a17ccde:1-7397
# at 194
#160324 14:45:31 server id 2  end_log_pos 259 CRC32 0x1d072fcf  GTID    last_committed=0        sequence_number=1
SET @@SESSION.GTID_NEXT= ‘e2e2f927-e75c-11e5-ac89-5c260a17ccde:7398’/*!*/;
# at 259
#160324 14:45:31 server id 2  end_log_pos 338 CRC32 0x68889415  Query   thread_id=8     exec_time=0 error_code=0
SET TIMESTAMP=1458801931/*!*/;
SET @@session.pseudo_thread_id=8/*!*/;
SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=0, @@session.unique_checks=1, @@session.autocommit=1/*!*/;
SET @@session.sql_mode=1436549152/*!*/;
SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/;
/*!\C utf8 *//*!*/;
SET @@session.character_set_client=33,@@session.collation_connection=33,@@session.collation_server=33/*!*/;
SET @@session.lc_time_names=0/*!*/;
SET @@session.collation_database=DEFAULT/*!*/;
BEGIN
/*!*/;
# at 338
# at 370
#160324 14:45:31 server id 2  end_log_pos 370 CRC32 0x63a4e5cb  Intvar
SET INSERT_ID=5/*!*/;
#160324 14:45:31 server id 2  end_log_pos 516 CRC32 0xeba65974  Query   thread_id=8     exec_time=0 error_code=0
use `test`/*!*/;
SET TIMESTAMP=1458801931/*!*/;
INSERT INTO `test`.`t1` (`a`, `b`, `c`, `d`) VALUES(‘az’,’bz’,’cz’,’dz’)
/*!*/;
# at 516
#160324 14:45:31 server id 2  end_log_pos 547 CRC32 0x233469fc  Xid = 88
COMMIT/*!*/;
# at 547
#160324 14:45:40 server id 2  end_log_pos 594 CRC32 0xc96a01d9  Rotate to mysql-bin.000037  pos: 4
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*/;

D:\Program Files\mysql-5.7.11-winx64\data>

看到有木有?sbr模式下是将sql语句直接写入binlog文件的。

那么rbr呢?继续看

mysql> show master status\G
*************************** 1. row ***************************
             File: mysql-bin.000037
         Position: 194
     Binlog_Do_DB:
 Binlog_Ignore_DB:
Executed_Gtid_Set: e2e2f927-e75c-11e5-ac89-5c260a17ccde:1-7398
1 row in set (0.00 sec)

mysql> set @@session.binlog_format=’row’;
Query OK, 0 rows affected (0.00 sec)

mysql> INSERT INTO `test`.`t1` (`a`, `b`, `c`, `d`) VALUES(‘azz’,’bzz’,’czz’,’dzz’);
Query OK, 1 row affected (0.13 sec)

mysql> flush logs;
Query OK, 0 rows affected (0.30 sec)

mysql>

我们打开37号binlog文件:

D:\Program Files\mysql-5.7.11-winx64\data>mysqlbinlog -v mysql-bin.000037
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=1*/;
/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
DELIMITER /*!*/;
# at 4
#160324 14:45:40 server id 2  end_log_pos 123 CRC32 0x81532d9a  Start: binlog v 4, server v 5.7.11-log created 160324 14:45:40
BINLOG ‘
FI3zVg8CAAAAdwAAAHsAAAAAAAQANS43LjExLWxvZwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAEzgNAAgAEgAEBAQEEgAAXwAEGggAAAAICAgCAAAACgoKKioAEjQA
AZotU4E=
‘/*!*/;
# at 123
#160324 14:45:40 server id 2  end_log_pos 194 CRC32 0xbcc90ada  Previous-GTIDs
# e2e2f927-e75c-11e5-ac89-5c260a17ccde:1-7398
# at 194
#160324 14:49:17 server id 2  end_log_pos 259 CRC32 0xf703e1df  GTID    last_committed=0        sequence_number=1
SET @@SESSION.GTID_NEXT= ‘e2e2f927-e75c-11e5-ac89-5c260a17ccde:7399’/*!*/;
# at 259
#160324 14:49:17 server id 2  end_log_pos 331 CRC32 0xc0d13c56  Query   thread_id=8     exec_time=0 error_code=0
SET TIMESTAMP=1458802157/*!*/;
SET @@session.pseudo_thread_id=8/*!*/;
SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=0, @@session.unique_checks=1, @@session.autocommit=1/*!*/;
SET @@session.sql_mode=1436549152/*!*/;
SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/;
/*!\C utf8 *//*!*/;
SET @@session.character_set_client=33,@@session.collation_connection=33,@@session.collation_server=33/*!*/;
SET @@session.lc_time_names=0/*!*/;
SET @@session.collation_database=DEFAULT/*!*/;
BEGIN
/*!*/;
# at 331
#160324 14:49:17 server id 2  end_log_pos 388 CRC32 0x5956c1fb  Table_map: `test`.`t1` mapped to number 112
# at 388
#160324 14:49:17 server id 2  end_log_pos 444 CRC32 0x42c7621a  Write_rows: table id 112 flags: STMT_END_F

BINLOG ‘
7Y3zVhMCAAAAOQAAAIQBAAAAAHAAAAAAAAEABHRlc3QAAnQxAAUDDw8PDwgPAA8ADwAPAB77wVZZ
7Y3zVh4CAAAAOAAAALwBAAAAAHAAAAAAAAEAAgAF/+AGAAAAA2F6egNienoDY3p6A2R6ehpix0I=
/*!*/;
### INSERT INTO `test`.`t1`
### SET
###   @1=6
###   @2=’azz’
###   @3=’bzz’
###   @4=’czz’
###   @5=’dzz’

# at 444
#160324 14:49:17 server id 2  end_log_pos 475 CRC32 0x7cd4b94a  Xid = 92
COMMIT/*!*/;
# at 475
#160324 14:49:22 server id 2  end_log_pos 522 CRC32 0x5abe2a18  Rotate to mysql-bin.000038  pos: 4
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*/;

D:\Program Files\mysql-5.7.11-winx64\data>

看到红色加粗部分了吗?有木有?

在rbr模式下,sql语句引起的更改被转换成了binlog自有的表达方式,就是蓝色那段。这段代码实际才是有效的。才是被复制到slave端执行的代码。

而红色部分是由于我们在mysqlbinlog时加了-v参数,这个参数的意思就是把蓝色部分的代码给翻译成我们可读的形式展示的。

下面来看看红色部分的意思:

INSERT INTO `test`.`t1`
SET
  @1=6
  @2=’azz’
  @3=’bzz’
  @4=’czz’
  @5=’dzz’

@1,表示字段序列为1,@1=6就是1字段将值设置为6。以此类推。所以很明显,如果master和slave端字段顺序不一致,那么肯定有问题。

所以mysql数据库对字段顺序是敏感的。

下面来看一个update语句对应的mysqlbinlog代码:

执行sql是这样的:

update t1 set c=123 where id=1;

而实际上数据库binlog代码是这样的(binlog_row_image=full):

### UPDATE `test`.`t1`
### WHERE
###   @1=1
###   @2=’a1′
###   @3=’b2′
###   @4=’c3′
###   @5=’d4′
### SET
###   @1=1
###   @2=’a1′
###   @3=’b2′
###   @4=’123′
###   @5=’d4′

还是通过@4的方式表示的。delete 是:

delete from t1 where id=1;

### DELETE FROM `test`.`t1`
### WHERE
###   @1=1
###   @2=’a1′
###   @3=’b2′
###   @4=’123′
###   @5=’d4′

end。。。

而不管这个语句是否在master端引起更改。所以slave端接收到的event也是sql语句。

也就是说,在sbr里,master端执行了什么样子的sql语句,那么在slave端也要执行同样的SQL语句。

这就会有一个现象是,同一个语句在master没有引起更改,而在slave重演时引起了更改。或者两端都引起了更改,但是两端的更改不一致。

    原文作者:mysql
    原文地址: https://blog.csdn.net/q3dxdx/article/details/50971300
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞