Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

19 | 为什么我只查一行的语句,也执行这么慢? #29

Open
git-zjx opened this issue Aug 5, 2019 · 0 comments

Comments

@git-zjx
Copy link
Owner

commented Aug 5, 2019

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

一般碰到这种情况的话,大概率是表 t 被锁住了。分析原因时一般都是首先执行一下 show processlist 命令,看看当前语句处于什么状态

  1. 等 MDL 锁

5008d7e9e22be88a9c80916df4f4b328
出现这个状态表示的是,现在有一个线程正在表 t 上请求或者持有 MDL 写锁,把 select 语句堵住了。
这类问题的处理方式,就是找到谁持有 MDL 写锁,然后把它 kill 掉。通过查询 sys.schema_table_lock_waits 这张表,我们就可以直接找出造成阻塞的 process id,把这个连接用 kill 命令断开即可(MySQL 启动时需要设置 performance_schema=on,相比于设置为 off 会有 10% 左右的性能损失)

  1. 等 flush

2d8250398bc7f8f7dce8b6b1923c3724
这个状态表示的是,现在有一个线程正要对表 t 做 flush 操作。也可能是有一个 flush tables 命令被别的语句堵住了,然后它又堵住了我们的 select 语句
这类问题的处理方式,可以执行 show processlist 查看结果,然后 kill 掉堵塞的语句

  1. 等行锁

3c266e23fc307283aa94923ecbbc738f
这个问题并不难分析,但问题是怎么查出是谁占着这个写锁。如果你用的是 MySQL 5.7 版本,可以通过 sys.innodb_lock_waits 表查到。

mysql> select * from sys.innodb_lock_waits where locked_table='`test`.`t`'\G

d8603aeb4eaad3326699c13c46379118

可以看到,这个信息很全,4 号线程是造成堵塞的罪魁祸首。而干掉这个罪魁祸首的方式,就是 KILL QUERY 4KILL 4。不过,这里不应该显示 KILL QUERY 4。这个命令表示停止 4 号线程当前正在执行的语句,而这个方法其实是没有用的。因为占有行锁的是 update 语句,这个语句已经是之前执行完成了的,现在执行 KILL QUERY,无法让这个事务去掉 id=1 上的行锁。实际上,KILL 4 才有效,也就是说直接断开这个连接。这里隐含的一个逻辑就是,连接被断开的时候,会自动回滚这个连接里面正在执行的线程,也就释放了 id=1 上的行锁。

第二类:查询慢

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

由于字段 c 上没有索引,这个语句只能走 id 主键顺序扫描,因此需要扫描 5 万行,随着数据量的增加,执行的时间会越来越长,坏查询不一定是慢查询

还有一种就是,回滚日志太大,假如生成了 100w 条回滚日志,如果是一致性读的话,会依次执行 undo log,执行 100w 次之后才把结果返回

@git-zjx git-zjx added this to MySQL实战45讲 in MySQL Aug 7, 2019

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
1 participant
You can’t perform that action at this time.