sql运行的很慢排查

第一类:锁的原因

mysql中有表锁,行锁,一些线程加了锁了之后占有着资源,其他线程再进入进行相关操作就可能一直在等待锁的释放导致感觉sql运行很慢

等表锁

如执行 mysql> select * from t where id=1;

分析原因的时候,一般都是首先执行一下show processlist命令,看看当前语句处于什么状态。

img

MDL(metadata lock)。MDL不需要显式使用,在访问一个表的时候会被自动加上。MDL的作用是,保证读写的正确性。你可以想象一下,如果一个查询正在遍历一个表中的数据,而执行期间另一个线程对这个表结构做变更,删了一列,那么查询线程拿到的结果跟表结构对不上,肯定是不行的。

因此,在MySQL 5.5版本中引入了MDL,当对一个表做增删改查操作的时候,加MDL读锁;当要对表做结构变更操作的时候,加MDL写锁。

  • 读锁之间不互斥,因此你可以有多个线程同时对一张表增删改查。
  • 读写锁之间、写锁之间是互斥的,用来保证变更表结构操作的安全性。因此,如果有两个线程要同时给一个表加字段,其中一个要等另一个执行完才能开始执行。

复现方法:

img

等行锁

复现方法

img

会话A启动事务来更新id=1这一行的数据卡住了没有提交事务,会话B查询id=1这一行数据一直锁着的导致查询很慢

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

查询方法是:

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

img

这个信息很全,4号线程是造成堵塞的罪魁祸首。而干掉这个罪魁祸首的方式,就是KILL 4。干掉4线程就可以回滚上一个语句释放锁。

第二类:查询遍历慢

慢查询一般有这几种可能,没有建立好索引导致全表检索或没做到很好的索引覆盖导致多次回表,还有就是select * 很多数据造成网络io拥堵。

以上一般看慢查询日志。注意,为了把所有语句记录到slow log里,连接后先执行了 set long_query_time=0,将慢查询日志的时间阈值设置为0。

在慢查询日志里查看哪条sql慢再进行sql性能分析,使用explain即可。

还有一致性读的原因也有可能查询慢,若一个事务对某行数据新操作生成了大量的undo log日志,另一事务进行该行读取的时候就要依次遍历改行数据的undo log也会很慢


sql运行的很慢排查
https://lililib.github.io/一条sql语句执行很慢排查/
作者
煨酒小童
发布于
2023年1月6日
许可协议