InnoDB死锁是INSERT / UPDATE / DELETE专有的吗?


8

我正在解决MySQL错误“尝试获取锁时发现死锁;尝试重新启动事务”

我将不得不更新程序以允许死锁。该SELECT语句是否可能产生死锁错误?我知道这只是一个读锁,因此多个选择不会有问题,但是如果存在INSERTUPDATEDELETE语句(对于联接可能有子查询)SELECT语句(对于联接或子查询可能)怎么办?

有没有可能是错误将在被抛出SELECT,而不是INSERTUPDATEDELETE

如果您好奇的话,这里就是故事。


+1是一个很好的问题,因为它揭示了一个大多数人都不知道的InnoDB怪癖,与针对InnoDB表的SELECT结合使用。
RolandoMySQLDBA 2011年

Answers:


5

您问题标题的直接答案是“否”。

SELECT查询可以对gen_clust_index(也称为聚簇索引)执行锁定。

这是我与@RedBlueThing一起积极询问的三个DBA Stack Exchange 问题。@RedBlueThing找到了解决他的问题的方法。

只是为了使您的问题更直观,当您仔细查看这些答案时(不要看上去太深,即使我自己眼花con乱的答案也令人头晕),应该很快就会发现SELECT查询可以锁定数据。

您还有SELECT的特殊情况,您可以根据需要锁定特定的行

更新2011-08-08 16:49 EDT

您问了一个变体问题:“在选择条件下,InnoDB死锁异常是否可能被SELECT抛出”,答案可能是“是”。那是什么情况?如果由于错误而仅回滚单个SQL语句,则可以保留该语句设置的某些锁。发生这种情况是因为InnoDB以某种格式存储行锁,使得以后无法知道哪个语句设置了哪个锁

根据该陈述,导致这种情况的事件顺序理论上可以如下:

  • 您的SQL更新仅一行,但会产生错误
  • UPDATE导致回滚一行
  • 该行有一个挥之不去的锁

就个人而言,最后的陈述使我感到恐惧。对于MySQL来说,将这个怪癖告知每个人本来很好。但是,该声明来自MySQL文档。(哦,是的,Oracle拥有InnoDB)

更新2015-09-22 18:40 EST

今年早些时候,我了解到Percona有一个不错的Nagios支票,可以发现这些讨厌的锁藏在睡眠连接的后面。您现在要做的就是从该链接运行代码:

SELECT COALESCE(MAX(IF(p.command = 'Sleep', p.time, 0)), 0) AS idle_in_trx
FROM INFORMATION_SCHEMA.INNODB_LOCK_WAITS AS w
INNER JOIN INFORMATION_SCHEMA.INNODB_TRX        AS b ON  b.trx_id = w.blocking_trx_id
INNER JOIN INFORMATION_SCHEMA.INNODB_TRX        AS r ON  r.trx_id = w.requesting_trx_id
LEFT JOIN  INFORMATION_SCHEMA.PROCESSLIST       AS p ON  p.id     = b.trx_mysql_thread_id;

这仅适用于MySQL 5.5+。如果您使用的是MySQL 5.1或更低版本,则必须终止所有睡眠连接以释放锁。


@Rolando-InnoDB的MVCC读取永不阻塞(不是for update,当然使用时除外),这不是真的吗?
杰克说,请在2011年

@Jack-如果您阅读了前3个要点中的链接,将会看到MVCC ia没问题。这是聚集索引中的一个严重僵局,甚至MVCC也无法缓解。
RolandoMySQLDBA 2011年

@Rolando-我已经更仔细地阅读了链接,但仍然看不到任何迹象表明正常状态select可以锁定行或以任何方式被DML在另一笔交易中阻止。就Oracle而言,这当然是正确的,据我所知,对于InnoDB也是如此。当然,该select语句实际上是通过函数或其他某种绕行路线进行DML 的情况除外。
杰克说尝试topanswers.xyz 2011年

@Jack-如果SELECT可以阻塞索引,那么我的前3个链接显示的UPDATE还要多得多。
RolandoMySQLDBA 2011年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.