偶尔变慢
- 刷脏页,写磁盘
首先说明脏页的概念:当内存数据页跟磁盘数据页内容不一致的时候,我们称这个内存页为“脏页”。内存数据写入到磁盘后,内存和磁盘上的数据页的内容就一致了,称为“干净页”。
通常情况下,我们对于数据的操作都是将数据从磁盘中加载到内存中后,在内存中进行修改的。而修改后也并不是直接就将内存中的脏页刷回到磁盘中。什么情况下会进行刷脏页的操作呢?
- redo log写满了,要flush脏页,前面我们讲过,MySQL操作时会写redo log,而且redo log 的大小时有限的,那么就会出现写满了的情况,此时,就不得不将redo log中的数据刷回到磁盘中。这种情况是InnoDB要尽量避免的。因为出现这种情况的时候,整个系统就不能再接受更新了,所有的更新都必须堵住。
- 内存不够用了,要先将脏页写到磁盘,这种情况其实是常态。InnoDB用缓冲池(buffer pool)管理内存,缓冲池中的内存页有三种状态:
- 第一种是,还没有使用的;
- 第二种是,使用了并且是干净页;
- 第三种是,使用了并且是脏页。
- 而当要读入的数据页没有在内存的时候,就必须到缓冲池中申请一个数据页。如果内存不够,就要把最久不使用的数据页从内存中淘汰掉,如果是刚好是脏页呢,就必须将脏页先刷到磁盘,变成干净页后才能复用。
- 系统处于空闲时刻,在系统处于空闲时刻时,就会将刷脏页操作安排起来。
- MySQL正常关闭时刻,在关闭时刻,系统会将内存中的脏页都刷回磁盘,保证下次使用可以直接使用数据。
对于第三四种情况,明显不是在执行SQL语句导致慢的原因,重点影响效率的就是第一种和第二种情况。
📌所以如果在执行SQL语句时,发生了刷脏页操作,那就一定会影响整体效率!
- 还在等锁
当我们在执行一条SQL语句,需要获得行锁又或者是表锁时,刚好这个表或者行上的锁已经被别的线程持有,此时,我们要执行的语句只能等待别的事务提交后释放锁才能继续执行。
在排查问题时,可以使用show processlist命令,来查看当前的状态,然后进行响应的调整。
📌所以如过SQL语句操作需要等待获取锁,就会导致执行变慢 !
- 回滚日志过多
还有可能出现的问题就是有很多的undo log回滚日志,由于MySQL默认的隔离级别是可重复读,也就是一致性读,所以就有可能出现事务A在事务B之前开启事务并进行查询字段a的操作,而事务B进行了大量修改字段a的操作。
所以,当事务A查到字段a的最新值时,由于隔离级别是可重复读,它查询出的字段a的值不应该是事务B修改后的。而事务A读到的却a是最新的值,但它并不会返回这个结果,而是会从a当前的值多次使用回滚日志,最终查询到未被事务B修改时候的值。
📌由于重复进行了大量对查询值的回滚,也会导致一条SQL语句变慢!
一直很慢
- 没有索引
就是在SQL语句中操作的字段上没有索引,执行语句只能进行全表扫描。如果整个表的数据很多,显然进行全表扫描会导致整体的效率十分低。为了解决这个问题,就要考虑在字段上加上索引,当然加索引也要选择最适合的索引。比如是否可以根据最左前缀的原则使用联合索引,又或者是根据是否需要回表添加主键索引或普通索引,还有根据业务逻辑是否需要建立唯一索引。总之要选择最适合的索引来增加效率。
- 对字段进行函数操作
如果对索引字段做函数操作,执行时就不会继续选择这个索引,这样也会导致效率低下 !
- 选错索引
