MySQL执行一个查询的过程,如下图所示:
- 客户端发送一条查询给服务器
- 服务器先检查查询缓存,如果命中了缓存,则立刻返回存储在缓存中的结果。否则进入下一阶段
- 服务器端进行SQL解析、预处理,再由优化器生成对应的执行计划
- MySQL根据优化器生成的执行计划,调用存储引擎的API来执行查询
- 将结果返回给客户端
MySQL客户端/服务端通信协议
MySQL客户端和服务端之间的通信协议是“半双工”的,这意味着,在任何一个时刻,要么是由服务器向客户端发送数据,要么是由客户端想服务器发送数据,这两个动作不能同时发生。所以,无法也无须将一个消息切成小块独立发送
查询缓存
在解析一个查询语句之前,如果查询缓存是打开的,那么MySQL会优先检查这个查询是否命中缓存的数据。
如果当前查询命中查询缓存,那么在返回查询结果之前MysQL会检查一次用户权限。如果权限没有问题,MySQL会跳过所有其他阶段,直接从缓存中拿到结果返回给客户端
查询优化处理
在这个阶段,包含多个子阶段:解析SQL、预处理、优化SQL执行计划。这个过程中任何错误都可能终止查询
语法解析器和预处理
首先MySQL通过关键字将SQL语句进行解析,并生成一颗对应的“解析树”。MySQL解析器将使用MySQL语法规则校验和解析校验。
查询优化器
如果语法树被认为是合法的,那么将由优化器转化成执行计划。
下面是一些MySQL能够处理的优化类型:
- 重新定义关联表的顺序
- 将外链接转化成内链接
并不是所有的OUTER JOIN语句都必须以外链接的方式执行。例如WHERE条件、库表结构都可能会让一个外链接等价于一个内链接。MySQL能够识别这点并重写查询,让其可以调整关联顺序
- 使用等价变换规则
MySQL可以使用一些等价变换来简化并规范表达式。它可以合并和减少一些比较。比如(5=5 AND a>5) 将被改写为a>5。
-
优化COUNT(),MIN()和MAX() 索引和列是否可为空通常可以帮助MySQL优化这类表达式。例如,要找到某一列的最小值,只需要查询对应B-Tree索引最左端的记录,MySQL可以直接获取索引的第一行记录。如果要查询最大值,也只需要读取B-Tree索引的最后一条记录。
-
预估并转化为常数表达式
- 覆盖索引扫描
- 子查询优化 MySQL在某些情况下将子查询转换成效率更高的形式
- 提前终止查询 在发现已经满足查询需求的时候,MySQL总是能够立即终止查询。比如limit子句,还比如不成立的条件
SELECT * FROM film where film_id=-1;
- 等值传播
- 列表IN()比较