MySQL 二进制文件 (STATEMENT)浅谈
看完<高可用性 MySQL>的第三章,对二进制日志有加深了一些认识,现在总结下知识点。
知识点:
1:二进制日志是公共资源,所有的线程都向它写入语句,避免两个线程同时更新二进制日志。在写二进制日志前,需要获得一个互斥锁,在事件完成后释放。由于服务器的所有线程都向二进制日志写语句,所以这个锁会常常阻塞某些会话线程。
2:默认情况下,二进制日志不是在每次写的时候直接同步到磁盘的,需要先写到二进制日志缓存里(binlog_cache_size)。当宕机时,会丢失该部分的事务,需要用sync_binlog=1来确保写1次缓存就同步到磁盘来保证,特殊情况下还需要用innodb_support_xa (确保二进制日志和存储引擎的分布提交)开启来保证。二进制日志在事务提交前写磁盘。
使用支持事务的存储引擎,所有未提交的二进制日志先放到缓存里面,等到事务提交,再把缓冲中的二进制日志写到磁盘。
3:二进制日志的结构:
Log_name:这个event所在的binlog名称。
Pos:这个event在当前binlog中的位置
Event_type:这个event的类型,类型是有很多。每个二进制日志文件的开头都是Format_desc类型。
Server_id:这个event是在哪个server上发生的。注意在replication中这个server id记录的是master端的server id。不是replication则记录自己的server id。
End_log_pos:下一个event的位置,因此当前这个event的长度是End_log_pos-Pos。
Info:本条event的信息。
关于Event_type这里简单说明下:event 类型是有很多:Format_desc、Query、User var、Xid、Rand、Intvar、Stop、Rotate 等等。下面解释:
User var:自定义变量。
Rand : 随机数种子。
Intvar :Auto_increment信息。
Format_desc:每一个binlog文件的头,格式信息。
Rotate:每个binlog文件的结束event时候,如Flush logs、大小上线时产生的类型。
Stop :每个binlog文件的结束event时候,如MySQL 重启时产生的类型。
注意,要是数据库被Kill掉的话,这个时候不会有任何event写入。
Query :一般执行的查询。
Xid : 事务提交的信息。
其他还有很多event类型,最常见的可能就是Query了,update、delete等操作都是Query类型.通常一个update操作在binlog文件中会产生好几个event,因为为了保证主从一致,需要确保很多外部因素的一致。
在这里我们引入一个分组的概念:除了format_desc和rotate,其他的event我们往往可以对其进行分组,对于事务型数据库来说,往往认为一个事务就是一个分组,对于非事务型数据库和类似create、alter这类语句来说,一条语句本身就是一个分组.
*************************** 1. row ***************************
Log_name: mysql-bin.000005
Pos: 4
Event_type: Format_desc
Server_id: 1
End_log_pos: 106
Info: Server ver: 5.1.66-0ubuntu0.11.10.2-log, Binlog ver: 4
*************************** 2. row ***************************
Log_name: mysql-bin.000005
Pos: 106
Event_type: Query
Server_id: 1
End_log_pos: 174
Info: BEGIN
*************************** 3. row ***************************
Log_name: mysql-bin.000005
Pos: 174
Event_type: Query
Server_id: 1
End_log_pos: 260
Info: use `test`; truncate table employee
*************************** 4. row ***************************
Log_name: mysql-bin.000005
Pos: 260
Event_type: Xid
Server_id: 1
End_log_pos: 287
Info: COMMIT /* xid=48640 */
*************************** 5. row ***************************
Log_name: mysql-bin.000005
Pos: 287
Event_type: Query
Server_id: 1
End_log_pos: 355
Info: BEGIN
*************************** 6. row ***************************
Log_name: mysql-bin.000005
Pos: 355
Event_type: User var
Server_id: 1
End_log_pos: 433
Info: @`pass`=_latin1 0x2A36424234383337454237343332393130354545343536384444413744433637454432434132414439 COLLATE latin1_swedish_ci
*************************** 7. row ***************************
Log_name: mysql-bin.000005
Pos: 433
Event_type: Query
Server_id: 1
End_log_pos: 577
Info: use `test`; insert into employee(name,email,password) values('mats','mats@example.com',@pass)
*************************** 8. row ***************************
Log_name: mysql-bin.000005
Pos: 577
Event_type: Xid
Server_id: 1
End_log_pos: 604
Info: COMMIT /* xid=48641 */
*************************** 9. row ***************************
Log_name: mysql-bin.000005
Pos: 604
Event_type: Rotate
Server_id: 1
End_log_pos: 647
Info: mysql-bin.000006;pos=4
这里有一个疑问:因为主上binlog中的每个event都会把信息通过IO线程传给从,在上面说的binlog格式中End_log_pos表示下一个事件的开始位置, 当主宕机的时候,再开起来,会新起一个binlog,而前一个binlog中End_log_pos表示下一个事件的位置已经无效了,并且Event_type没有任何提示说轮循了。同理所以它在replication中会遇到从找不到pos,因为没有提示从,主已经另起来一个binlog文件了。解决办法是重新change 到 最新的binlog最新的pos。<等待验证>
3:触发器(trigger)、事件(Event)、存储函数(Procedure、Function)的记录:
请见这篇文章
触发器主从都需要有,事件和存储函数只需要做主上有就可以了。
注意:在Row Format格式下,触发器不需要从上也存在。
4:一张A表上有Before 触发器的时候,需要注意,即使在A表有错误的执行(比如重复键),也会导致该触发器执行,使触发的内容写到和触发器相关的表中(B<Myisam>)。在STATEMENT 下,触发的sql不会记录。导致主从不一致。
5:ROW 和 STATEMENT 模式下的记录方式不同。