MySQL性能优化之Innodb事务系统,值得收藏
副标题[/!--empirenews.page--]
今天主要分享下Innodb事务系统的一些优化相关,以下基于mysql 5.7。 一、Innodb中的事务、视图、多版本 1. 事务 在Innodb中,每次开启一个事务时,都会为该session分配一个事务对象。而为了对全局所有的事务进行控制和协调,有一个全局对象trx_sys,对trx_sys相关成员的操作需要trx_sys->mutex锁。 mysql数据库遵循的是两段锁协议,将事务分成两个阶段,加锁阶段和解锁阶段(所以叫两段锁)
2. 视图 Innodb使用一种称做ReadView(视图)的对象来判断事务的可见性(也就是ACID中的隔离性)。根据可见性原则,某个新开启的事务不应该看到其他未提交的事务。 Innodb在执行一个SELECT或者显式开启START TRANSACTION WITH CONSISTENT SNAPSHOT (后者只应用于REPEATABLE-READ隔离级别) 会创建一个视图对象。对于RR隔离级别,视图的生命周期到事务提交结束,对于RC隔离级别,则每条查询开始时重分配事务。 通常一个视图中包含创建视图的事务ID,以及在创建视图时活跃的事务ID数组。例如,当开启一个视图时,当前事务的事务ID为5, 事务链表上活跃事务ID为{2,5,6,9,12},那么就会把{2,6,9,12}存储到当前的视图中(5是当前事务的ID,不记录到视图中),{2,6,9,12}对应的事务所做的修改对当前事务而言都是不可见的,小于2的事务ID对当前事务都是可见的,大于12的事务ID对当前事务是不可见的。 那么如何判断可见性呢? InnoDB表数据的组织方式为主键聚簇索引。由于采用索引组织表结构,记录的ROWID是可变的(索引页分裂的时候,Structure Modification Operation,SMO),因此二级索引中采用的是(索引键值, 主键键值)的组合来唯一确定一条记录。无论是聚簇索引,还是二级索引,其每条记录都包含了一个DELETED BIT位,用于标识该记录是否是删除记录。除此之外,聚簇索引记录还有两个系统列:DATA_TRX_ID,DATA_ROLL_PTR。DATA _TRX_ID表示产生当前记录项的事务ID;DATA _ROLL_PTR指向当前记录项的undo信息。 聚簇索引行结构(与多版本一致读有关的部分,DELETED BIT省略): 二级索引行结构: 从聚簇索引行结构,与二级索引行结构可以看出,聚簇索引中包含版本信息(事务号+回滚指针),二级索引不包含版本信息。 对于聚集索引,每次修改记录时,都会在记录中保存当前的事务ID,同时旧版本记录存储在UNDO中;对于二级索引,则在二级索引页中存储了更新当前页的最大事务ID,如果该事务ID大于readview->up_limit_id(对于上例,up_limit_id值为2),那么就需要回聚集索引判断记录可见性;如果小于2, 那么总是可见的,可以直接读取。 3. 多版本(MVCC) 为了便于理解MVCC的实现原理,这里简单介绍一下undo log的工作过程 在不考虑redo log 的情况下利用undo log工作的简化过程为: 说明:
MVCC只在READ COMMITED 和 REPEATABLE READ 两个隔离级别下工作。READ UNCOMMITTED总是读取最新的数据行,而不是符合当前事务版本的数据行。而SERIALIZABLE 则会对所有读取的行都加锁。 (1) SELECT InnoDB 会根据两个条件来检查每行记录:
(2) INSERT InnoDB为新插入的每一行保存当前系统版本号作为行版本号 (3) DELETE InnoDB为删除的每一行保存当前的系统版本号作为行删除标识 (4) UPDATE InnoDB为插入一行新记录,保存当前系统版本号作为行版本号,同时保存当前系统版本号到原来的行作为行删除标识。 Innodb的多版本数据使用UNDO来维护的,例如聚集索引记录(1) =>(2)=>(3),从1更新成2,再更新成3,就会产生两条undo记录。 二、Innodb事务系统优化 在MySQL 5.7版本里,针对性的对事务系统做了比较深入的优化,主要解决了下面几个问题。 1. 视图对象的创建需要trx_sys->mutex锁保护 trx_sys->mutex是事务系统最核心的全局锁对象,持有该锁进行的操作都不应该耗时过长。对于read view对象,完全可以将其缓存下来重复使用。这样就避免了持有锁分配视图内存。 因此在MySQL 5.7版本中,实例启动时就分配1024个视图对象;同时维护两个链表,一个是已使用的视图链表,一个是空闲的视图链表;当需要分配新的视图时,总是从空闲视图链表中分配,如果没有,再新分配一个。 2. 视图对象中保存全局事务ID时,需要扫描事务链表 为了判断事务视图的可见性,在打开一个视图时需要拷贝当时活跃的事务ID。 (编辑:好传媒网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |