通过事务日志落盘时间理解innodb_flush_log_at_trx_commit

事务日志刷写参数 innodb_flush_log_at_trx_commit=0|1|2三个值
其原理如下图

image

1 此为默认值,日志缓冲区将写入日志文件,并在每次事务后执行刷新到磁盘。 这是完全遵守ACID特性

0 提交时没有写磁盘的操作; 而是每秒执行一次将日志缓冲区的提交的事务写入刷新到磁盘。 这样可提供更好的性能,但服务器崩溃可能丢失最后一秒的事务

2 每次提交后都会写入OS的缓冲区,但每秒才会进行一次刷新到磁盘文件中。 性能比0略差一些,但操作系统或停电可能导致最后一秒的交易丢失

高并发业务行业最佳实践,是使用第三种折衷配置(=2):

1.配置为2和配置为0,性能差异并不大,因为将数据从Log Buffer拷贝到OS cache,虽然跨越用户态与内核态,但毕竟只是内存的数据拷贝,速度很快
2.配置为2和配置为0,安全性差异巨大,操作系统崩溃的概率相比MySQL应用程序崩溃的概率,小很多,设置为2,只要操作系统不奔溃,也绝对不会丢数据

那么我们了解了参数innodb_flush_log_at_trx_commit=0|1|2
无非是1是最安全的,每条事务commit后都需要立即从事务日志缓冲区log buffer 执行落盘
0是每条事务commit后会继续放到事务日志缓冲区log buffer中,但是每隔一秒就会落盘log buffer中已提交的事务。假如log buffer中存了上千上万个已提交事务,这一秒也要落盘完。
2和0一样,每条事务commit后不会立即落盘,而是放到os buffer缓冲区中,它和0的区别就是:
0将已提交的事务放在log buffer即mysql的在内存的日志缓冲区,而2是将已提交的事务放到os buffer 系统的内存缓冲区,从用户态转向内核态仅此而已。

准备阶段

库下创建数据表testlog 查看初始大小

use helldb;
CREATE TABLE `testlog` (
  `id` int NOT NULL AUTO_INCREMENT,
  `name` char(10) DEFAULT NULL,
  `age` int DEFAULT '20',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=100001 DEFAULT CHARSET=utf8

root@17  hellodb]# ll -h
总用量 992K
-rw-r----- 1 mysql mysql 112K 1月  12 04:59 classes.ibd
-rw-r----- 1 mysql mysql 112K 1月  12 04:59 coc.ibd
-rw-r----- 1 mysql mysql 112K 1月  12 04:59 courses.ibd
-rw-r----- 1 mysql mysql 112K 1月  12 04:59 scores.ibd
-rw-r----- 1 mysql mysql 112K 1月  12 04:59 students.ibd
-rw-r----- 1 mysql mysql 112K 1月  14 14:33 t1.ibd
-rw-r----- 1 mysql mysql 112K 1月  14 16:10 t2.ibd
-rw-r----- 1 mysql mysql 112K 1月  13 18:22 t3.ibd
-rw-r----- 1 mysql mysql 112K 1月  12 04:59 teachers.ibd
-rw-r----- 1 mysql mysql 112K 1月  14 16:57 testlog.ibd  #看到只有112k
-rw-r----- 1 mysql mysql 112K 1月  12 04:59 toc.ibd
-rw-r----- 1 mysql mysql 128K 1月  14 10:41 t_user.ibd

定义存储过程 向testlog表中插入十万行数据

delimiter //
create procedure sp_testlog()
begin
declare i int;
set i=1;
while i <= 100000
do insert into testlog(name,age) values(concat("wang",i),i);
set i=i+1;
end while;
end //
delimiter;

(root@localhost) [hellodb]> show create procedure sp_testlog\G;
*************************** 1. row ***************************
           Procedure: sp_testlog
            sql_mode: ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION
    Create Procedure: CREATE DEFINER=`root`@`localhost` PROCEDURE `sp_testlog`()
begin
declare i int;
set i=1;
while i <= 100000
do insert into testlog(name,age) values(concat("wang",i),i);
set i=i+1;
end while;
end
character_set_client: utf8mb4
collation_connection: utf8mb4_0900_ai_ci
  Database Collation: utf8_general_ci
1 row in set (0.00 sec)

验证

innodb_flush_log_at_trx_commit=1级别下十万次事务刷写时长
当我们直接call调用定义好的存储过程(procredure)sp_testlog时,由于自动提交autocommit=1开启,所以mysql认为存储过程中的每条DML语句都是一条事务。这里有十万条事务提交。
在innodb_flush_log_at_trx_commit=1时,每条事务commit都必须立即刷盘,所以10万条事务,会落盘10万次 IO操作。相当慢。

#innodb_flush_log_at_trx_commit=1 每次提交事务都立即将日志从log buffer中刷写到磁盘
(root@localhost) [hellodb]> select @@innodb_flush_log_at_trx_commit;
+----------------------------------+
| @@innodb_flush_log_at_trx_commit |
+----------------------------------+
|                                1 |
+----------------------------------+
1 row in set (0.00 sec)

#直接call sp_testlog 
(root@localhost) [hellodb]> call sp_testlog;
Query OK, 1 row affected (45.36 sec) #用时45秒

#因为我们定义的存储过程 如下
delimiter //
create procedure sp_testlog()
begin
declare i int;
set i=1;
while i <= 100000
do insert into testlog(name,age) values(concat("wang",i),i);
set i=i+1;
end while;
end //
delimiter;
#每条insert在autocommit=1自动提交下都是单独的一个事务。
#所以该存储过程在执行了10万次事务。在innodb_flush_log_at_trx_commit=1级别刷写时长为45秒

#查看ibd文件变大为12M
root@17  hellodb]# ll -h
总用量 13M
-rw-r----- 1 mysql mysql 112K 1月  12 04:59 classes.ibd
-rw-r----- 1 mysql mysql 112K 1月  12 04:59 coc.ibd
-rw-r----- 1 mysql mysql 112K 1月  12 04:59 courses.ibd
-rw-r----- 1 mysql mysql 112K 1月  12 04:59 scores.ibd
-rw-r----- 1 mysql mysql 112K 1月  12 04:59 students.ibd
-rw-r----- 1 mysql mysql 112K 1月  14 14:33 t1.ibd
-rw-r----- 1 mysql mysql 112K 1月  14 16:10 t2.ibd
-rw-r----- 1 mysql mysql 112K 1月  13 18:22 t3.ibd
-rw-r----- 1 mysql mysql 112K 1月  12 04:59 teachers.ibd
-rw-r----- 1 mysql mysql  12M 1月  14 19:03 testlog.ibd
-rw-r----- 1 mysql mysql 112K 1月  12 04:59 toc.ibd
-rw-r----- 1 mysql mysql 128K 1月  14 10:41 t_user.ibd

innodb_flush_log_at_trx_commit=1级别 一次事务执行时长
autocommit=1,但是begin显式开启事务 调用存储过程(procredure)sp_testlog时,mysql认为整个存储过程是一条事务,即使里面执行了10万次insert也是一条事务。所以只有一次事务提交。
在innodb_flush_log_at_trx_commit=1时,每条事务commit都必须立即刷盘,所以1条事务,flush一次 打包把这十万个一次性落盘不用每次一条一条落盘了 很快。

#innodb_flush_log_at_trx_commit=1 每次提交事务都立即将日志从log buffer中刷写到磁盘
(root@localhost) [hellodb]> select @@innodb_flush_log_at_trx_commit;
+----------------------------------+
| @@innodb_flush_log_at_trx_commit |
+----------------------------------+
|                                1 |
+----------------------------------+
1 row in set (0.00 sec)

(root@localhost) [hellodb]> begin;call sp_testlog;commit;
Query OK, 0 rows affected (0.00 sec)
Query OK, 1 row affected (4.01 sec)
Query OK, 0 rows affected (0.49 sec)
#我们看到将存储过程call sp_testlog作为一个事务来说,其内部的十万条insert合起来一个事务的所有操作。
#总共执行时间为4秒 大大小于10万次事务操作

innodb_flush_log_at_trx_commit=0级别 一次事务执行时长

#innodb_flush_log_at_trx_commit=0 事务提交时不会立即刷新到磁盘 每秒从log buffer中刷新已提交的事务到磁盘。如果故障 丢失一秒钟的数据 但是性能因为从log buffer直接刷磁盘 很快
(root@localhost) [hellodb]> begin;call sp_testlog;commit;
Query OK, 0 rows affected (0.00 sec)
Query OK, 1 row affected (3.01 sec)
Query OK, 0 rows affected (0.03 sec)
#我们看到将存储过程call sp_testlog作为一个事务来说,其内部的十万条insert合起来一个事务的所有操作。
#总共执行时间为3秒 大大小于10万次事务操作

innodb_flush_log_at_trx_commit=2级别下一次事务执行时长

#innodb_flush_log_at_trx_commit=2 事务提交时会写入os buffer缓冲区,每秒执行一次从os buffer刷新日志记录到到磁盘文件中。 性能比0略差一些,但操作系统或停电可能导致最后一秒的交易丢失
(root@localhost) [hellodb]> begin;call sp_testlog;commit
Query OK, 0 rows affected (0.00 sec)
Query OK, 1 row affected (2.97 sec)
Query OK, 0 rows affected (0.05 sec)

通过上面例子,我们明显看到了有事务日志与没有事务日志的区别。
有事务 十万条insert打包统一从内存写入到磁盘。
有事务 级别不一样 速度差不多 安全不一样。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,277评论 6 503
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,689评论 3 393
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,624评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,356评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,402评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,292评论 1 301
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,135评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,992评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,429评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,636评论 3 334
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,785评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,492评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,092评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,723评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,858评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,891评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,713评论 2 354

推荐阅读更多精彩内容