大多数情况是正常的,只是偶尔会出现很慢的情况
-
网络问题
-
数据库在刷新脏页
-
获取锁失败,我们可以用 show processlist这个命令来查看当前的状态
刷脏页有下面4种场景(后两种不用太关注“性能”问题):
-
redolog写满了:redo log 里的容量是有限的,如果数据库一直很忙,更新又很频繁,这个时候 redo log 很快就会被写满了,这个时候就没办法等到空闲的时候再把数据同步到磁盘的,只能暂停其他操作,全身心来把数据同步到磁盘中去的,而这个时候,就会导致我们平时正常的SQL语句突然执行的很慢,alter table 可能造成脏页过多。所以说,数据库在在同步数据到磁盘的时候,就有可能导致我们的SQL语句执行的很慢了。
-
内存不够用了:如果一次查询较多的数据,恰好碰到所查数据页不在内存中时,需要申请内存,而此时恰好内存不足的时候就需要淘汰一部分内存数据页,如果是干净页,就直接释放,如果恰好是脏页就需要刷脏页。
-
MySQL 认为系统“空闲”的时候/ Master Thread:这时系统IO压力不大,每秒或每十秒的异步刷新操作
-
MySQL 正常关闭的时候:这时候,MySQL 会把内存的脏页都 flush 到磁盘上,这样下次 MySQL 启动的时候,就可以直接从磁盘上读数据,启动速度会很快。
在数据量不变的情况下,这条SQL语句一直以来都执行的很慢
- 没有用上索引:例如该字段没有索引;由于对字段进行运算、函数操作导致无法用索引。
- 数据库选错了索引
有索引但是最终却选择全表扫描的原因:
例如以下SQL:
select * from t where 100 < c and c < 100000;
索引的选择判断来源于系统的预测,也就是说,如果要走 c 字段索引的话,系统会预测走 c 字段索引大概需要扫描多少行。如果预测到要扫描的行数很多(大概接近于20%),它可能就不走索引而直接扫描全表了。因为索引c将标识多一次的辅助索引的查询,造成IO的增多。
系统判断是否走索引,扫描行数的预测其实只是原因之一,这条查询语句是否需要使用使用临时表、是否需要排序等也是会影响系统的选择的。