查询缓存
在解析一个查询语句前 , 如果查询缓存是打开的 , 那么MySQL会检查这个查询语句是否命中查询缓存中的数据 。如果当前查询恰好命中查询缓存 , 在检查一次用户权限后直接返回缓存中的结果 。这种情况下 , 查询不会被解析 , 也不会生成执行计划 , 更不会执行 。
MySQL将缓存存放在一个引用表(不要理解成table , 可以认为是类似于HashMap的数据结构) , 通过一个哈希值索引 , 这个哈希值通过查询本身、当前要查询的数据库、客户端协议版本号等一些可能影响结果的信息计算得来 。所以两个查询在任何字符上的不同(例如:空格、注释) , 都会导致缓存不会命中 。
如果查询中包含任何用户自定义函数、存储函数、用户变量、临时表、MySQL库中的系统表 , 其查询结果都不会被缓存 。比如函数NOW()或者CURRENT_DATE()会因为不同的查询时间 , 返回不同的查询结果 , 再比如包含CURRENT_USER或者CONNECION_ID()的查询语句会因为不同的用户而返回不同的结果 , 将这样的查询结果缓存起来没有任何的意义 。
既然是缓存 , 就会失效 , 那查询缓存何时失效呢?MySQL的查询缓存系统会跟踪查询中涉及的每个表 , 如果这些表(数据或结构)发生变化 , 那么和这张表相关的所有缓存数据都将失效 。正因为如此 , 在任何的写操作时 , MySQL必须将对应表的所有缓存都设置为失效 。如果查询缓存非常大或者碎片很多 , 这个操作就可能带来很大的系统消耗 , 甚至导致系统僵死一会儿 。而且查询缓存对系统的额外消耗也不仅仅在写操作 , 读操作也不例外:
- 任何的查询语句在开始之前都必须经过检查 , 即使这条SQL语句永远不会命中缓存
- 如果查询结果可以被缓存 , 那么执行完成后 , 会将结果存入缓存 , 也会带来额外的系统消耗
- 用多个小表代替一个大表 , 注意不要过度设计
- 批量插入代替循环单条插入
- 合理控制缓存空间大小 , 一般来说其大小设置为几十兆比较合适
- 可以通过SQL_CACHE和SQL_NO_CACHE来控制某个查询语句是否需要进行缓存

文章插图
当然查询缓存系统本身是非常复杂的 , 这里讨论的也只是很小的一部分 , 其他更深入的话题 , 比如:缓存是如何使用内存的?如何控制内存的碎片化?事务对查询缓存有何影响等等 , 读者可以自行阅读相关资料 , 这里权当抛砖引玉吧 。
语法解析和预处理

文章插图
MySQL通过关键字将SQL语句进行解析 , 并生成一颗对应的解析树 。
这个过程解析器主要通过语法规则来验证和解析 。比如SQL中是否使用了错误的关键字或者关键字的顺序是否正确等等 。预处理则会根据MySQL规则进一步检查解析树是否合法 。比如检查要查询的数据表和数据列是否存在等 。
SQL总体执行流程图

文章插图
查询优化

文章插图
经过前面的步骤生成的语法树被认为是合法的了 , 并且由优化器将其转化成查询计划 。多数情况下 , 一条查询可以有很多种执行方式 , 最后都返回相应的结果 。优化器的作用就是找到这其中最好的执行计划 。
推荐阅读
- mysql千万级数据量插入的几种方案耗时,看完就知道如何选择
- MySQL的优化,看这篇文章就够了
- PHP的微服务框架预览
- MySQL性能优化分区之实战
- MacOS下brew安装mysql5.7数据库
- 电商支付架构设计
- 详解Docker架构原理、功能及使用
- mysql导入数据,涉及到时间转换,乱码问题解决
- 如何基于 MySQL 主从模式搭建上万并发的系统架构?
- 你知道CentOS 6和 CentOS 7的区别吗?
