An example about consistent read and next-key lock in InnoDB

本文深入探讨了InnoDB数据库中的一致性读和Next-Key锁的概念,通过实例展示了如何避免Phantom Read陷阱,并揭示了一个隐藏的bug。文章详细解释了在默认重复可读隔离级别下,一致性视图的生成过程,以及如何通过正确的使用`START TRANSACTION WITH CONSISTENT SNAPSHOT`避免Phantom Read现象。同时,通过Next-Key锁的概念,阐述了插入操作被锁定的原因及其与`FOR UPDATE`查询的区别,最终通过实验验证了这一理论。文章还讨论了InnoDB记录级锁定的实现方式,以及如何通过合理的SQL查询策略来优化并发性能。

  This article begins with a misunderstanding to discuss consistent read and next-key lock, and end up with a bug in MySQL optimizer. All bellow are based on the default isolation level, repeatable read, and innodb_locks_unsafe_for_binlog is off.

 

1、   Misunderstanding

        

1-1

         Look into session1, the transaction starts at the query “select … for update”, so the TRX_ID of session2’s transaction is larger than that of session1’s. But it looks “strange” that after the session2’s transaction committed, the query “select * from tb” can return the new row (200,200).

 

2、   Explanation

         Is it Phantom Read? As I understood before, the consistent view of session1’s transaction is generated at the first select query.

In fact, as described in manual page, there are statements as followed:

"All consistent reads within the same transaction read the snapshot established by the first such read in that transaction"

"Suppose that you are running in the default REPEATABLE READ isolation level. When you issue a consistent read (that is, an ordinary SELECT statement), InnoDB gives your transaction a time point according to which your query sees the database. "

The “ordinary SELECT statement” is pointed specially, it means that the “select … for update” statement will not generate consistent view, which is in fact generated in the “select * from b”. So it is normal that we can see the (200,200) here.

 

3、   Verification

As verification, we can insert another (201, 201) in session2 now, and the next “select * from tb” will not return (201,201).

Another clue comes from the command “show engine InnoDB status”.

 

insert into tb values(10,10),(11,11),(13,13),(20,20);

begin;

select * from tb force index a where a>15 and a<18 for update;

show engine InnoDB status \G

 

------------

TRANSACTIONS

------------

Trx id counter 1E82110B

Purge done for trx's n:o < 1E821107 undo n:o < 0

History list length 8

LIST OF TRANSACTIONS FOR EACH SESSION:

---TRANSACTION 1E82110A, ACTIVE 2 sec, process no 5438, OS thread id 1311758656

3 lock struct(s), heap size 376, 2 row lock(s)

MySQL thread id 16, query id 757 localhost root

show engine InnoDB status

select * from tb;

show engine InnoDB status \G

 

------------

TRANSACTIONS

------------

Trx id counter 1E82110B

Purge done for trx's n:o < 1E821107 undo n:o < 0

History list length 8

LIST OF TRANSACTIONS FOR EACH SESSION:

---TRANSACTION 1E82110A, ACTIVE 29 sec, process no 5438, OS thread id 1311758656

3 lock struct(s), heap size 376, 2 row lock(s)

MySQL thread id 16, query id 759 localhost root

show engine InnoDB status

Trx read view will not see trx with id >= 1E82110B, sees < 1E82110B

 

Till the second execution of “show engine InnoDB status”, there is “Trx read view” generated. The consistent view id is not 1E82110A but 1E82110B.

A “for update” statement is not “ordinary select query”, so no consistent view is generated, the same results when run “select … lock in share mod” and update statements.

If I want to create the consistent view at the beginning of the transaction, “START TRANSACTION WITH CONSISTENT SNAPSHOT” can be issued.

 

4、   Next-Key Lock

a)         Locked When Insertion

       If we want to offer a simpler case to tell about this, perhaps we can prefer to drop the column b, and make the table as “create table tb (a int key) engine=InnoDB” here. Then you will find that inserting (200) is locked in session2.

        

 

4-1

What happens and why?

 

b)        Next-Key Lock

We must mention a concept that named next-key lock in InnoDB. Look into the next case first.

 

4-2

The insertion is locked here, what is the difference between this and the prior example? In the “for update” query, the “Gap” is locked. The definitions of the gaps are as follow:

(Negative infinity, 10]

(10, 11]

(11, 13]

(13, 20]

(20, positive infinity)

So the whole gap (13, 20] is locked by session1, it prevent session2 from inserting (19, 19) here. Certainly the (200,200) will not be locked here, because it is located in another gap.

 

c)         Rows that Locked

 

Then come back to the question that why the (200) can’t be inserted when there is only one column in the table.

We can look into the “show engine InnoDB status\G” again.

CREATE TABLE `tb` (

  `a` int(11) NOT NULL DEFAULT '0',

  PRIMARY KEY (`a`)

) ENGINE=InnoDB DEFAULT CHARSET=gbk;

Insert into tb values(10),(11),(13),(20);

begin;

select * from tb where a>15 and a<18 for update;

show engine InnoDB status\G

 

------------

TRANSACTIONS

------------

Trx id counter 1E82112A

Purge done for trx's n:o < 1E821121 undo n:o < 0

History list length 17

LIST OF TRANSACTIONS FOR EACH SESSION:

---TRANSACTION 1E821129, ACTIVE 4 sec, process no 5438, OS thread id 1312815424

2 lock struct(s), heap size 376, 5 row lock(s)

 

That seems to be strange that there are “5 row locks”. In fact the optimizer decides it to be a full table scan, because the row number is so small.

As proof we can see Innodb_rows_read increases 4 here. The implicit “supremum” makes the row lock to 5.

So it can say that all the gaps are locked by the “select … for update” query, so any insertion will be prevent here.

We can insert (300),(301),(302)….(10000) into the table, can run the steps again, now the (200) can be inserted in session2.

So it seems that we reach a bug from a “fake bug” :)

 

5、   Reference

http://dev.mysql.com/doc/refman/5.5/en/innodb-consistent-read.html

       http://dev.mysql.com/doc/refman/5.5/en/innodb-record-level-locks.html

基于数据驱动的 Koopman 算子的递归神经网络模型线性化,用于纳米定位系统的预测控制研究(Matlab代码实现)内容概要:本文围绕“基于数据驱动的Koopman算子的递归神经网络模型线性化”展开,旨在研究纳米定位系统的预测控制问题,并提供完整的Matlab代码实现。文章结合数据驱动方法与Koopman算子理论,利用递归神经网络(RNN)对非线性系统进行建模与线性化处理,从而提升纳米级定位系统的精度与动态响应性能。该方法通过提取系统隐含动态特征,构建近似线性模型,便于后续模型预测控制(MPC)的设计与优化,适用于高精度自动化控制场景。文中还展示了相关实验验证与仿真结果,证明了该方法的有效性和先进性。; 适合人群:具备一定控制理论基础和Matlab编程能力,从事精密控制、智能制造、自动化或相关领域研究的研究生、科研人员及工程技术人员。; 使用场景及目标:①应用于纳米级精密定位系统(如原子力显微镜、半导体制造设备)中的高性能控制设计;②为非线性系统建模与线性化提供一种结合深度学习与现代控制理论的新思路;③帮助读者掌握Koopman算子、RNN建模与模型预测控制的综合应用。; 阅读建议:建议读者结合提供的Matlab代码逐段理解算法实现流程,重点关注数据预处理、RNN结构设计、Koopman观测矩阵构建及MPC控制器集成等关键环节,并可通过更换实际系统数据进行迁移验证,深化对方法泛化能力的理解。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值