Mysql InnoDb中的锁定等待超时

Mysql InnoDb中的锁定等待超时,mysql,indexing,innodb,Mysql,Indexing,Innodb,我创建了一个mysql表,其中(date、name、id、money_-spend)列的主键是(date、name、id)(因为这种组合总是唯一的),InnoDb是存储引擎 日期-日期数据类型, 姓名-瓦尔查尔(30), id-varchar(100) 我有一个逻辑,即在多个更新查询中并行触发。对于Eg(现在考虑这两个) T1: T2: 并行运行这2个事务会导致T2超时,因为T1获得了锁 事务隔离级别-可重复读取隔离级别 InnoDb引擎状态 LOCK WAIT 19543 lock stru

我创建了一个mysql表,其中(date、name、id、money_-spend)列的主键是(date、name、id)(因为这种组合总是唯一的),InnoDb是存储引擎

日期-日期数据类型, 姓名-瓦尔查尔(30), id-varchar(100)

我有一个逻辑,即在多个更新查询中并行触发。对于Eg(现在考虑这两个)

T1:

T2:

并行运行这2个事务会导致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事务一个暂停时间

将主键重新排列为
主键(名称、日期、id)
。这样,所需的所有行(在任一查询中)都将在表中相邻。这比分散行(使用
(日期、名称等)
)更有效

加快查询速度将帮助一个查询在另一个查询可能与之冲突之前完成

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

使用
=
测试的列需要位于“范围测试”之前

更多索引提示:


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

将主键重新排列为
主键(名称、日期、id)
。这样,所有需要的行(在任一查询中)都将在表中相邻。这比分散行(使用
(日期、名称,…)
更有效

加快查询速度将帮助一个查询在另一个查询可能与之冲突之前完成

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

使用
=
测试的列需要位于“范围测试”之前

更多索引提示:


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

表中有哪些索引?@Shadow only primary(日期、名称、id)。没有任何辅助项。日期、名称和id是索引中字段的确切顺序吗?@Shadow yes这是确切顺序。似乎索引的名称部分在锁定中被忽略了。说明中的键长度是多少?表上有哪些索引?@Shadow only primary(日期、名称、id)。没有任何辅助项。日期、名称和id是索引中字段的确切顺序吗?@Shadow yes这是确切顺序。似乎索引的名称部分在锁定中被忽略了。“解释”中的键长度是什么?您能否在这个答案中添加mysql文档或性能博客中的参考?如果能了解范围查找如何影响索引使用,那就太好了@影子-我怀疑我简单的一句话经验法则是否在文档中明确说明。同时,我的博客基于索引和搜索的工作原理。(所以,我承认我的博客不是一个“性能博客”。)你能在这个答案中添加mysql文档或性能博客的引用吗?如果能了解范围查找如何影响索引使用,那就太好了@影子-我怀疑我简单的一句话经验法则是否在文档中明确说明。同时,我的博客基于索引和搜索的工作原理。(因此,我承认我的博客不是一个“性能博客”。)
update test_database.users set money_spend = 1005
     where date between "2020-01-01" and "2020-01-10"
       and name = "Tammy";

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 [;;