请求−−>缓存−−>解析器−−>预处理器−−>查询优化器−−>将解析树生成执行计划−−>执行计划调用存储引擎API执行 −−>索引或查询数据表−−>响应数据
缓存
- 一个对英文大小写敏感的hash表。对sql做hash运算,精确匹配。
- 缓存命中,则不执行后续解析、预处理、优化。但在返回数据前会校验权限。
sql解析器
将sql解析按关键字解析成解析树,然后校验:
- 是否存在错误的关键字
- 关键字顺序是否正确
- 引号是否匹配
预处理器
- 验证表是否存在
- 列是否存在
- 解析名和别名是否存在歧义
- 验证权限是否满足
通过解析器和预处理器得到一个合法的解析树交给查询优化器
查询优化器
优化标准依赖mysql的成本算法,所以可能存在优化后并不是我们认为的最优。并且优化器没有考虑并发查询带来的锁消耗问题
优化内容:
- 优化表关联顺序、外关联变内关联
- 当查询max() min()时,如果有索引,直接使用索引最左或者最右返回。这时候执行计划可以看到“select tables optimized away”,表示优化器移除了该表查询,使用一个常数取代之。
- 等价变换
- 子查询优化
- 覆盖索引优化,当发现存在索引可以覆盖这次查询,将使用覆盖索引
- 提前终止,当使用了limit 或者发现一个不成立条件。
- In比较,mysql的in查询不等于多个or查询,mysql优化器会将in做排序,在做二分查找,确实是否满足条件,时间复杂度是Ologn,而or是On复杂度,in值越多比or性能越好。
mysql糟糕的子查询5.6以前好像有变化,待查证
最糟糕的是在where条件中in的子查询,一般我们会认为他应该先执行子查询获取到in列表,再外层查询。
而mysql是将外层查询压入内层查询中实现的,也就是循环嵌套关联查询。
所以当外层查询返回的是一个很大的列表时,性能极低。
count函数
- count(*)并不是统计所有列非Null,而且忽略所有列,只统计行数。
关联查询优化
- A B两个表关联查询,要在on后面的关联字段加索引。
- 而且索引只需要建立在后关联的表的列上。待验证
- 确保group by 和order by只涉及到一个表中的列。这样mysql才有可能使用索引来优化这个过程。