目的
优化数据访问
分两步分析是否是低效的查询:
是否向数据库请求了不需要的数据?
比如查询了过多的行,查询过多的列(select * …),以及重复的查询。Mysql是否在扫描额外的记录?
三个指标衡量查询开销:- 响应时间
- 扫描行数
- 返回的行数
重构查询的方式
- 一个复杂查询or多个简单查询?
- 切分查询(比如在删改操作时,将全量语句改成批量执行)
- 分解关联查询(把一条复杂的关联查询分解为多条简单查询,可以让缓存效率更高,减少锁竞争)
一张图看Mysql执行过程
- 客户端将查询发送到服务器;
- 服务器检查查询缓存,如果找到了,就从缓存中返回结果,否则进行下一步。
- 服务器解析,预处理和优化查询,生成执行计划。
- 执行引擎调用存储引擎API执行查询。
- 服务器将结果发送回客户端。
1.客户端服务端通信协议
通信协议工作机制:“抛球”游戏。任意时刻,要么是客户端发送数据,要么是服务端发送数据。一旦一端发送数据(抛球),另一端只能完整的接受消息才能响应。
所以,我们需要限制发送信息的大小。
客户端:查询语句尽量少,否则可能会抛错误异常(“MySQL server has gone away”)。
# 查看你的服务器所允许传送的最大数据
SHOW VARIABLES LIKE 'max_allowed_packet'
服务端:当服务端开始响应客户端请求时,客户端必须完整接受整个返回结果。所以要限制查询条数,必要时查询语句用“LIMIT”限制。
通过 “SHOW [FULL] PROCESSLIST” 命令查询mysql连接时线程状态:MySQL5.7通用线程状态
2.查询缓存
如果开启了缓存,MySql会检查查询缓存,进行大小写敏感的哈希查找。如果命中,判断权限没问题后会跳过所有其他阶段直接返回。
# 查看是否开启查询
SHOW VARIABLES LIKE 'query_cache_type';
3.解析器
解析器通过关键字解析SQL,然后生成一颗对应的“解析树”,然后它使用MySQL语法规则验证和解析语句,比如关键字是否错误,顺序等。
4.预处理
进一步检查解析树的合法性。比如检查数据表列是否存在,名字和别名等。最后,预处理器检查权限。
5.查询优化器(重点)
优化器负责将预处理合格的语法树转化为执行计划。
MySQL使用基于成本的优化器,它将尝试预测一个查询使用某种执行计划的成本,并选择成本最小的一个。
# 查询当前会话的当前查询成本
SHOW VARIABLES LIKE 'Last_query_cost';
Q: 那么,MySQL是如何预测成本的呢?
A: MySQL根据一系列统计信息计算得来:每个表或页面个数,索引基数,索引和数据行的长度,索引分布情况等。评估成本不考虑缓存,假设读取任何数据需要一次磁盘I/O。
可惜MySQL优化器并不是万能的,有诸多因素会导致MySQL选择错误的执行计划,比如统计信息可能不准确,成本估算和实际成有差距等。
更多的了解查询优化器是怎么处理查询语句的,查看MySQL查询优化器
6.查询执行引擎
MySQL根据解析优化阶段生成的执行计划给出的指令逐步执行。
7.返回结果给客户端
- 查询结果返回给客户端,即时查询不需要返回结果集给客户端,也亏返回一些这个查询信息,比如影响的行数。
- 如果查询可以被缓存,这一阶段也会存放结果入缓存。
- MySQL结果集返回是一个增量、逐步返回的过程。一旦处理开始产生第一条结果时,MySQL就开始逐步返回结果集了。这样的好处是,服务器无须存储太多结果而消耗太多内存,二是客户端可以第一时间获得返回结果。
总结
- 当发现MySQL查询效率不高时,考虑两个因素:1.是否请求了不需要的数据?2.是否查询了额外的记录?
- 对待效率不高的语句,考虑语句适当拆分成多个简单的语句。
- MySQL执行过程,看图