盘点导致 sql 执行速度慢的几种情况,都是生产环境踩过的坑
当我们遇到慢 sql,第一反应可能就是去优化我们的 sql 语句。一些比较复杂的语句如果执行慢可能还能理解,但是有时一些特别简单的查询也会变得卡顿,“查一行”,也会执行得特别慢。今天,我们盘点一下,都有哪些情况会导致 sql 执行速度慢。
1,数据库本身压力较大
如果数据库本身的性能压力就比较大,资源比较紧张,CPU 占用率或者 IO 利用率很高,这时会导致所有的语句执行起来都比较慢。这种情况下首先要做的应该是提升服务器的配置,然后观察服务器的性能指标是否平稳。
![](https://static001.geekbang.org/infoq/6b/6b6891a7e3eb02e38a04af476e62f7bc.png)
2,表锁冲突
如果遇到一个简单的查询长时间未返回结果,那么大概率是表被锁住了。一般遇到这种情况,都是通过 show processlist 命令,查看 sql 语句的状态。
![](https://static001.geekbang.org/infoq/de/de49cc8044e96d3308037b43cd1508d0.webp?x-oss-process=image%2Fresize%2Cp_80%2Fformat%2Cpng)
如图所示,id 为 8 的语句正在等待一个 MDL 锁,我们可以使用 kill 命令杀掉这个阻塞线程。
另外还可以通过表 sys.schema_table_lock_waits 查询阻塞的线程 id。
![](https://static001.geekbang.org/infoq/0a/0a278ae8918f1095df19bff26cb8549d.webp?x-oss-process=image%2Fresize%2Cp_80%2Fformat%2Cpng)
3,行锁冲突
当我们访问 id=3 这条记录时,使用了 for update,表示要对这条语句加锁。但是如果此时已经有另一个事务对这条记录加了锁,并且一直持有不释放锁,那么当前语句就会一直阻塞。
![](https://static001.geekbang.org/infoq/b5/b5b728e349621b69a32284a448e782dc.png)
通过上图可以看出,第一个语句不提交事务,第二个语句就一直处于等待阻塞状态。
我们执行 show processlist,
![](https://static001.geekbang.org/infoq/86/8693d026f3e98f23cfb3a59d837b1633.png)
可以看出确实有一个线程处于阻塞状态。
锁冲突会导致执行效率降低,进而影响到业务,需要我们重点关注。
4,索引未命中
如果字段 c 上面没有索引,那么就只能走主键 id 顺序扫描,一直扫描到第 50000 行才能停下来。
给表数据加索引可以快速提升查询性能,一般来说,因为索引失效导致的慢 sql 可能是我们平常开发过程中经常遇到的,比如字段类型的隐式转换,字段使用了函数导致索引失效等等。
5,多表 join 查询
有了索引,并不代表万事大吉。如果一个比较复杂的 sql,需要关联很多表进行查询,即使每张表的索引都可以起到作用,但是由于数据量过多,即使都命中索引,扫描的行数仍然是巨大的。这样 sql 的执行速度仍然会受到很大影响。
一般来说,超过 3 个表的 join 就应该尽量避免,将其拆分为多个查询,使用空间换时间也不失为一个好办法。
总结
总的来说,sql 执行速度慢会受到很多种情况的影响,比如表锁,行锁,索引失效等。在实际的业务场景中也许会更复杂,但是处理起来的步骤基本大同小异,只要找到问题的根源,知道如何解决,处理起来就可以做到心中有数,游刃有余。
finally,都看到这里了,点个赞再走吧。
版权声明: 本文为 InfoQ 作者【程序员拾山】的原创文章。
原文链接:【http://xie.infoq.cn/article/c7c68c0bf2370807f0533a36b】。未经作者许可,禁止转载。
评论