贵州省住房和城乡建设厅网站官网,兰州百度网站建设,做征婚网站,做拍客哪个网站好MySQL5.7 : Innodb 事务子系统优化之前写了篇博客介绍了Percona Server对Read View的优化#xff0c;顺带简单提到了MySQL5.7的事务子系统优化#xff0c;详细见http://mysqllover.com/?p834 。 另外一篇博客http://mysqllover.com/?p1087 也有所涉及。本文总体介绍了几个和…MySQL5.7 : Innodb 事务子系统优化之前写了篇博客介绍了Percona Server对Read View的优化顺带简单提到了MySQL5.7的事务子系统优化详细见http://mysqllover.com/?p834 。 另外一篇博客http://mysqllover.com/?p1087 也有所涉及。本文总体介绍了几个和事务子系统相关的worklog以及其代码实现。这部分代码值得细读因为他们是5.7 Innodb比较核心的改动极大的提升了只读场景下的性能。这个worklog包含几点变化第一无需显示的开启只读事务所有的事务开始默认为只读事务当遇到读写SQL时自动加入读写列表。第二只读事务不为其分配事务ID因此如果SHOW ENGINE INNODB STATUS时看到大量事务的ID表现的很怪异时(非常大的整数值)不要觉得奇怪。该改进带来的最大的好处是你无需修改你的业务SQL。其实这才是用户能接受的特性如果没有量级别的提升谁会愿意去改代码呢?不过显而易见的这个优化也带了某些 运维的‘退化’例如你再也无法从SHOW ENGINE INNODB STATUS中发现一个活跃的长时间不提交的只读事务(例如BEGIN;SELECT;SELECT…)你需要去查询INNODB_TRX表来获得这些信息。我们以一个典型的例子来开启这个话题首先准备一个简单的表。隔离级别为READ-COMMITCREATE TABLE t1 (a INT PRIMARY KEY, b INT);INSERT INTO t1 VALUES (1,RAND()*100),(2,RAND()*100);BEGIN;以BEGIN显式开启一个事务b) SELECT * FROM t1;分配一个事务句柄ha_innobase::openha_innobase::info_lowupdate_thdcheck_trx_existsinnobase_trx_allocatetrx_allocate_for_mysql新分配的事务句柄会加入到trx_sys-mysql_trx_list并重复使用。开始一个只读事务开启的事务不分配事务ID 不分配回滚段row_search_mvcc-trx_start_if_not_started-trx_start_lowAssign Read Viewrow_search_mvcctrx_assign_read_viewMVCC::view_open分配的read view会拷贝当前的活跃事务ID设置最高和最低可见事务ID然后加入到活跃事务的read view链表上(MVCC::m_views)c) UPDATE t1 SET bb1 WHERE a2;row_search_mvcclock_tabletrx_set_rw_mode将事务转换成读写事务模式分配回滚段分配事务ID。加入读写事务链表(trx_sys-rw_trx_ids, trx_sys-rw_trx_set, trx_sys-rw_trx_list)。d) COMMIT; 事务提交代码在该worklog种优化了read view的创建对MVCC控制视图部分的代码进行了重构。具体包括以下几个方面在之前版本中read view的创建的复杂度为O(N)因为需要扫描读写事务链表现在创建一个read view 需要以下几步Step 1:view-prepare(trx-id);拷贝事务ID(不包含自己的事务ID)相当于做一个当前活跃读写事务的快照存放在视图中直接使用memcpy的方式 (copy_trx_ids(trx_sys-rw_trx_ids))这一点和percona的优化是一样的。设置m_low_limit_no m_low_limit_idStep 2:view-complete();设置视图的m_up_limit_id表示所有小于这个值的修改都可见Step 3:UT_LIST_ADD_FIRST(m_views, view);将视图加入到活跃视图链表中。b) 在之前版本中是在持有trx_sys mutex时创建的read view。为了降低分配/释放read view的开销维护了两个read view链表一个用于放当前活跃的视图链表一个用于放空闲的、可分配的视图链表。当系统启动时会初始化一定数量的read view放到空闲链表上。Percona实现了类似的方案不同的是Percona的read view在事务完成后不是放到空闲链表而是下次继续重用(但从活跃链表移除不管是否是读写事务)c) 对于autocommit的只读事务即时当前没有活跃事务也可能因为创建read view 而大量别的线程在释放read view导致trx_sys mutex冲突。针对该问题实际上我已经在博文http://mysqllover.com/?p1087中描述过了对于自动提交的查询在关闭read view时是不从视图链表上移除的在再次开启事务重用该read view时如果这期间没有读写事务都无需重新初始化read view直接使用即可。 因此如果一台实例上的都是自动提交的只读事务完全可以避免trx_sys mutex的开销。d) 需要持有trx_sys mutex来遍历rw_trx_list以判断更改是否可见或者根据事务id获取事务对象trx_t由于已经保存了事务ID的快照因此直接根据二分查找查找有序数组即可无需遍历读写事务链表参考函数ReadView::changes_visibletrx_sys_t新增成员rw_trx_set用于维护从trx_id到trx_t的映射。这样可以根据事务ID快速找到对应的事务对象而无需扫描事务链表。参考函数trx_get_rw_trx_by_id主要更改在完成上述修改后无需再维持ro_trx_list了因为所有事务默认都被当做只读事务这个链表开销完全可以忽略掉的。该worklog主要实现了隐式锁向现式锁转换的一个优化点。在获取活跃事务对象时无需持有lock_sys mutex锁。在连续内存中预分配事务对象保持内存的连续性有利于编译器或者CPU做出某些优化例如内存预取之类的(不是很了解这一块不展开叙述)为了实现事务对象内存分配回收等在底层分装了一些pool类事务对象实际上被管理在一个池结构中。后面我再单独写一篇博客来介绍新加的这些底层结构。在启动时初始化trx_pools (trx_pool_init)初始化时分配4M内存在shutdown时释放(trx_pool_close())为了管理事务对象池设计了三个类TrxFactoryTrxPoolLockTrxPoolManagerLock获取事务对象trx_create_low —- trx_pools-get()释放事务对象trx_free —- trx_pools-free(trx)相关代码http://bazaar.launchpad.net/~mysql/mysql-server/5.7/revision/5753