MySQL死锁错误 [英] MySQL Deadlock Error

查看:407
本文介绍了MySQL死锁错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的Web应用程序最多每秒运行以下查询1-2次,具体取决于用户流量:

UPDATE `click_rollups` 
   SET `clicks` = `clicks` + 1, `last_updated` = ? 
   WHERE `camp_id` = ? 
     AND `country` = ? 
     AND `clicks` < ? 
     AND `time_created` = ?

我们的日志显示有时会出现此错误:

SQLSTATE[40001]: Serialization failure: 1213 Deadlock found when trying to get lock; try restarting transaction
但是,click_rollups仅在该事务的写上下文中使用一次,因此我无法想象死锁会以何种方式发生。仅使用SELECTs在应用程序的其他位置查询一次。

因此,这是否意味着这两个独立事务(UPDATE和SELECT-ONLY)的死锁导致了问题,因为每个独立事务只使用该表一次(并且使用该表的查询不引用任何其他表)?或者是否存在行级锁定问题,这可能意味着其中一个事务可能会与同一事务的其他事件发生死锁?

InnoDB

进一步阅读后,我发现,由于推荐答案确实使用行级锁定,因此在仅插入或更新单行时可能会发生死锁,因为操作不是原子的。我跑了:

SHOW ENGINE INNODB STATUS

以查找有关上次死锁的信息。我发现:

------------------------
LATEST DETECTED DEADLOCK
------------------------
140106 17:22:41
*** (1) TRANSACTION:
TRANSACTION 63EB5222A, ACTIVE 0 sec starting index read
mysql tables in use 3, locked 3
LOCK WAIT 9 lock struct(s), heap size 3112, 6 row lock(s), undo log entries 2
MySQL thread id 4304350, OS thread handle 0x7fd3b74d3700, query id 173460207 192.168.0.2 sharecash Updating
UPDATE `click_rollups` SET `clicks` = `clicks` + 1, `last_updated` = '1389046961' WHERE `camp_id` = '27739' AND `country` = 'US' AND `clicks` < '1000' AND `time_created` = '1389046866'
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 186 page no 407 n bits 1272 index `country` of table `sharecash`.`click_rollups` trx id 63EB5222A lock_mode X waiting
*** (2) TRANSACTION:
TRANSACTION 63EB52225, ACTIVE 0 sec fetching rows
mysql tables in use 3, locked 3
177 lock struct(s), heap size 31160, 17786 row lock(s), undo log entries 2
MySQL thread id 4304349, OS thread handle 0x7fd6961c8700, query id 173460194 192.168.0.1 sharecash Updating
UPDATE `click_rollups` SET `clicks` = `clicks` + 1, `last_updated` = '1389046961' WHERE `camp_id` = '30949' AND `country` = 'US' AND `clicks` < '1000' AND `time_created` = '1388964767'
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 186 page no 407 n bits 1272 index `country` of table `sharecash`.`click_rollups` trx id 63EB52225 lock_mode X
*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 186 page no 512 n bits 384 index `PRIMARY` of table `sharecash`.`click_rollups` trx id 63EB52225 lock_mode X locks rec but not gap waiting
*** WE ROLL BACK TRANSACTION (1)

您可以看到,导致死锁的两个查询实际上是完全相同的。它显示WHERE子句中的列也有不同的参数,因此被锁定的实际行是不同的,这似乎有点违反我的直觉-对不同行集的操作如何会导致死锁?

答案似乎是死锁是由查询引擎锁定索引结构中的条目引起的。如果您查看上面的输出,您可以看到一个事务锁定了country索引中某个页面的特定部分,并且需要锁定主键索引的一部分,而另一个事务基本上是相反的情况。

在我们的应用程序的这一部分中有一个不变量,只有一行的点击次数会少于1000次,所以我相信通过解决这个问题,死锁问题将被最小化,因为总体上会减少锁定。MySQL文档建议对应用程序进行编码,以便在由于死锁而导致回滚的情况下始终重新发布事务,这将防止导致页面错误的问题。然而,如果任何人有任何关于如何实际避免这些死锁的其他想法,请再次在评论中发布它们!

编辑-

country索引不需要由事务使用,因为对于每个camp_id值,只有几个(通常只有1个)不同的country值,每个值只对应于一行。我已经向查询添加了一个索引提示,使其停止使用该索引,该问题现在已得到修复,而不会对性能造成任何影响(可能会有一些小的提高)。

这篇关于MySQL死锁错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆