MySQL 基础架构图
MySQL分为Server层和存储引擎层两部分
Server层包括连接器、查询缓存、分析器、优化器、执行器等,以及所有内置函数(日期、时间等),所有跨存储引擎的功能都在这一层实现,比如存储过程、触发器、视图等。
存储引擎层负责数据的存储和提取。其架构模式是插件式,支持 InnoDB、MyISAM、Memory等多个存储引擎。MySQL从5.5.5版本默认InnoDB为默认存储引擎。在创建表的时候可以使用 engine=memory指定存储引擎。
Server层
连接器
连接命令:mysql -h$ip -P$port -u$user -p
在TCP握手之后,连接器就要认证身份以及权限,验证完权限就会缓存下来,此时就算更改了此用户的权限,只有再建立新的连接才会使用新的权限设置。
客户端若长时间没有动静,连接器就会断开连接,默认是8小时,这个时间可以通过参数 wait_timeout 控制
建立连接的过程是比较复杂的,使用中需尽量少建立连接的动作,也就是尽量使用长连接。
MySQL在执行过程中临时使用的内存是管理在连接对象里面的,这些资源会在连接断开的时候才释放。所以长连接积累下来会导致占用内存太大,被系统强行杀掉(OOM),现象就是MySQL异常重启了。
解决这个问题可以考虑两种方案:
- 定期断开长连接。使用一段时间,或者程序里面判断执行过一个占用内存的大查询后,断开连接,之后要查询再重连。
- 如果是 MySQL 5.7 或更新版本,可以在每次执行一个比较大的操作后,通过执行 mysql_reset_connection 来重新初始化连接资源。这个过程不需要重连和重新做权限验证,但是会将连接恢复到刚刚创建完时的状态。
查询缓存(8.0 删除)
MySQL拿到一个查询请求后,会先到查询缓存看看是否存在这条语句,存在就直接返回结果。执行过的语句以及结果可能会以key-value形式缓存在内存中,key是查询语句,value是查询结果。
表面看使用查询缓存效率会比较高,但是大多数情况下是不建议使用查询缓存的!
因为查询缓存的时效非常频繁,只要对一个表的更新,这个表上所有的查询缓存都会被清空。除非类似系统配置表不会经常更新才适合使用查询缓存。。
当然可以按需使用。将参数 query_cache_type 设置为 REMAND,这样都不会使用缓存,然后对于需要使用查询缓存的语句使用 select SQL_CACHE * from T
在MySQL 8.0 版本将查询缓存功能删掉了。
分析器
分析器一般是对SQL语句进行解析。
第一步 词法分析:输入的是由多个字符串和空格组成的一条SQL语句,MySQL需要识别里面的字符串分别是什么,代表什么。例如:“select”表示这是一个查询语句,字符串“T”表示表名,字符串“K”表示列字段。
第二步 语法分析:根据此法分析的结果,语法分析器会根据语法规则,判断输入的SQL语句是否符合MySQL语法。若语法不对则会返回“You have an error in your SQL syntax”的错误提醒。
优化器
优化器是处理如何将输入的语句更高效的执行。
- 在有多个索引是,决定使用哪个索引。
- 在一个语句有多表关联的时候,决定各个表的连接顺序。
执行器
在开始执行的时候,要先判断一下用户是否有查询的权限。 若无权限,则会返回错误信息。
打开表的时候,执行器会根据表的引擎定义,去使用这个引擎提供的接口。
select * from T where ID=10对于没有索引的字段,执行器的执行逻辑:
- 调用InnoDB引擎接口获取这个表的第一行,判断ID值是不是10,不是则跳过,是则将这行存在结果集中。
- 调用引擎接口获取“下一行”,重复相同的逻辑,知道获取到这个表的最后一行。
- 执行器将上述遍历过程中所有满足条件的行组成的记录集作为结果集返回客户端。
对于有索引的表,执行逻辑也差不多
- 第一次调用的是“取满足条件的第一行”这个接口
- 循环获取“满足条件的下一行”这个接口。
数据库的慢查询日志中的rows_examine 字段,标识这个语句执行过程中扫描了多少行。就是执行器每次调用引擎取数据时累加的。
在有些场景下,执行器调用一次,在引擎内部则扫描了多行,因此引擎扫描行数跟 rows_examined 并不是完全相同的。