【发布时间】: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 是的,这是正确的顺序
-
似乎索引的名称部分在锁定中被忽略了。解释中的密钥长度是什么意思?