表锁、行锁和一致性读——为什么我只查一行的语句,也执行这么慢?

目录

1、第一类:查询长时间不返回

(1)等 MDL 锁

(2)等 flush

(3)等行锁

2、第二类:查询慢

(1)扫描行数多,所以执行慢

(2)一致性读需要进行多次回滚操作


1、第一类:查询长时间不返回

mysql> select * from t where id=1;

一般碰到这种情况的话,大概率是表 t 被锁住了。

首先执行一下 show processlist 命令,看看当前语句处于什么状态。

(1)等 MDL 锁

举例:

原因:即现在有一个线程正在表 t 上请求或者持有 MDL 写锁,把 select 语句堵住了。

解决:通过查询 sys.schema_table_lock_waits 这张表,我们就可以直接找出造成阻塞的 process id,把这个连接用 kill 命令断开即可。

(2)等 flush

举例:

原因:有一个 flush tables 命令被别的语句堵住了,然后它又堵住了我们的 select 语句。

现在有一个线程正要对表 t 做 flush 操作。MySQL 里面对表做 flush 操作的用法,一般有以下两个:

flush tables t with read lock;

flush tables with read lock;

注:这两个 flush 语句,如果指定表 t 的话,代表的是只关闭表 t;如果没有指定具体的表名,则表示关闭 MySQL 里所有打开的表

(3)等行锁

举例:

原因:session A 启动了事务,占有写锁,还不提交,是导致 session B 被堵住的原因。

解决:查出谁占用行锁,kill掉

2、第二类:查询慢

(1)扫描行数多,所以执行慢

mysql> select * from t where c=50000 limit 1;

由于字段 c 上没有索引,这个语句只能走 id 主键顺序扫描,因此需要扫描 5 万行。

(2)一致性读需要进行多次回滚操作

只扫描一行,但是执行很慢的语句:“ select * from t where id=1;”执行时间长达 800 毫秒。而“select * from t where id=1 lock in share mode“,执行时扫描行数也是 1 行,执行时间是 0.2 毫秒

结果:为什么结果不一致呢?

原因:session B 更新完 100 万次,生成了 100 万个回滚日志 (undo log)。带 lock in share mode 的 SQL 语句,是当前读,因此会直接读到 1000001 这个结果,所以速度很快;而 select * from t where id=1 这个语句,是一致性读,因此需要从 1000001 开始,依次执行 undo log,执行了 100 万次以后,才将 1 这个结果返回。

发布了114 篇原创文章 · 获赞 21 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/qq_38151401/article/details/104791028
今日推荐