19-为什么我只查一行的语句,也执行这么慢?
欢迎来到我的 ChatGPT 中转站,极具性价比,为付费不方便的朋友提供便利,有需求的可以添加左侧 QQ 二维码,另外,邀请新用户能获取余额哦!最后说一句,那啥:请自觉遵守《生成式人工智能服务管理暂行办法》。
# 等行锁
Session A | Session B |
---|---|
begin; | |
update t set c = c+1 where id = 1; | |
select * from t where id = 1 lock in share mode;(lock in share mode 等价于 for update,第 8 篇讲过) |
执行完成后发现 Session B 被阻塞。执行下面命令可以看到阻塞。
select * from sys.innodb_lock_waits where locked_table='`test`.`t`'\G
1
这里能看到造成阻塞的是 103 号线程,执行 KILL QUERY 103 或者 QUERY 103。但是执行 KILL QUERY 103 是没有用的,这个语句是代表停止执 103 号线程正在执行的语句,而造成阻塞的是 for update 行锁语句。必须执行 QUERY 103 才行,断开链接,就自动回滚了事务的执行的语句了。
# 查询慢
select * from t where c=50000 limit 1;
1
因为 C 没有索引,这个会扫描 50000 行才会返回。但是通过慢查询日志却发现并不是很慢,所以印证了一句话:坏查询不一定是慢查询。10 万行看着不慢,等数据量上去后就线性涨上去了。
再看一个案例
select * from t where id = 1;
## 但是这个查询却非常快。
select * from t where id = 1 for update ;
1
2
3
2
3
复现步骤
SessionA | SessionB |
---|---|
start transaction with consistent snapshot | |
update t set c = c+1 where id =1 ; /100 万次 / | |
select * from t where id = 1; | |
select * from t where id = 1 for update / lock in share mode ; |
这是因为用了一致性读取,undo log 会创建出来 100 万个回滚日志, select * from t where id = 1;
要找到创建快照时候对应的那条数据,而 select * from t where id = 1 for update / lock in share mode ;
是当前读,所以就能立刻找到。
上次更新: 2025/04/12, 05:37:39