Mysql数据库查询好慢,除了索引,还能因为什么?( 二 )

关注下上面的query_id,比如select * from user where age>=60对应的query_id是1,如果你想查看这条SQL语句的具体耗时,那么可以执行以下的命令 。
mysql> show profile for query 1;+----------------------+----------+| Status               | Duration |+----------------------+----------+| starting             | 0.000074 || checking permissions | 0.000010 || Opening tables       | 0.000034 || init                 | 0.000032 || System lock          | 0.000027 || optimizing           | 0.000020 || statistics           | 0.000058 || preparing            | 0.000018 || executing            | 0.000013 || Sending data         | 0.067701 || end                  | 0.000021 || query end            | 0.000015 || closing tables       | 0.000014 || freeing items        | 0.000047 || cleaning up          | 0.000027 |+----------------------+----------+15 rows in set, 1 warning (0.00 sec)通过上面的各个项,大家就可以看到具体耗时在哪 。比如从上面可以看出Sending data的耗时最大,这个是指执行器开始查询数据并将数据发送给客户端的耗时,因为我的这张表符合条件的数据有好几万条,所以这块耗时最大,也符合预期 。
一般情况下,我们开发过程中,耗时大部分时候都在Sending data阶段,而这一阶段里如果慢的话,最容易想到的还是索引相关的原因 。
 
索引相关原因索引相关的问题,一般能用explain命令帮助分析 。通过它能看到用了哪些索引,大概会扫描多少行之类的信息 。
mysql会在优化器阶段里看下选择哪个索引,查询速度会更快 。
一般主要考虑几个因素,比如:

  • 选择这个索引大概要扫描多少行(rows)
  • 为了把这些行取出来,需要读多少个16kb的页
  • 走普通索引需要回表,主键索引则不需要,回表成本大不大?
 
回到show profile中提到的sql语句,我们使用explain select * from user where age>=60 分析一下 。
Mysql数据库查询好慢,除了索引,还能因为什么?

文章插图
 
explain sql
上面的这条语句,使用的type为ALL,意味着是全表扫描,possible_keys是指可能用得到的索引,这里可能使用到的索引是为age建的普通索引,但实际上数据库使用的索引是在key那一列,是NULL 。也就是说这句sql不走索引,全表扫描 。
这个是因为数据表里,符合条件的数据行数(rows)太多,如果使用age索引,那么需要将它们从age索引中读出来,并且age索引是普通索引,还需要回表找到对应的主键才能找到对应的数据页 。算下来还不如直接走主键划算 。于是最终选择了全表扫描 。
当然上面只是举了个例子,实际上,mysql执行sql时,不用索引或者用的索引不符合我们预期这件事经常发生,索引失效的场景有很多,比如用了不等号,隐式转换等,这个相信大家背八股文的时候也背过不少了,我也不再赘述 。
聊两个生产中容易遇到的问题吧 。
 
索引不符合预期实际开发中有些情况比较特殊,比如有些数据库表一开始数据量小,索引少,执行sql时,确实使用了符合你预期的索引 。但随时时间变长,开发的人变多了,数据量也变大了,甚至还可能会加入一些其他重复多余的索引,就有可能出现用着用着,用到了不符合你预期的其他索引了 。从而导致查询速度突然变慢 。
这种问题,也好解决,可以通过force index指定索引 。比如
Mysql数据库查询好慢,除了索引,还能因为什么?

文章插图


推荐阅读