基础材料:
centos7.5 mysql 5.7.24 开启GTID
binlog对于mysql是至关重要的,binlog与undo redo一起保证了数据的完整性,用于数据恢复,崩溃恢复、任一时间点恢复、甚至是任意一条数据的恢复。所有的高可用模式也都是基于binlog进行处理的。
本文主要对binlog的三种存储格式statement、row、mixed进行分析对比其优缺点。
statement格式:
在statement格式下,binlog忠实的记录的执行过的语句,你执行过什么语句它就照搬复制到binlog中。由于其可能造成主从不一致的情况,所以生产环境基本都不会设置为statement。
优势:1、节省空间。由于只是对执行的语句进行记录,所以相比row模式binlog所占的空间很小
2、提高数据库性能。由于binlog是在事务提交时才进行fsync刷盘操作,而刷盘的操作是最耗费IO的,statement只需要记录一条语句而不是记录所有操作过的数据行。
劣势:可能造成主从不一致
在测试环境执行delete from test limit 10;删除表中的10条数据,观察binlog的内容变化,binlog部分内容如下:
#190312 21:29:43 server id 98 end log_pos 1800 crc32 0x14f1f4f3 GTID last_committed=6 nce_number=7 rbr_only=no SET@@SESSION.GTID_NEXT='f00ee5e5-ece0-11e8-9e64-000c294b8e72:21'/*!*;# at 1800 #190312 21:29:43 server id 98 end loq_pos 1879 crc32 0x6817975b Query thread_id=2 rror_code=0 SET TIMESTAMP=1552397383/*!*/; BEGIN/*!*/;# at 1879 rror_code=0#190312 21:29:43 server id 98 end 1og_pos 1978 crc32 0xb5dc29fb Query thread_id=2 SET TIMESTAMP=1552397383/*!*/; delete from test limit 10 j*!*/; # at 1978 #190312 21:29:43 server id 98 end_1og_pos 2058 crc32 0xfb287e31 Query thread_id=2 rror code=0 SET TIMESTAMP=1552397383/*!*/: COMMIT
可以看到执行过的语句被原原本本的记录到binlog中,被同步到从库重做。
执行delete from test limit 10;时还会产生一个警告,大意就是使用statement格式时执行limit语句可能造成主从同步不一致。因为limit语句只是指定了删除10条记录,但没有指定具体是哪10条,当mysql在两次执行时选择了不同的索引进行操作时,删除的记录就是不同的。当然还有其他函数也可能会造成主从不一致。
row格式:
在row格式下,binlog对于DDL操作记录执行的SQL语句,对于DML语句则记录具体操作的数据行。一般生产环境采用该格式。
优势:对于DML操作记录了具体的行数据,保证重放的一致性,同时也可以对一些误操作的数据进行单独恢复提供了可能性
劣势:由于记录了每条数据的内容变更,导致了binlog日志占用了很大的空间,由于fsync时一次写入数据过多,在一定程度上影响了性能。
调整binlog格式为row,执行delete from testxxxx limit 10;观察binlog的内容变化,binlog部分内容如下:
### DELETE FROM test,testxxxx ### WHERE ### @1=101 /* INT meta=0 nullable=0 is_nu1l=0 ### @2=101 /* INT meta=0 nullaple=1 is nul]=0 ### @3=101 /* INT meta=0 nullable=1 is_nul7=0 ### DELETE FROM test,testxxxx ### WHERE ### @1=102 /* INT meta=0 nullable=0 is_null=0 ### @2=102 /* INT meta=0 nullable=1 is_nul7=0 ### @3=102 /* INT meta=0 nullable=1 is_nul1=0 ### DELETE FROM test,testxxxx ### WHERE ### @1=103 INT meta=0 nullable=0 is_null=0 ### @2=103 INT meta=0 nullable=1 is_nul]=0 ### @3=103 /* INT meta=0 nullable=1 is_nu17=0 ### DELETE FROM test,testxxxx ### WHERE ### @1=104 * INT meta=0 nullable=0 is nu1]=0 )* ### @2=104 INT meta=0 nullable=1 is_nul1=0 * ### @3=104 INT meta=0 nullabiteplogicgenme
可见binlog修改的每一行数据的具体值都被记录了下来。如果我需要恢复其中的某一条记录只要把delete转换成insert就可以了,这是其他格式做不到的。
mixed格式:
集前两种格式的优点,对于DDL只对SQL语句进行记录。对DML操作则会进行判断,如果mysql判断会造成主从不一致,就会采用row格式记录,反之则用statement格式记录。
优点:节省空间,提高数据库性能,通过判断保证数据重放时的一致性。
缺点:无法对误操作数据进行单独恢复
调整binlog格式为mixed,执行delete from test limit 1;和delete from test where a =1;观察binlog的内容变化,binlog部分内容如下:
### DELETE FROMtest.test ### WHERE ### @1=1 /* INT meta=0 nullable=1 is_nu11=0 */ ### @2=2 /* INT meta=0 nullable=1 is_nu11=0 */ # at 1257 #190312 23:24:17 server id 98 end_log_pos 1288 CRC32 COMMIT/*!*/;# at 1288 #190312 23:24:32 server id 98 end_log_pos 1353 CRC32 nce_number=5rbr_only=no SET @@SESSION.GTID_NEXT='f00ee5e5-ece0-11e8-9e64-000c# at 1353 #190312 23:24:32 server id 98 end log.pos 1432 cRc32 rror_code=0 SET TIMESTAMP=1552404272/*!*/; BEGIN/*!*/;# at 1432 #190312 23:24:32 server id 98 end_log_pos 1532 CRC32 rror_code=0 SET TIMESTAMP=1552404272/*!*/ delete from test where a=1 /*!*/;
可见对于limit语句可能造成主从不一致的情况下,mysql选择了row格式进行记录,对于后面执行delete语句则采用了statement格式进行记录。