MySQL查询慢别怪索引,没准是这些原因导致的

我熟练应用ctrl c和ctrl v 开发curd代码好多年了 。
 
MySQL查询为什么会慢,关于这个问题,在实际开发经常会遇到,而面试中,也是个高频题 。
 
遇到这种问题,我们一般也会想到是因为索引 。
 
那除开索引之外,还有哪些因素会导致数据库查询变慢呢?
 
有哪些操作,可以提升mysql的查询能力呢?
 
今天这篇文章,我们就来聊聊会导致数据库查询变慢的场景有哪些,并给出原因和解决方案 。
 
一、数据库查询流程
 
我们先来看下,一条查询语句下来,会经历哪些流程 。
 
比如我们有一张数据库表:
 
CREATE TABLE `user` (`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',`name` varchar(100) NOT NULL DEFAULT '' COMMENT '名字',`age` int(11) NOT NULL DEFAULT '0' COMMENT '年龄',`gender` int(8) NOT NULL DEFAULT '0' COMMENT '性别',PRIMARY KEY (`id`),KEY `idx_age` (`age`),KEY `idx_gender` (`gender`)) ENGINE=InnoDB DEFAULT CHARSET=utf8; 
我们平常写的应用代码(go或C++之类的),这时候就叫客户端了 。
 
客户端底层会带着账号密码,尝试向mysql建立一条TCP长链接 。
 
mysql的连接管理模块会对这条连接进行管理 。
 
建立连接后,客户端执行一条查询sql语句 。比如:
 
select * from user where gender = 1 and age = 100; 
客户端会将sql语句通过网络连接给mysql 。
 
mysql收到sql语句后,会在分析器中先判断下SQL语句有没有语法错误,比如select,如果少打一个l,写成slect,则会报错You have an error in your SQL syntax;  。这个报错对于我这样的手残党来说可以说是很熟悉了 。
 
接下来是优化器,在这里会根据一定的规则选择该用什么索引 。
 
之后,才是通过执行器去调用存储引擎的接口函数 。

MySQL查询慢别怪索引,没准是这些原因导致的

文章插图
 
Mysql架构
 
存储引擎类似于一个个组件,它们才是mysql真正获取一行行数据并返回数据的地方,存储引擎是可以替换更改的,既可以用不支持事务的MyISAM,也可以替换成支持事务的Innodb 。这个可以在建表的时候指定 。比如:
 
CREATE TABLE `user` (...) ENGINE=InnoDB; 
现在最常用的是InnoDB 。
 
我们就重点说这个 。
 
InnoDB中,因为直接操作磁盘会比较慢,所以加了一层内存提提速,叫buffer pool,这里面,放了很多内存页,每一页16KB,有些内存页放的是数据库表里看到的那种一行行的数据,有些则是放的索引信息 。
MySQL查询慢别怪索引,没准是这些原因导致的

文章插图
 
bufferPool与磁盘
 
查询SQL到了InnoDB中 。会根据前面优化器里计算得到的索引,去查询相应的索引页,如果不在buffer pool里则从磁盘里加载索引页 。再通过索引页加速查询,得到数据页的具体位置 。如果这些数据页不在buffer pool中,则从磁盘里加载进来 。
 
这样我们就得到了我们想要的一行行数据 。
MySQL查询慢别怪索引,没准是这些原因导致的

文章插图
 
索引页与磁盘页的关系
 
最后将得到的数据结果返回给客户端 。
 
二、慢查询分析
 
如果上面的流程比较慢的话,我们可以通过开启profiling看到流程慢在哪 。
 
mysql> set profiling=ON;Query OK, 0 rows affected, 1 warning (0.00 sec)mysql> show variables like 'profiling';+---------------+-------+| Variable_name | Value |+---------------+-------+| profiling| ON|+---------------+-------+1 row in set (0.00 sec) 
然后正常执行sql语句 。
 
这些SQL语句的执行时间都会被记录下来,此时你想查看有哪些语句被记录下来了,可以执行 show profiles;
【MySQL查询慢别怪索引,没准是这些原因导致的】 
mysql> show profiles;+----------+------------+---------------------------------------------------+| Query_ID | Duration| Query|+----------+------------+---------------------------------------------------+|1 | 0.06811025 | select * from user where age>=60||2 | 0.00151375 | select * from user where gender = 2 and age = 80||3 | 0.00230425 | select * from user where gender = 2 and age = 60||4 | 0.00070400 | select * from user where gender = 2 and age = 100 ||5 | 0.07797650 | select * from user where age!=60|+----------+------------+---------------------------------------------------+5 rows in set, 1 warning (0.00 sec)


推荐阅读