导致sql执行速度慢的几种情况盘点(生产环境踩过的坑)
作者:程序员拾山 时间:2024-01-17 17:07:21
前言
当我们遇到慢sql,第一反应可能就是去优化我们的sql语句。一些比较复杂的语句如果执行慢可能还能理解,但是有时一些特别简单的查询也会变得卡顿,“查一行”,也会执行得特别慢。今天,我们盘点一下,都有哪些情况会导致sql执行速度慢。
1,数据库本身压力较大
如果数据库本身的性能压力就比较大,资源比较紧张,CPU占用率或者IO利用率很高,这时会导致所有的语句执行起来都比较慢。这种情况下首先要做的应该是提升服务器的配置,然后观察服务器的性能指标是否平稳。
2,表锁冲突
如果遇到一个简单的查询长时间未返回结果,那么大概率是表被锁住了。一般遇到这种情况,都是通过show processlist命令,查看sql语句的状态。
如图所示,id为8的语句正在等待一个MDL锁,我们可以使用kill命令杀掉这个阻塞线程。
另外还可以通过表sys.schema_table_lock_waits查询阻塞的线程id。
3,行锁冲突
mysql> select * from temp where id =3 for update;
当我们访问id=3这条记录时,使用了for update,表示要对这条语句加锁。但是如果此时已经有另一个事务对这条记录加了锁,并且一直持有不释放锁,那么当前语句就会一直阻塞。
通过上图可以看出,第一个语句不提交事务,第二个语句就一直处于等待阻塞状态。
我们执行show processlist,
可以看出确实有一个线程处于阻塞状态。
锁冲突会导致执行效率降低,进而影响到业务,需要我们重点关注。
4,索引未命中
mysql> select * from t where c=50000 limit 1;
如果字段c上面没有索引,那么就只能走主键id顺序扫描,一直扫描到第50000行才能停下来。
给表数据加索引可以快速提升查询性能,一般来说,因为索引失效导致的慢sql可能是我们平常开发过程中经常遇到的。
5,多表join查询
有了索引,并不代表万事大吉。如果一个比较复杂的sql,需要关联很多表进行查询,即使每张表的索引都可以起到作用,但是由于数据量过多,即使都命中索引,扫描的行数仍然是巨大的。这样sql的执行速度仍然会受到很大影响。
一般来说,超过3个表的join就应该尽量避免,将其拆分为多个查询,使用空间换时间也不失为一个好办法。
补充知识:慢 SQL 语句的几种常见诱因
1. 无索引、索引失效导致
慢查询如果在一张几千万数据的表中以一个没有索引的列作为查询条件,大部分情况下查询会非常耗时,这种查询毫无疑问是一个慢 SQL 查询。
所以对于大数据量的查询,需要建立适合的索引来优化查询。虽然我们很多时候建立了索引,但在一些特定的场景下,索引还有可能会失效,所以索引失效也是导致慢查询的主要原因之一。
2. 锁等待
常用的存储引擎有 InnoDB 和 MyISAM,前者支持行锁和表锁,后者只支持表锁。
如果数据库操作是基于表锁实现的,试想下,如果一张数据表在更新时,需要锁住整张表,那么其它大量数据库操作(包括查询)都将处于等待状态,这将严重影响到系统的并发性能。这时,InnoDB 存储引擎支持的行锁更适合高并发场景。
行锁升级为表锁的可能:
在批量更新操作时,行锁就很可能会升级为表锁。
MySQL 认为如果对一张表使用大量行锁,会导致事务执行效率下降,从而可能造成其它事务长时间锁等待和更多的锁冲突问题发生,致使性能严重下降,所以 MySQL 会将行锁升级为表锁。还有,行锁是基于索引加的锁,如果我们在更新操作时,条件索引失效,那么行锁也会升级为表锁。
因此,基于表锁的数据库操作,会导致 SQL 阻塞等待,影响执行速度。
行锁相对表锁来说,虽然粒度更细,并发能力提升了,但也带来了死锁的问题。因此,在使用行锁时,我们要注意避免死锁。
3. 不恰当的 SQL 语句
使用不恰当的 SQL 语句也是慢 SQL 最常见的诱因之一 :
在大数据表中使用 分页查询,以及对非索引字段进行排序等等。
来源:https://blog.csdn.net/qq_33312725/article/details/128010225