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 真正获取一行行数据并返回数据的地方,存储引擎是可以替换更改的,既可以用不支持事务的 MyISAM,也可以替换成支持事务的 Innodb。这个可以在建表的时候指定。比如
CREATE TABLE `user` (
...
) ENGINE=InnoDB;
现在最常用的是 InnoDB。
我们就重点说这个。
InnoDB 中,因为直接操作磁盘会比较慢,所以加了一层内存提提速,叫 buffer pool,这里面,放了很多内存页,每一页 16KB,有些内存页放的是数据库表里看到的那种一行行的数据,有些则是放的索引信息。
查询 SQL 到了 InnoDB 中。会根据前面优化器里计算得到的索引,去查询相应的索引页,如果不在 buffer pool 里则从磁盘里加载索引页。再通过索引页加速查询,得到数据页的具体位置。如果这些数据页不在 buffer pool 中,则从磁盘里加载进来。
这样我们就得到了我们想要的一行行数据。
最后将得到的数据结果返回给客户端。
慢查询分析
如果上面的流程比较慢的话,我们可以通过开启profiling
看到流程慢在哪。