为"卡住的"Mysql表修复"超出锁定等待超时;尝试重新启动事务"?

Tom*_*Tom 116 mysql transactions

从脚本我发送了数千次这样的查询到我的本地数据库:

update some_table set some_column = some_value
Run Code Online (Sandbox Code Playgroud)

我忘了添加where部分,因此同一列被设置为表中所有行的相同值,这已经完成了数千次并且列已被索引,因此相应的索引可能更新了很多次.

我注意到有些事情是错的,因为它花了太长时间,所以我杀了剧本.从那时起我甚至重新启动了我的计算机,但是表格中存在一些问题,因为简单查询需要很长时间才能运行,当我尝试删除相关索引时,它会失败并显示以下消息:

Lock wait timeout exceeded; try restarting transaction
Run Code Online (Sandbox Code Playgroud)

这是一个innodb表,因此卡住交易可能是隐含的.如何修复此表并从中删除卡住的事务?

Mih*_*iță 134

我有一个类似的问题,并通过检查正在运行的线程解决它.要查看正在运行的线程,请在mysql命令行界面中使用以下命令:

SHOW PROCESSLIST;
Run Code Online (Sandbox Code Playgroud)

如果您无法访问mysql命令行界面,也可以从phpMyAdmin发送它.
这将显示具有相应ID和执行时间的线程列表,因此您可以杀死执行时间过长的线程.在phpMyAdmin中,您将有一个使用KILL来停止线程的按钮,如果您使用命令行界面,只需使用KILL命令后跟线程ID,如下例所示:

KILL 115;
Run Code Online (Sandbox Code Playgroud)

这将终止相应线程的连接.

  • 做记录!关于这个问题的许多SO线程中的某个人都提到了这一点:有时锁定表的进程显示为在进程列表中休眠!我正在撕扯我的头发,直到我杀死了有问题的数据库中打开的所有线程,无论是睡觉还是不睡觉.最终解锁了表并让更新查询运行.评论者提到了类似"有时一个MySQL线程锁定一个表,然后在等待与MySQL无关的事情发生时休眠的事情." (32认同)
  • 这不是一个解决方案,不仅仅是感染伤口的导管绑带是一种解决方案.你没有解决潜在的根本问题. (2认同)

小智 46

您可以使用检查当前正在运行的事务

SELECT * FROM `information_schema`.`innodb_trx` ORDER BY `trx_started`
Run Code Online (Sandbox Code Playgroud)

您的交易应该是第一个,因为它是列表中最早的.现在只需从中获取值trx_mysql_thread_id并将KILL命令发送给它:

KILL 1234;
Run Code Online (Sandbox Code Playgroud)

如果您不确定哪个交易是您的,请经常重复第一个查询并查看哪些交易仍然存在.


小智 34

当我的数据库大小增加并且我在它上面做了很多事务时,这开始发生在我身上.

事实上,可能有一些方法可以优化您的查询或数据库,但尝试这两个查询来解决修复问题.

运行这个:

SET GLOBAL innodb_lock_wait_timeout = 5000; 
Run Code Online (Sandbox Code Playgroud)

然后这个:

SET innodb_lock_wait_timeout = 5000; 
Run Code Online (Sandbox Code Playgroud)

  • 参考链接:[innodb_lock_wait_timeout](https://dev.mysql.com/doc/refman/5.5/en/innodb-parameters.html#sysvar_innodb_lock_wait_timeout) (2认同)

mar*_*kas 33

检查InnoDB状态是否有锁

SHOW ENGINE InnoDB STATUS;
Run Code Online (Sandbox Code Playgroud)

检查MySQL打开表

SHOW OPEN TABLES WHERE In_use > 0;
Run Code Online (Sandbox Code Playgroud)

检查待处理的InnoDB事务

SELECT * FROM `information_schema`.`innodb_trx` ORDER BY `trx_started`; 
Run Code Online (Sandbox Code Playgroud)

检查锁依赖性 - 什么阻止什么

SELECT * FROM `information_schema`.`innodb_locks`;
Run Code Online (Sandbox Code Playgroud)

在调查上面的结果后,您应该能够看到什么是锁定什么.

问题的根本原因可能也在于您的代码 - 如果您使用像Hibernate这样的JPA,请检查相关函数,尤其是注释.

例如,如所描述这里,下面标注的滥用可能会导致数据库锁:

@Transactional(propagation = Propagation.REQUIRES_NEW) 
Run Code Online (Sandbox Code Playgroud)

  • 非常感谢!运行`SELECT*FROM information_schema.innodb_trx t JOIN information_schema.processlist p ON t.trx_mysql_thread_id = p.id`揭示了罪魁祸首:锁定线程来自我的IP地址...我忘了关闭我有的调试控制台离开了交易中... (3认同)

Ben*_*enj 7

重启MySQL,它运行正常.

请注意,如果这样的查询被卡住,则存在某个问题:

  • 在您的查询中(错位的char,笛卡尔积,...)
  • 要编辑的记录非常多
  • 复杂的连接或测试(MD5,子串LIKE %...%等)
  • 数据结构问题
  • 外键模型(链/循环锁定)
  • 错误索引的数据

正如@syedrakib所说,它有效,但这不是生产的长期解决方案.

注意:重新启动可能会影响状态不一致的数据.

此外,您可以检查MySQL如何使用EXPLAIN关键字处理您的查询,并查看是否有可能加速查询(索引,复杂测试......).


use*_*324 6

为事务建立连接时,在执行事务之前需要先获得一个锁。如果无法获取锁,则尝试一段时间。如果仍然无法获得锁定,则抛出超出锁定等待时间的错误。为什么无法获取锁的原因是您没有关闭连接。因此,当您第二次尝试获取锁时,由于以前的连接仍未关闭并持有该锁,因此您将无法获得该锁。

解决方案: 关闭连接或setAutoCommit(true)(根据您的设计)释放锁。


Tom*_*Tom -216

我通过删除表并从备份中恢复它解决了这个问题。

  • 我得出的结论是,当他等待答案时,卡住的事务在后台完成,所以当他得到答案时,其他任何事情都不起作用。 (13认同)