在MySQL的慢查询日志中出现只有commit,但是没有任何其它SQL的这种现象到底是一个什么情况呢?如下截图所示(没有优化前的一个Zabbix数据库)
其实在慢查询日志中出现commit,就是因为事务提交(commit)的时间过长。至于为什么commit的时间过长,可能有下面一些原因:
1:磁盘IO过载时或者发生故障的时候,因此在事务完成时进行刷新(flush)需要很长时间。
2:二进制日志轮换(Rotate)时,在二进制日志轮换完成之前,无法提交其他任何事务。这个会引起事务提交出现短暂的停顿/卡顿。尤其当二进制日志过大或者IO性能差的时候,这个停顿可能更长。导致commit的时间超过参数long_query_time的值。从而commit语句出现在慢查询日志。
3: MySQL的系统参数innodb_flush_log_at_trx_commit、sync_binlog、max_binlog_size的设置可能会引起这种现象。但是注意,并不是说设这些参数的某个设置就一定会引起这个现象。而是说在某种取值下,在磁盘IO过载,业务暴增等一系列的综合因素影响下,会增加这种现象出现的概率。
举个例子,将MySQL配置为sync_binlog = 0的情况下,这可能导致操作系统缓存整个二进制日志,甚至使用最快的磁盘。默认情况下,最大二进制日志大小为1G,如果所有日志均已缓存,则需要一些时间才能写出。 在这种情况下,没有其他事务可以提交。那么就可能出现commit耗时变长的情况。而如果将max_binlog_size设置小一些,那么就缓解这种情况。
4:事务过大,导致事务提交的时候,需要等候的时间过长,尤其是发生二进制日志轮换时。
下面我们构造一个这样的例子,准备测试环境,如下所示,当然这个实验受数据量,表的结构,还有MySQL的参数等很多因素的影响。下面实验仅仅说明一个超大的事务可能出现这种现象。在你的测试环境中,根据实验情况进行调整。
create table test(id int auto_increment primary key, name varchar(32));
delimiter &&
drop procedure if exists prc_insert;
create procedure prc_insert(in row_cnt int)
begin
declare i int;
set i=1;
while i < row_cnt do
insert into test(name)
SELECT CONCAT('KERRY', cast(i as char));
set i = i+1;
end while;
end &&
delimiter ;