consitent read原理及实现分析(2)

上面提到的是semi-consistent read的功能实现,除此之外,MySQL针对semi-consistent read,还做了优化措施:对于update scan返回的不满足条件的记录,提前放锁。

MySQL Server层流程

sql_update.cc::mysql_update()

// 判断当前scan返回的记录,是否满足update的where条件

    // 若满足,则进行update操作

if (!(select && select->skip_record())

// 若不满足update的where条件,则选择将当前记录上的行锁提前释放

else

table->file->unlock_row();

InnoDB Engine层流程

ha_innobd.cc::unlock_row();

switch (prebuilt->row_read_type)

// 若系统未设置参数innodb_locks_unsafe_for_binlog,同时隔离级别大于

    // TRX_ISO_READ_COMMITTED,则不可提前释放不满足条件的行锁

    // 否则可以提前释放不满足条件的行锁

case ROW_READ_WITH_LOCKS:

if (!srv_locks_unsafe_for_binlog &&

prebuilt->trx->isolation_level > TRX_ISO_READ_COMMITTED)

break;

// 若当前系统已采用SEMI_CONSISTENT read,但是没有锁等待,加锁直接成功

    // 那么此时直接释放不满足条件的行锁

case ROW_READ_TRY_SEMI_CONSISTENT:

row_unlock_for_mysql();

// 若当前系统已采用SEMI_CONSISTENT read,并且有锁等待,构造了commit版本

    // 没有在commit版本上加锁,因此也无锁可放,直接返回即可

case ROW_READ_DID_SEMI_CONSISTENT:

prebuilt->row_read_type = ROW_READ_TRY_SEMI_CONSISTENT;

break;

semi-consistent优缺点分析 优点

减少了更新同一行记录时的冲突,减少锁等待。

无并发冲突,读记录最新版本并加锁;有并发冲突,读事务最新的commit版本,不加锁,无需锁等待。

可以提前放锁,进一步减少并发冲突概率。

对于不满足update更新条件的记录,可以提前放锁,减少并发冲突的概率。

在理解了semi-consistent read原理及实现方案的基础上,可以酌情考虑使用semi-consistent read,提高系统的并发性能。

缺点

非冲突串行化策略,因此对于binlog来说,是不安全的

两条语句,根据执行顺序与提交顺序的不同,通过binlog复制到备库后的结果也会不同。不是完全的冲突串行化结果。

因此只能在事务的隔离级别为read committed(或以下),或者设置了innodb_locks_unsafe_for_binlog参数的情况下才能够使用。

测试用例 构造semi-consistent read

set binlog_format=mixed;

set session transaction isolation level repeatable read;

create table t1(a int not null) engine=innodb DEFAULT CHARSET=latin1;

insert into t1 values (1),(2),(3),(4),(5),(6),(7);

session 1:                                                session 2:

set autocommit=0;

update t1 set a = a + 10;

set binlog_format=mixed;

set session transaction isolation level read committed;

update t1 set a = a + 100 where a > 10;

此时,session 2不需要等待session 1,虽然session 1的更新后项满足session 2的条件,但是由于session 2进行了semi-consistent read,读取到的记录的前项为(1-7),不满足session 2的更新where条件,因此session 2直接返回。

session 2直接返回,0 rows affected。

构造unlock unmatched row

set binlog_format=mixed;

set session transaction isolation level repeatable read;

create table t1(a int not null) engine=innodb DEFAULT CHARSET=latin1;

insert into t1 values (1),(2),(3),(4),(5),(6),(7);

session 1:                                                session 2:

set autocommit=0;

update t1 set a = a + 10;

commit;

set binlog_format=mixed;

set session transaction isolation level repeatable read;

set autocommit = 0;

update t1 set a = a + 100 where a < 10;

select * from t1 lock in share mode;

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/42b1c21a375518af0a3264085300946e.html