还得分两种情况来讨论:

  1. 大多数情况是正常的,只是偶尔会出现很慢的情况
  2. 在数据量不变的情况下,这条SQL一直以来都执行很慢。

    偶尔很慢的情况

    数据库在刷新脏页

    往数据库插入一条数据或者更新一条数据,数据库会先在内存把对应字段更新了,更新之后并不会立即持久化到磁盘上去,而是先写redo log, 等到空闲的时候,再写磁盘。
    redo log的容量是有限的,如果数据库一直很忙,然后更新操作又很频繁,这个时候redo log很快就被写满了,没法等到空闲的时候再把数据同步到磁盘,只能暂停其他操作,全心全意的把数据同步磁盘。

    拿不到锁

    这条SQL语句涉及到的表,别人在用,并且加锁了,我们拿不到锁,只能慢慢等待别人释放锁了。或者,表没有被加锁, 但是使用到的某一行被加锁了,这个时候,也没有办法。
    可以使用show processlist 查看当前的状态。

    针对一直很慢的情况

    没用到索引

  3. 字段没有索引

  4. 字段有索引但是没有用到

    select from t where c -1 =1000 正确: select from t where c = 1000 + 1

  5. 函数操作导致没有用上索引

    数据库选错索引了

    主键索引和非主建索引是有区别的,主键索引存放的是整行字段的数据,非主键索引存放的值不是整行字段的值,而是主键字段的值,
    mysql执行的时候,会预测扫描行数,扫描行数越少,磁盘IO越少。可能走全表扫描时是不走索引的,那么系统是怎么判断的呢?

    索引区分度。一个索引上不同的值越多,区分度越高,称之为基数。区分度越高,基数越大。

怎么知道索引的基数?

采样预测。

其他: force index(a) 强制搜索引
也可以通过show index from t 来查询索引的基数和实际是否符合,不符合的话,可以重新统计索引的基数,

analyze table t