2012年4月4日星期三

对innodb MVCC实现的一点点思考

不得不说MVCC思想对关系数据库的影响很大,读不阻塞写,写也不会阻塞读,大大提高了并发性。当前主流的数据库基本上都实现了MVCC,比如Oracle、MySQL、PostgreSQL等等。现在来谈谈MySQL(innodb)是怎么实现MVCC的,它的优缺点是什么。

innodb对MVCC的实现是通过在每个事物开启时创建一个当前系统活跃事务的副本(read_view),然后每次读取行的时候,通过这个行上的trx_id与read_view里面的trx_id进行比较。说到行上的trx_id,那么首先得说明一下innodb在每行上有三个隐藏字段:DB_ROW_ID、DB_TX_ID(这个就是行上的事务id)、DB_ROLL_PTR(指向当前行的回滚段指针)。具体的源码如下:

/*********************************************************************//**
Checks if a read view sees the specified transaction.
@return TRUE if sees */
UNIV_INLINE
ibool
read_view_sees_trx_id(
/*==================*/
const read_view_t* view, /*!< in: read view */
trx_id_t trx_id) /*!< in: trx id */
{
ulint n_ids;
ulint i;


if (trx_id < view->up_limit_id) {


return(TRUE);
}


if (trx_id >= view->low_limit_id) {


return(FALSE);
}


/* We go through the trx ids in the array smallest first: this order
may save CPU time, because if there was a very long running
transaction in the trx id array, its trx id is looked at first, and
the first two comparisons may well decide the visibility of trx_id. */


n_ids = view->n_trx_ids;


for (i = 0; i < n_ids; i++) {
trx_id_t view_trx_id
= read_view_get_nth_trx_id(view, n_ids - i - 1);


if (trx_id <= view_trx_id) {
return(trx_id != view_trx_id);
}
}


return(TRUE);
}

在我参考的一片文章[1]里面,作者说每次与行上的trx_id比较的时候
并不是根据当前事务的tx id,而是根据read view最早一个事务的tx id(read view->up_limit_id)来做比较的,我觉得作者只说对了一部分,这个read_view->up_limit_id确实是一个参考的参数(up_limit_id是当前事务的read_view里面trx_id最小的,这就好比我们求素数的时候,首先直接将n%2==0的剔除,这里的与read_view->up_limit_id比较也是一样的效果,实际上再源码里面也有说明),而在for循环里面我们可以看到,从read_view里面找到一个view_trx_id >= trx_id(行当前的事务id),至于为什么trx_id!=view_trx_id,这是因为两者相等的话,那就是同一个事务id,与自己比较没有意义。那么最后return(TRUE)呢?这是因为如果事务开启的时候没有活动的事务,那么read_view也就为空(本质上是view_n_trx_ids=0)这种情况自然事务可以读当前行。

那么innodb这样设计有什么缺点吗?依据我自己的见解,这样中设计比较浪费内存,因为如果在极端的情况下,有些事务耗时比较长,系统事务比较多的情况下,那么每一个新的事务开启的时候,都会导致read_view(当前活动事务副本)需要被创建一份,而且创建read_view的开销肯定也不小。Oracle的设计就不同,貌似它是在每个block(或者行)上有一个事务槽,所以每次去判断是直接读当前行还是读undo段时就利用当前事务的id与槽里面的事务id进行比较,这样应该来得比较innodb这种设计高效吧。




参考文章:


没有评论:

发表评论