注本文是本人在学习Mysql的过程中记忆巩固,参考许多资料并非个人原创,下面将列出本人参考资料:
小林coding 图解Mysql
《Mysql是怎样运行的:从根上理解Mysql》
一条SQL的执行过程
首先连接到mysql->查询缓存->解析器->预处理器->优化器->执行器
查询缓存:
首先mysql看看SQL语句是否是查询语句,如果不是则继续执行,如果是select语句则需要查询缓存。mysql的缓存是以key-value形式保存,查询缓存里是否有该语句,如果有则直接返回结果,如果没有则继续执行,得到结果后将数据返回并保存在缓存中。
mysql的缓存的计很巧妙,但是有个很鸡肋的事情,只要mysql的表数据更新该表的缓存就会被清空,故mysql8.0移除了查询缓存这一步骤,但是mysql缓存中的各种设计仍然值得我们学习,LRU算法的设计,缓存与数据的一致性的设计等。
解析器:
解析器主要做两件事,根据SQL语句构建语法树、检查SQL语句是否有错误
根据SQL语句识别关键字构建出语法树,方便后续模块读取。
检查SQL语句是否有错误,如果SQL语法出错将会在此步报错。
预处理器:
检查表明是否存在,将 * 替换为所有具体字段
优化器:
优化器负责根据SQL语句和表的结构选出构建出效率最快的执行计划,例如走不走索引,走哪个索引等,还会对SQL不合理的地方做出一定的优化,顺便一提mysql本身对部分查询存在天然优化。
使用explain关键字来查看当前SQL的执行计划(重要)
执行器:
执行器根据优化给出的执行计划进行执行,并将结果返回。
InnoDB的行存贮格式
开门见山,InnoDB的行存贮:Compact、Redundant、Dynamin、Compressed四种
常用的有:Compact、Dynamin、Compressed三种,其中Dynamin为默认使用(5.7),其他两种基本上与Compact类似只是在处理行溢出时的方式不一样。
个人能力原因直接将图列在此:
Compact行格式大概如图所示,先解释图中字段,下面会解释行记录信息。
边长字段长度列表:例如varChar()等字段长度不确定,故需要在行中记录该行中变长字段所占用的真实字节数,需要注意的是存贮将按照列表倒叙存贮,例如:列1、列2、列三都为变长字段则存贮时应为:列3、列2、列1。
NULL值列表:行中可能会含有允许为NULL的字段,如果某一列为NULL则InnoDB不会存贮值会NULL列表中将该列表示出来,值得注意的是该列表也是倒序。
记录头信息
记录头信息中包含很多信息,慢慢一个个说,先将总体列在下面:
预留位1与预留位2在5.7的版本种没有使用
delete_make:用来标记删除的,Mysql中删除并不会马上删除而是先打上标记,后续才会删除,其中被标记删除的将会维护一个链表,如果有有添加的行可以先使用被标记删除的行,这方面和后面的redoLog日志有关。
min_rec_make:B+树种非叶子节点中最小记录会标记此位,与后面的页结构有关。
n_owned:该记录拥有的记录数,与页结构有关。
heap_no:标记该行在堆中的相对位置。
record_type:标记该行的类型,0:普通记录,1:B+树非叶子节点记录,2:最小记录,3:最大记录,与页结构有关。
next_record:下一条记录的相对位置,故innoDB是以链表的形式将行记录相连。
除了上述表中表示的字段外InnoDB还会在行中添加三个或两个额外字段(隐藏列):
row_id:行ID,唯一标识一条记录,需要注意的是当表中无主键时才会添加此行。
transaction_id:事务ID,与InnoDB的MVCC机制有关。
roll_pointer:回滚指针,与MVCC机制的实现有关,undoLog日志有关。
接下来介绍其他三种行格式
Redundant:一种古老的行格式
待定
Dyamin与Compressed
两种行格式其实与Compact区别不大,只是在关于行溢出的处理方式不一样
Compact发生行溢出时会将前768个字节与页地址放在行中,剩余的数据将放在页地址的页中。
Dyamin是行中只存放页地址,将数据都放在其他页中。
Compressed与Dyamin相同,还会采用压缩算法以节省空间。