Mysql锁等待超时错误

时间:2017-07-20 16:55:34

标签: mysql locking

我的应用程序中有一个场景,其中事务下的简单INSERT语句阻止了MySQL中不同行的DELETE语句,最终,DELETE语句会话超时,锁定超时错误。

我试图在下面的简单场景中解释这种情况。注意,在列上添加索引有点帮助,但是如果我在DELETE的WHERE子句中有2列,我仍然会看到锁等待超时。另请注意,在我开始事务之后,我需要做一些其他处理,因此事务需要几分钟才能提交或回滚。很难相信即使我删除了不同于我想要插入的记录,MySQL也会阻止它。

第1节: -

mysql> SELECT @@GLOBAL.tx_isolation, @@tx_isolation, @@session.tx_isolation;

 +-----------------------+----------------+------------------------+
 | @@GLOBAL.tx_isolation | @@tx_isolation | @@session.tx_isolation |
 +-----------------------+----------------+------------------------+
 | READ-COMMITTED        | READ-COMMITTED | READ-COMMITTED         |
 +-----------------------+----------------+------------------------+ 

1 row in set (0.02 sec)` 

mysql> create table testtab(col1 int, col2 int);
Query OK, 0 rows affected (0.53 sec) 
mysql> START TRANSACTION; 
Query OK, 0 rows affected (0.00 sec) 
mysql> INSERT INTO testtab values(1,1); 
Query OK, 1 row affected (0.00 sec) 
mysql> INSERT INTO testtab values(2,2); 
Query OK, 1 row affected (0.00 sec) 

第二节: -

mysql> SELECT @@GLOBAL.tx_isolation, @@tx_isolation, @@session.tx_isolation; 
+-----------------------+----------------+------------------------+ 
| @@GLOBAL.tx_isolation | @@tx_isolation | @@session.tx_isolation | 
+-----------------------+----------------+------------------------+ 
| READ-COMMITTED        | READ-COMMITTED | READ-COMMITTED         | 
+-----------------------+----------------+------------------------+
 1 row in set (0.00 sec) 
mysql> DELETE FROM testtab where col1=3;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction  

有什么建议吗?

1 个答案:

答案 0 :(得分:0)

这是InnoDB锁定工作的结果。引用manual

  

锁定读取,UPDATE或DELETE通常会在处理SQL语句时扫描的每个索引记录上设置记录锁定。在语句中是否存在排除该行的WHERE条件并不重要。 InnoDB不记得确切的WHERE条件,但只知道扫描了哪些索引范围。

还值得注意的是

  

如果没有适合您的语句的索引,并且MySQL必须扫描整个表来处理该语句,则表的每一行都会被锁定,这反过来会阻止其他用户对表的所有插入。创建好的索引非常重要,这样您的查询就不会不必要地扫描很多行。

那么在你的情况下会发生的是两个insert向表中添加两个锁定的行。由于没有合适的索引,delete现在将扫描整个表。它必须锁定它遇到的每一行,但要做到这一点,它必须等待insert创建的锁已被解除(这不会及时发生)。

col1上添加索引将解决此问题,因为delete只需考虑(并锁定)可以使用索引找到的col1 = 3行,因此它将与其他事务插入的行没有重叠。

如果您在查找"双列 - where-condition"的良好索引时遇到问题,您应该添加更多有关它的详细信息,可能有适合该情况的索引。

这当然不会阻止所有情况(例如,如果你真的想要修改同一行),所以通常最好保持你的交易尽可能短,准备等待那么久和/或准备好在必要时重复交易。

这不是InnoDB锁的完整描述,只是解释你情况的部分。