我有一个由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使用不同的前缀,为什么会发生死锁?
答案 0 :(得分:1)
发生冲突是因为INSERT实际上锁定了它插入的“间隙”。在插入到表的末尾的情况下,它实际上锁定了所有现有行之后的间隙(理论上延伸到无限远。
由于你有第二个UNIQUE KEY约束,情况变得复杂,因此当你运行两个并发会话时,InnoDB需要创建两个间隙锁,一个在PRIMARY KEY上,一个在UNIQUE KEY上。因此,可能存在竞争条件,其中两个会话可能以他们最终彼此等待的方式获得他们的锁。
我想知道为什么你有一个AUTO_INCREMENT主键,但是你要覆盖自动增量功能。使用自动增量可能有所帮助,因为自动增量通过非常简短的表锁解决,因此您可以避免死锁,因为您只有一个间隙锁。不过,我还没有测试过这个想法。
另见: