Jak*_*raw 9 mysql database performance innodb locking
我遇到了一个innodb锁定问题,用于表上具有主键和单独唯一索引的事务.似乎TX使用唯一键删除记录,然后重新插入相同的记录,这将导致下一键锁定而不是预期的记录锁定(因为该键是唯一的).请参阅下面的测试用例以及我希望锁定哪些记录的细分:
DROP TABLE IF EXISTS foo;
CREATE TABLE `foo` (
`i` INT(11) NOT NULL,
`j` INT(11) DEFAULT NULL,
PRIMARY KEY (`i`),
UNIQUE KEY `jk` (`j`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 ;
INSERT INTO foo VALUES (5,5), (8,8), (11,11);
Run Code Online (Sandbox Code Playgroud)
(注意:只需在TX1 sql之后运行TX2 sql,在单独的连接中)
START TRANSACTION;
DELETE FROM foo WHERE i=8;
Run Code Online (Sandbox Code Playgroud)
导致i = 8的独占锁定(没有间隙锁定,因为我是主键并且是唯一的)
INSERT INTO foo VALUES(8,8);
Run Code Online (Sandbox Code Playgroud)
导致i = 8&j = 8的独占锁定,i = 6&i = 7的共享意图锁定,以及j = 6&j = 7
START TRANSACTION;
INSERT INTO foo VALUES(7,7);
Run Code Online (Sandbox Code Playgroud)
导致i = 7&j = 7的排他锁定,以及i = 6&j = 6的共享意图锁定
我希望TX2不被TX1阻止,但它确实如此.奇怪的是,阻塞似乎与TX1的插入有关.我这样说是因为如果在删除后没有运行TX1的insert语句,TX2的插入不会被阻止.这几乎就像TX1重新插入(8,8)导致索引j上的下一键锁定(6,8).
任何见解都会非常感激.
您遇到的问题是因为MySQL不仅仅锁定要插入的值的表行,它会id按顺序锁定上一个和下一个id 之间的所有可能值,因此,重复使用下面的示例:
DROP TABLE IF EXISTS foo;
CREATE TABLE `foo` (
`i` INT(11) NOT NULL,
`j` INT(11) DEFAULT NULL,
PRIMARY KEY (`i`),
UNIQUE KEY `jk` (`j`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 ;
INSERT INTO foo VALUES (5,5), (8,8), (11,11);
Run Code Online (Sandbox Code Playgroud)
假设您从事务TX1开始:
START TRANSACTION;
REPLACE INTO foo VALUES(8,8);
Run Code Online (Sandbox Code Playgroud)
然后,如果您开始交易TX2,将锁定5或11之间的任何INSERT或REPLACE使用id:
START TRANSACTION;
REPLACE INTO foo VALUES(11,11);
Run Code Online (Sandbox Code Playgroud)
看起来MySQL使用这种锁定来避免这里描述的"幻象问题":http://dev.mysql.com/doc/refman/5.0/en/innodb-next-key-locking.html,MySQL使用" next-key locking",它将索引行锁定与间隙锁定结合起来,这对我们来说意味着它将锁定前一个和下一个id之间的许多可能的id,并且还会锁定prev和next id.
为了避免这种情况,请尝试创建一个插入记录的服务器算法,以便插入不同事务的记录不会重叠,或者至少不会同时执行所有事务,因此TX不必彼此等待.