【问题标题】:lock wait timout in InnoDbInnoDb 中的锁定等待超时
【发布时间】:2020-11-10 00:17:32
【问题描述】:

我创建了一个 mysql 表,其中 (date,name,id,money_spent) 列具有 (date,name,id) 作为主键(因为这个组合总是唯一的)并且 InnoDb 是存储引擎。

date - 日期数据类型, 名称 - varchar(30), id - varchar(100),

我有一个逻辑,其中多个更新查询是并行触发的。例如(暂时考虑这两个)

T1:

 update test_database.users set money_spend = 1000
     where date between "2020-01-01" and "2020-01-10"
       and name = "John";

T2:

update test_database.users set money_spend = 1005
     where date between "2020-01-01" and "2020-01-10"
       and name = "Tammy";

并行运行这2个Transaction会导致T2因为T1获取锁而超时。

事务隔离级别 - 可重复读隔离级别

InnoDb 引擎状态


LOCK WAIT 19543 lock struct(s), heap size 376, 1407774 row lock(s)
MySQL thread id 105402, OS thread handle 0x2ba11d68a700, query id 16862373 10.11.3.212 connect-dev Sending data
update test_database.users set money_spend = 1005 where date between "2020-01-01" and "2020-01-10" and name = "Tammy";
------- TRX HAS BEEN WAITING 2 SEC FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 154606 page no 243093 n bits 78 index `PRIMARY` of table `test_database`.`users` trx id 44023639357 lock_mode X waiting
Record lock, heap no 78 PHYSICAL RECORD: n_fields 30; compact format; info bits 0
 0: len=3; bufptr=0x2b9fea4e2d5e; hex= 8fc95b; asc   [;;
 1: len=8; bufptr=0x2b9fea4e2d61; hex= 4170706e65787573; asc John;;
 2: len=8; bufptr=0x2b9fea4e2d69; hex= 3230393835373832; asc 20985782;;
 3: len=6; bufptr=0x2b9fea4e2d71; hex= 000a3f47ff22; asc   ?G ";;
 4: len=7; bufptr=0x2b9fea4e2d77; hex= 0f011040350d5b; asc    @5 [;;

查看 innoDb 状态,看起来 T2 正在尝试获取以“John”为名称的记录的锁定,但由于以“John”为名称的记录已被 T1 锁定,因此 T2 超时。

问题:由于 InnoDb 支持行级锁定,因此事务(T1)不应该仅对日期在“2020-01-01”和“2020-01-10”之间且名称为“John”的记录获取锁定。由于索引的名称部分不同(T2 的名称为“Tammy”),为什么它会为 T2 事务提供超时时间

【问题讨论】:

  • 你的桌子上有什么索引?
  • @Shadow only primary (date,name,id) 。没有任何辅助。
  • 日期、名称和id是否是索引中字段的确切顺序?
  • @Shadow 是的,这是正确的顺序
  • 似乎索引的名称部分在锁定中被忽略了。解释中的密钥长度是什么意思?

标签: mysql indexing innodb


【解决方案1】:

将 PK 重新排列为 PRIMARY KEY(name, date, id)。这样,所有需要的行(在任一查询中)都将在表中相邻。这比分散行((date, name, ...))更有效。

加快查询速度将有助于一个查询在另一个查询可能与之发生冲突之前完成。

连续的行避免了一些“间隙锁定”的情况。 (我不知道这是否与此处相关,但似乎是。)

= 测试的列需要`范围测试之前。

更多索引提示:http://mysql.rjweb.org/doc.php/index_cookbook_mysql

如果idAUTO_INCREMENT,那么模式是“让我们先在PK 中放置一些列以加快某些查询,然后在末尾添加id 以确保它是唯一的。(我不知道这是否是你正在做的;但这与当前的讨论无关。)

【讨论】:

  • 您能否在此答案中添加来自 mysql 文档或性能博客的参考?很高兴了解范围查找如何影响索引使用!
  • @Shadow - 我怀疑我的简单一句话经验法则是否在文档中明确说明。同时,我的博客基于索引和搜索的工作原理。 (所以,我承认我的博客不是“性能博客”。)
猜你喜欢
  • 2011-01-24
  • 1970-01-01
  • 2017-10-29
  • 2016-12-16
  • 2011-01-07
  • 1970-01-01
  • 2019-11-20
  • 2017-02-01
  • 1970-01-01
相关资源
最近更新 更多