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> 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)


推荐阅读