繁体   English   中英

INSERT…SELECT,InnoDB和锁定

[英]INSERT … SELECT, InnoDB and locking

我在MySQL 5.5.34(在Ubuntu 12.04上)下使用InnoDB引擎遇到以下行为。

在执行INSERT ... SELECT语句时,某些意外行似乎被锁定在正在读取的表中。

让我举个例子吧。 假设两个表table_sourcetable_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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM