Percona XtraDB在插入时具有独特的PK死锁

时间:2014-04-07 16:18:17

标签: deadlock percona xtradb

我有一个由3个percona db服务器组成的集群,这个表:

CREATE TABLE `metric` (
  `metricid` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `host` varchar(50) NOT NULL,
  `userid` int(10) unsigned DEFAULT NULL,
  `name` varchar(255) NOT NULL,
  `sampleid` tinyint(3) unsigned NOT NULL,
  PRIMARY KEY (`metricid`),
  UNIQUE KEY `unique-metric` (`userid`,`host`,`name`,`sampleid`)
) ENGINE=InnoDB AUTO_INCREMENT=1000000000000 DEFAULT CHARSET=utf8

每个服务器(ID 1,2,3)每秒运行一次此查询:

insert into metric set metricid = $serverId$now, host = $now, name = $serverId

(例如insert into metric set metricid = 31396887217, host = 1396887217, name = 3

而且速度很快我遇到了“第1行的ERROR 1213(40001):尝试获取锁定时发现死锁;尝试重新启动事务” - 假设我提供了不重叠的ID,因为每个服务器都会生成一个id使用不同的前缀,为什么会发生死锁?

1 个答案:

答案 0 :(得分:1)

发生冲突是因为INSERT实际上锁定了它插入的“间隙”。在插入到表的末尾的情况下,它实际上锁定了所有现有行之后的间隙(理论上延伸到无限远。

由于你有第二个UNIQUE KEY约束,情况变得复杂,因此当你运行两个并发会话时,InnoDB需要创建两个间隙锁,一个在PRIMARY KEY上,一个在UNIQUE KEY上。因此,可能存在竞争条件,其中两个会话可能以他们最终彼此等待的方式获得他们的锁。

我想知道为什么你有一个AUTO_INCREMENT主键,但是你要覆盖自动增量功能。使用自动增量可能有所帮助,因为自动增量通过非常简短的表锁解决,因此您可以避免死锁,因为您只有一个间隙锁。不过,我还没有测试过这个想法。

另见: