看了GitHub推送的一篇《 腾讯面试:一条SQL语句执行得很慢的原因有哪些?》

里面总结了 SQL 语句执行的很慢的原因:1.数据库在刷新脏页的时候会导致SQL很慢

2.锁的问题

3.sql本身的问题

自己对文章进行理解如下:

1、大多数情况下速度正常,偶尔很慢,则有如下原因

(1)、数据库在刷新脏页1.redo日志切换

2.buffer pool不足

3.mysql 自己觉得空闲

4.mysql正常关机

第一种情况,redo写满了需要覆盖,覆盖前需要刷新缓冲没有被写入磁盘的脏页,这种情况是要尽量的避免的,因为这种情况出现,整个系统会不在访问数据。版本低的可能还会阻塞查询。 第二种情况,内存不够了,需要为查询或者更新腾出对应的空闲页,这种情况很常见。 第三, 四两种情况可以忽略他们对性能的影响。

(2)、执行的时候,遇到锁,如表锁、行锁锁是数据库服务器用来控制数据被并行使用的一种机制。当数据库的一些内容被锁定时,任何打算修改(或者可能是读取)这个数据的用户必须等到锁释放。

表锁:阻止多用户同时修改同一个表的数据。

行锁:阻止多用户同时修改某表中同一行的数据。

可以用show processlist这个命令来查看当前的状态是否真的在等待锁。

2、这条 SQL 语句一直执行的很慢,就要查找自身原因了

(1)、没有用上索引 (下面是常见的几种原因分析)查询下面的语句该字段没有索引, 要全表扫描,体验不到索引遍历带来的快乐,导致这条查询语句很慢。

select * from t where 100 < c and c < 100000;该字段有索引, 但由于对字段进行如下运算导致无法用索引。然而右边有运算就能用上索引, 但是数据库不会自动帮我们优化, 需要自己注意。

select * from t where c - 1 = 1000;函数操作导致无法用索引。
select * from t where pow(c,2) = 1000;

(2)、数据库选错了索引

进行如下语句查询操作的时候,例如:

select * from t where 100 < c and c < 100000;如果走 c 这个字段的索引的话,最后会查询到对应主键的值,然后,再根据主键的值走主键索引,查询到整行数据返回。

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

出现这样的原因是:系统在执行这条语句的时候,会进行预测:判断究竟是走 c 索引扫描的行数少,还是走全表扫描的行数少。(扫描行数的预测只是原因之一,这条查询语句是否需要使用使用临时表、是否需要排序等也是会影响系统的选择的。)

系统是通过索引的区分度来预测执行,一个索引上不同的值越多,意味着出现相同数值的索引越少,意味着索引的区分度越高。我们也把区分度称之为基数,即区分度越高,基数越大, 走索引查询越有优势。

系统是通过采样的方式遍历部分数据,来预测索引的基数。采样,那就有可能出现失误的情况,也就是说:c 这个索引的基数实际上是很大的,但是采样的时候,却把这个索引的基数预测成很小。即由于统计的失误,导致系统没有走索引,而是走了全表扫描。

有时候可以通过强制走索引的方式来查询,例如:

select * from t force index(a) where c < 100 and c < 100000;我们自己可以通过下面语句来查询索引的基数和实际是否符合,
show index from t;如果和实际很不符合的话,我们可以用下面命令重新来统计索引的基数,重新统计分析。
analyze table t;