MySQL 基于row的复制的优缺点

来自Linux78|wiki
Bob讨论 | 贡献2020年12月10日 (四) 15:35的版本 (创建页面,内容为“基于row的复制的优点 可以正确复制所有数据的变更最安全的复制格式。 注意:会更新MySQL系统库数据的GRANT、REVOKE、TRIGGER、…”)
(差异) ←上一版本 | 最后版本 (差异) | 下一版本→ (差异)

基于row的复制的优点

可以正确复制所有数据的变更最安全的复制格式。

注意:会更新MySQL系统库数据的GRANT、REVOKE、TRIGGER、PROCEDURE、VIEW等操作,都是使用statement格式复制到从库的。

而CREATETABLE ... SELECT之类的语句的复制,会被拆分为两个步骤:建表操作使用statement格式的日志记录;涉及数据插入操作时,会使用row格式的日志记录。但GTID复制模式不允许执行CREATE TABLE ... SELECT语句,因为两步操作会导致产生两个不同的GTID(在GTID机制下,二进制日志中的每一个操作都会生成一个单独的GTID)。从逻辑上来说,这显然是不合理的,所以启用GTID之后,GTID的使用限制中有不允许执行该语句这一条。

对于以下类型的语句,从库需要的行锁更少,实现了更高的并发性:

INSERT INTO ... SELECT•

使用了AUTO_INCREMENT(自增字段)的INSERT语句(这里指的是INSERT语句在对定义了自增字段的表执行插入数据时,不指定自增字段名和自增字段值,让其自动分配)。

在UPDATE或DELETE语句中,WHERE条件字段未使用索引时,可能导致全表扫描,但大多数被扫描的行实际上都不会被修改,只有满足WHERE条件值的行才会真正被修改。采用statement格式的二进制日志中记录的是原始SQL语句,这时如果该语句无法使用索引,则会扫描并锁定全表的所有数据;而如果采用row格式,则二进制日志中记录的是逐行数据变更,从库在回放这些二进制日志时也逐行回放,不会锁住所有行。

这得益于从MySQL 5.6开始引入的一个新特性:在row格式下,如果表存在主键或唯一索引,那么可以通过特殊的优化算法找到能够唯一标志行的主键值或唯一索引值,从而避免对不需要修改的行加锁。查找算法由系统变量slave_rows_search_algorithms进行设置。


基于row的复制的缺点

生成更多的二进制日志数据,因为基于row的复制会将每行数据的变更都写入二进制日志。利用二进制日志进行备份和恢复的时间也会更长。此外,二进制日志的文件锁也会因为需要更长的时间来写入数据而被持有更久的时间,这可能会影响数据库的并发能力。可以使用系统变量binlog_row_image = minimal来减少二进制日志的写入量。

如果要生成大字段的BLOB值,使用基于row的复制比使用基于statement的复制耗费的时间更长,因为前者记录了BLOB字段的具体值,而不是生成数据的语句。

无法直接看到从库中执行的语句,但是可以使用mysqlbinlog工具的--base64-output= decode-rows和--verbose选项进行查看,或者在主库中启用系统变量binlog_rows_ query_log_events,它会在二进制日志中写入一个Rows_query_log_event类型的事件来记录原始的语句文本,可以使用mysqlbinlog工具的-vv选项来查看。

对于使用MyISAM存储引擎的表,当INSERT语句操作多行数据,在从库中重放该INSERT语句时,可能需要更多的表级锁,即在基于row的复制中,MyISAM引擎的并发性能会受到很大影响