[英]INSERT … SELECT, InnoDB and locking
我在MySQL 5.5.34(在Ubuntu 12.04上)下使用InnoDB引擎遇到以下行为。
在执行INSERT ... SELECT
语句时,某些意外行似乎被锁定在正在读取的表中。
让我举个例子吧。 假设两个表table_source
和table_dest
具有以下结构(特别注意索引):
CREATE TABLE table_source (
id int(11) unsigned NOT NULL AUTO_INCREMENT,
group_id int(11) NOT NULL,
data text NOT NULL,
created timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id),
KEY group_id_created (group_id,created)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8;
CREATE TABLE table_dest (
id int(11) unsigned NOT NULL AUTO_INCREMENT,
group_id int(11) NOT NULL,
data text NOT NULL,
created timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id),
KEY group_id_created (group_id,created)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8;
假设我现在执行以下事务:
BEGIN;
INSERT INTO table_dest
SELECT * FROM table_source WHERE group_id = 3 AND created < '2014-01-04';
....
然后,源表似乎被锁定为具有group_id
2的INSERT
:
INSERT INTO table_source (group_id, data, created)
VALUES (2, 'data', NOW()); --< This locks
以下是一些其他语句,以及它们是否锁定:
INSERT INTO table_source (group_id, data, created)
VALUES (3, 'data', NOW()); --< Does not lock
INSERT INTO table_source (group_id, data, created)
VALUES (1, 'data', NOW()); --< Does not lock
INSERT INTO table_source (group_id, data, created)
VALUES (3, 'data', '2014-01-01'); --< Does lock
有人可以解释一下为什么会发生这种情况吗(我想这与间隙锁有关)? 有没有办法避免这种情况(我仍然想保持REPEATABLE READ
隔离级别)?
没错 读取表中的行被共享锁锁定( SELECT
隐式为LOCK IN SHARE MODE
)。 没有办法避免这种情况。 这就是您要系统询问的内容:复制所有符合条件的行。 确保实际上所有与条件匹配的行以及该列表在执行该语句期间或之后不更改的唯一方法是锁定行。
为了澄清为什么您无法使用group_id = 2
进行INSERT
:
这与您的查询专门在WHERE group_id = 3 AND created < '2014-01-04'
在KEY group_id_created (group_id, created)
上WHERE group_id = 3 AND created < '2014-01-04'
有关。 为了搜索所有与group_id = 3 AND created < '2014-01-04'
相匹配的行, group_id = 3 AND created < '2014-01-04'
第一行开始搜索索引,该行超过该条件的上限为(3, '2014-01-14')
,直到找到与条件不匹配的行,直到created
的行没有下界为止,这将是第一行,其中group_id < 3
,当然是group_id = 2
。
这意味着group_id = 2
遇到的第一行也被锁定,这将是具有最大created
值的行。 这将不可能在(2, MAX(created))
和(3, MIN(created))
之间INSERT
“间隙” (2, MAX(created))
当然不是正确的SQL,只是伪SQL),尽管这不是“间隙”锁定”。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.