设为首页 加入收藏

TOP

MySQL+InnoDB semi-consitent read原理及实现分析(一)
2017-02-21 08:15:48 】 浏览:521
Tags:MySQL InnoDB semi-consitent read 原理 实现 分析

对于熟悉MySQL,或者是看过InnoDB源码的朋友们来说,可能会听说过一个新鲜的名词:semi-consistent read 。 何谓semi-consistent read?以下一段文字,摘于semi-consistent read一文:


A type of read operation used for?UPDATE?statements, that is a combination of?read committed?and?consistent read. When an?UPDATE?statement examines a row that is already locked, InnoDB returns the latest committed version to MySQL so that MySQL can determine whether the row matches the?WHERE?condition of the?UPDATE. If the row matches (must be updated), MySQL reads the row again, and this time InnoDB either locks it or waits for a lock on it. This type of read operation can only happen when the transaction has the read committed?isolation level, or when the?innodb_locks_unsafe_for_binlog?option is enabled.


简单来说,semi-consistent read是read committed与consistent read两者的结合。一个update语句,如果读到一行已经加锁的记录,此时InnoDB返回记录最近提交的版本,由MySQL上层判断此版本是否满足update的where条件。若满足(需要更新),则MySQL会重新发起一次读操作,此时会读取行的最新版本(并加锁)。


semi-consistent read只会发生在read committed隔离级别下,或者是参数innodb_locks_unsafe_for_binlog被设置为true。


MySQL server与InnoDB引擎是如何进行交互?InnoDB引擎如何实现semi-consistent read?请见下面的详细分析。


从上面的描述中可以看出,semi-consistent read仅仅针对于update操作,因此在sql_update.cc的mysql_update方法中,有如下调用:


sql_update.cc::mysql_update()


// 通知底层引擎,尝试进行semi consistent read


? ? // 是否真正进行semi consistent read,由底层引擎决定


table->file->try_semi_consistent_read(1);


// InnoDB引擎决定当前update是否可以进行semi-consistent read


? ? ? ? // 具体的处理方法,在下节中分析


ha_innodb.cc::try_semi_consistent_read(bool yes);


// 进行update的读与更新操作



// update操作完成之后,关闭semi-consistent read


table->file->try_semi_consistent_read(0);


MySQL Server层处理semi-consistent较为简单,接下来看看InnoDB Engine的处理方式。


InnoDB Engine层面,对于semi-consistent read的处理,包括两方面的逻辑:


前面提到,MySQL Server在update时,会调用引擎的try_semi_consistent_read方法,来尝试进行semi-consistent read,而是否进行semi-consistent read,则交由底层处理。


ha_innodb.cc::try_semi_consistent_read()


if (yes &&


(srv_locks_unsafe_for_binlog


|| prebuilt->trx->isolation_level <= TRX_ISO_READ_COMMITTED))


prebuilt->row_read_type = ROW_READ_TRY_SEMI_CONSISTENT;


简单分析下,当用户设置系统参数innodb_locks_unsafe_for_binlog为true,或者是采用的事务隔离级别为read committed(或以下)时,设置prebuilt->row_read_type参数,标识当前update语句使用semi-consistent read,fetch next时需要有针对性的做特殊处理。


InnoDB fetch next的主函数入口是row_search_for_mysql,此函数如何针对性的处理semi-consistent read呢?


row0sel.c::row_search_for_mysql()



// 尝试对于定位到的记录加锁


err = sel_set_rec_lock();



case DB_LOCK_WAIT:


// 如果加锁需要等待,则判断是否可以进行semi-consistent read


? ? ? ? // 判断条件为:


? ? ? ? // 1. prebuilt->row_read_type必须设置为ROW_READ_TRY_SEMI_CONSISTEN


? ? ? ? // 2. 当前scan必须是range scan或者是全表扫描,而非unique scan


? ? ? ? // 3. 当前索引必须是聚簇索引


? ? ? ? // 4. 不满足以上三个条件,就不能进行semi-consistent read,进行加锁等待


? ? ? ? // 注意:若不需要加锁等待,那么也不需要进行semi-consistent read,直接


? ? ? ? // 读取记录的最新版本即可,没有加锁等待的开销。


if ((prebuilt->row_read_type != ROW_READ_TRY_SEMI_CONSISTENT)


? ? ? ? ? ? || unique_search


|| index != clust_index)


goto lock_wait_or_error;


// 可以进行semi-consistent read,根据记录的当前版本,构造最新的commit版本


? ? ? ? // 若没有commit版本,当前版本为最新版本,则直接读取下一条记录


? ? ? ? // 若存在commit版本,则设置did_semi_consistent_read为TRUE


row_sel_build_committed_vers_for_mysql();


if (old_vers == NULL)


goto next_rec;


did_semi_consistent_read = TRUE;



// 若本次update scan,由于加锁等待,使用了semi-consistent,则设置相应的参数


? ? ? ? // 该参数,在下一小节提到的MySQL针对semi-consistent优化中有用


if (did_semi_consistent_read)


prebuilt->row_read_type = ROW_READ_DID_SEMI_CONSISTENT;


else


prebuilt->row_read_type = ROW_RE

首页 上一页 1 2 下一页 尾页 1/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇MySQL 中隔离级别 RC 与 RR 的区别 下一篇MySQL半一致性读导致语句级Binlog..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目