一条sql语句执行很慢的原因有哪些?

一条sql语句执行很慢的原因有哪些?

  1. 偶尔很慢

    • 数据库在刷新脏页(flush)

      当我们要往数据库插入一条数据、或者要更新一条数据的时候,我们知道数据库会在内存中把对应字段的数据更新了,但是更新之后,这些更新的字段并不会马上同步持久化到磁盘中去,而是把这些更新的记录写入到 redo log 日记中去,等到空闲的时候,在通过 redo log 里的日记把最新的数据同步到磁盘中去。

      刷脏页有下面4种场景(后两种不用太关注“性能”问题):

      • redo log写满了:redo log 里的容量是有限的,如果数据库一直很忙,更新又很频繁,这个时候 redo log 很快就会被写满了,这个时候就没办法等到空闲的时候再把数据同步到磁盘的,只能暂停其他操作,全身心来把数据同步到磁盘中去的,而这个时候,就会导致我们平时正常的SQL语句突然执行的很慢,所以说,数据库在在同步数据到磁盘的时候,就有可能导致我们的SQL语句执行的很慢了。
      • 内存不够用了:如果一次查询较多的数据,恰好碰到所查数据页不在内存中时,需要申请内存,而此时恰好内存不足的时候就需要淘汰一部分内存数据页,如果是干净页,就直接释放,如果恰好是脏页就需要刷脏页。
      • MySQL 认为系统“空闲”的时候:这时系统没什么压力。
      • MySQL 正常关闭的时候:这时候,MySQL 会把内存的脏页都 flush 到磁盘上,这样下次 MySQL 启动的时候,就可以直接从磁盘上读数据,启动速度会很快。
    • 拿不到锁

      这个就比较容易想到了,我们要执行的这条语句,刚好这条语句涉及到的,别人在用,并且加锁了,我们拿不到锁,只能慢慢等待别人释放锁了。或者,表没有加锁,但要使用到的某个一行被加锁了,这个时候,我也没办法啊。

  2. 一直这么慢

    • 没有用到索引(索引失效)

      (1)字段没有建立索引,进行全表扫描——sql语句写的很烂

      select * from t where 100 < c and c < 100000;

      刚好你的 c 字段上没有索引,那么抱歉,只能走全表扫描了,你就体验不会索引带来的乐趣了,所以,这回导致这条查询语句很慢。

      (2)字段有索引,但却没有用索引(索引失效)

      列举一种索引失效的情况:

      ​ 1)在索引列上做运算的时候不会走索引

      select * from t where c - 1 = 1000;
      正确的应该是:
      select * from t where c = 1000 + 1;
      

      ​ 2)对字段进行了函数操作,不会用上索引

      select * from t where pow(c,2) = 1000;
      

      假设函数 pow 是求 c 的 n 次方,实际上可能并没有 pow(c,2)这个函数。其实这个和上面在左边做运算也是很类似的。

      在这里插入图片描述

    • 数据库选错了索引

    select * from t where 100 < c and c < 100000;
    

    主键索引和非主键索引是有区别的,主键索引存放的值是整行字段的数据,而非主键索引上存放的值不是整行字段的数据,而且存放主键字段的值

    我们如果走 c 这个字段的索引的话,最后会查询到对应主键的值,然后,再根据主键的值走主键索引,查询到整行数据返回。

    就算你在 c 字段上有索引,系统也并不一定会走 c 这个字段上的索引,而是有可能会直接扫描扫描全表,找出所有符合 100 < c and c < 100000 的数据。

    为什么会这样呢?

    参考:一条SQL语句执行得很慢的原因有哪些?

posted @ 2021-05-14 21:22  your_棒棒糖  阅读(107)  评论(0编辑  收藏  举报