标签:rom serve null 回滚 roo 3.2 commit 完美 reads
举个栗子
session1:
(root@localhost) [test]> select * from t;
+------+
| a |
+------+
| 1 |
+------+
1 row in set (0.00 sec)
(root@localhost) [test]> begin;
Query OK, 0 rows affected (0.00 sec)
(root@localhost) [test]> update t set a = a + 1 where a = 1;
Query OK, 1 row affected (0.01 sec)
Rows matched: 1 Changed: 1 Warnings: 0
(root@localhost) [test]> select * from t;
+------+
| a |
+------+
| 2 |
+------+
1 row in set (0.00 sec)
session2:
(root@localhost) [test]> begin;
Query OK, 0 rows affected (0.00 sec)
(root@localhost) [test]> select * from t;
+------+
| a |
+------+
| 1 |
+------+
1 row in set (0.00 sec)
第一个会话开启事务更新记录,不提交,此时记录是被锁住的
新开一个会话去select 这条记录,并不会因为有锁而阻塞,读到的是原来的记录
这就是MVCC——多版本并发控制,实现原理就是undo,没有额外开销,读到这条记录被更新则读这条记录之前的版本
此时commit之后,之前版本的undo是不能被马上回收的,因为其他线程可能还在引用之前版本的undo,真正的回收undo是purge线程做的
purge的作用是删除undo,真正删除一条记录(完成update和delete)
delete from table where pk=1;
在page中只是标记为删除,page上并没有真正的删除
相关参数:innodb_purge_threads 默认是1,5.7中设大一点,4或者8,都是ssd性能比较好
5.5之前所有的purge操作都是master thread做的
默认只有一个purge thread
innodb_purge_threads={0|1}5.6
N purge thread
innodb_purge_threads={4}
1024个槽------1024个undo回滚段,每个槽对应不同的undo日志
一旦事务提交,undo就放到hitory list中
tips:
因为记录不是有序的,所以purge操作需要大量离散读取操作
undo不断增大,不能有效回收,导致系统空间不断增大,
最主要的原因有两个:
索引没有添加
检查slow log存在大事务
拆大为小
其实就一点,一个事务执行时间很长,那对应的undo就不能回收,至少要commit完成后才能回收
另外回滚比提交慢非常多,commit很快,rollback需要的时间就是事务执行的时间,逻辑回滚
tips:
目前MySQL已经支持在线回收undo,详见阿里数据库内核月报
之前我们谈到binlog和redo的一致性是通过一个内部的xa事务保证的,这里简单聊下外部的分布式事务
(root@localhost) [test]> xa start ‘a‘; -- 开启一个分布式事务
Query OK, 0 rows affected (0.00 sec)
(root@localhost) [test]> insert into t values(2000);
Query OK, 1 row affected (0.09 sec)
(root@localhost) [test]> insert into t values(3000);
Query OK, 1 row affected (0.00 sec)
(root@localhost) [test]> xa end ‘a‘; -- 结束
Query OK, 0 rows affected (0.00 sec)
(root@localhost) [test]> xa prepare ‘a‘; -- 写prepare
Query OK, 0 rows affected (0.03 sec)
(root@localhost) [test]> xa recover; -- 看一眼,有一个分布式事务
+----------+--------------+--------------+------+
| formatID | gtrid_length | bqual_length | data |
+----------+--------------+--------------+------+
| 1 | 1 | 0 | a |
+----------+--------------+--------------+------+
1 row in set (0.00 sec)
(root@localhost) [test]> xa rollback ‘a‘; -- 回滚
Query OK, 0 rows affected (0.01 sec)
(root@localhost) [test]> xa recover; -- 再看下,没了
Empty set (0.00 sec)
这是再单实例上模拟的,意义不大
真正应用程序中两个实例做分布式事务,需要两边的prepare都成功才能最终提交
create procedure load1(count int unsigned)
begin
declare s int unsigned default 1;
declare c char(80) default repeat(‘a‘,80);
while s <= count do
insert into t1 select NULL,c;
set s = s+1;
end while;
end
call load1(1000)
上面这个存储过程的调用,auto commit导致了insert会处罚一千次fsync
正确姿势:
begin;
call load1(1000)
commit;
事务拆大为小,原因就是binlog在搞鬼,其实不一定是大事务,大的操作都要拆吧
计算利息,拆了批量执行
update account
set account_total = account_total + (1 + interest_rate)
为什么要拆?老生常谈的、
题外话:
binlog是有点讨厌不像oracle用redo,历史原因,不好说
也有好处,做大数据平台集成非常简单,把MySQL的的数据实时推到大数据平台上太简单,github上一搜一大把项目直接用
标签:rom serve null 回滚 roo 3.2 commit 完美 reads
原文地址:https://www.cnblogs.com/---wunian/p/9074760.html