【问题标题】:FOR UPDATE with IN clause causes LOCK WAIT TIMEOUT带有 IN 子句的 FOR UPDATE 导致 LOCK WAIT TIMEOUT
【发布时间】:2014-12-29 14:25:22
【问题描述】:

我在使用 SELECT ... FOR UPDATE 语句时遇到了 LOCK WAIT TIMEOUT 问题。

我准备了我不明白的场景。你能告诉我为什么前三个块立即执行,而最后一个等待吗?

谢谢。

-- I'm using MariaDb

-- T1 is the mysql terminal window 1
-- T2 is the mysql terminal window 2

CREATE TABLE `test` (
  `id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
  `name` VARCHAR(255) NOT NULL
) COMMENT='' ENGINE='InnoDB' COLLATE 'utf8_bin';

INSERT INTO test SET name='foo';

T2: START TRANSACTION;
T1: START TRANSACTION;
T1: SELECT * FROM test WHERE id IN (1) FOR UPDATE;
T2: INSERT INTO test SET name='foo'; -- executed immediately

T2: START TRANSACTION;
T1: START TRANSACTION;
T1: SELECT * FROM test WHERE id IN (1,2) FOR UPDATE;
T2: INSERT INTO test SET name='foo'; -- executed immediately

T2: START TRANSACTION;
T1: START TRANSACTION;
T1: SELECT * FROM test WHERE id IN (1,2,3) FOR UPDATE;
T2: INSERT INTO test SET name='foo'; -- executed immediately

T2: START TRANSACTION;
T1: START TRANSACTION;
T1: SELECT * FROM test WHERE id IN (1,2,3,4) FOR UPDATE;
T2: INSERT INTO test SET name='foo'; -- waits for T1 to commit

T2: commit;
T1: commit;

【问题讨论】:

  • 我不熟悉innodb的事务机制,但ransactions通常以“start transaction”开始,执行一堆SQL语句,然后“commit”。但是,您的代码不遵循这种简单的模式。为什么要“开始交易”两次?
  • 那么“T1”和“T2”是什么意思呢?会议??
  • 感谢您的回答,但开始事务应该会导致任何未决事务被隐式提交提交。所以我没有写任何提交来使示例尽可能简约。 T1是一个mysql终端窗口,T2是第二个终端窗口。忘记提了,会更新原来的问题,谢谢。
  • 我不确定“隐式提交”,但“select .. for update”也需要“启动事务”。
  • 您的代码的另一个奇怪之处是操作顺序。虽然你把select放在insert之前,实际上insert必须先执行,因为它有第一个“Start transaction”

标签: mysql transactions locking mariadb


【解决方案1】:

InnoDB 行级锁是index-locks in reality。一个记录较少的特性* 是:如果锁定SELECT 不(或不能)使用(用户定义的)索引,则只能使用默认的聚集索引,整个表变为锁定。

很可能优化器认为索引对检查IN()参数的“长”列表没有用(可能是因为需要扫描大部分表)。这会导致您检测到的意外副作用。

这个假设可以通过检查execution plan来证实。

【讨论】:

  • * 我仍然无法为此找到参考,但我的所有测试都同意。我很高兴看到官方消息来源。
  • 非常感谢@RandomSeed,这正是发生的事情,由 EXPLAIN 声明确认。当我添加 FORCE INDEX 语句时,该示例按预期工作。非常感谢您的解释。
【解决方案2】:

我认为您假设“选择更新”仅锁定更新的行。但是,锁定也适用于 INSERT,因为插入可以插入属于原始“选择”的记录。该文档声明它“锁定行和任何关联的索引条目”。

http://dev.mysql.com/doc/refman/5.6/en/innodb-locking-reads.html

【讨论】:

  • 我认为这不是你提到的问题,因为 id 列是 AI 主键,所以它只锁定我需要的行。示例表中没有 FK,它适用于前三个块,但稍后会失败。如果这是你提到的问题,那么我希望它应该一直失败。
  • 是的,但是主键的索引应该被锁定(或至少对于受影响的条目)。
猜你喜欢
  • 2016-09-13
  • 2011-06-14
  • 2015-10-29
  • 1970-01-01
  • 2018-08-30
  • 2015-12-25
  • 2019-10-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多