MySQL的基本结构
Server层
有以下组件
连接器
在客户端登录Mysql时进行身份认证和权限确认
缓存
在进行select语句时,会优先查询的区域,同时在发现查询不到时会从表中查询并缓存到这个组件。顾名思义。
分析器
准确的说是语义分析器,即分析sql语句是否正确
优化器
优化sql语句到底层最优的方式从而执行sql语句,比如如何选择索引,如何联表,但只是理论最优,不一定是实际最优。
执行器
执行语句并从存储引擎层获取数据返回,与引擎交互的层。
binlog
熟悉的都知道,日志模块,记录日志
Server层主要实现了存储过程、触发器、视图、函数等功能。
存储引擎层
简单说就是负责数据的读和写,可以替换,有很多类型的存储引擎,默认情况下为InnoDB,比较常用的还有MyISAM、Memory等多个存储引擎。
MyISAM
不支持事务和行级锁,因此不支持并发事务,而且无法保证可用性,容错性很差。但是也有可取之处,比如全文索引、压缩、空间函数等,性能很好。
InnoDB
支持行级锁,支持事务,外键等功能,具有安全回滚的能力。
同时也支持MVCC:可以使用乐观锁和悲观锁来实现。只在读取已提交和可重复读两个隔离级别下工作。(数据库事务四个隔离级别,读取未提交,读取已提交,可重复读,可串行化)
效率上则未必比MyISAM弱,要看具体的实际场景。
两者在索引方面的区别
两者都使用的B+树(可自行查询),MyISAM引擎的叶节点data域存放数据的地址。被称为非聚簇索引。InnoDB数据文件本身是索引文件,索引文件和数据文件分离,树的叶节点data域保存了完整的数据记录,数据文件本身是主索引,而数据表主键则是索引的键值,被称为聚簇索引。
实例分析
大的来分,sql语句不外乎两种,查询与修改,因为增删改都可以算是修改。
查询语句
举个简单例子如下
select * from student Tate where Tate.sex='M' and Tate.num=1;
执行流程如下:
- 检查权限。若无则报错,若正确则下一步
- 查询缓存(8.0及更高不再查询)。如果有则直接返回,若无,继续下一步。
- 进入分析器分析词法,提取出语句中的操作,先找到select确认为查询操作,后找到from后的表名student进行查询,然后判断是否存在语法问题,若有则报错,无则继续下一步。
- 这就到了优化器的层面,确认理论最优的查询方案,比如这条语句,我们有两种做法,把性别=M的全部找出来再找num=1的或是把num=1的先找出来再找性别M的(再者也有联表顺序之类的语句也会有不同的执行过程)通过内部的相关算法选择理论上认为最优的过程进行执行操作,然后进入下一步
- 接下去再次进行权限检查去调用底层的存储引擎提供的相关接口,然后返回结果。
修改语句
同样举个例子
update student Tate set Tate.money=10000 where Tate.num=1;
和查询不一样,这里面主要涉及数据的修改,为了数据库的安全回复,这里就要用到上面提到的binlog组件,也就是日志组件,当然引擎也存在相应的日志组件。
具体过程如下:
- 查询num=1的所有数据(与查询语句类似)
- 根据查询语句修改money字段,调用引擎接口保存数据,在引擎的日志模块中记录,并返回执行器信号,记录此时处于“准备”阶段(还未commit)
- 执行器收到信号后将操作记录到binlog日志组件中,然后再次调用引擎接口,设置引擎的日志模块中这条日志为commit状态。
异常处理
因为两个日志的存在会引发很多问题。
为什么存在两个日志
首先先弄清楚这个问题,其实是可以不存在两个日志的,这应该算是个版本更新的问题,5.5之前版本Mysql采用的是MyISAM引擎,而上面提到了,这个是不存在日志模块的,而InnoDB是存在的,名字叫redo log。
极端情况
redo log正在准备阶段,但是binlog写完还未调用引擎接口的时候宕机了,造成数据的不一致。
解决方法
重启之后Mysql会对redolog进行检查,如果发现是commit状态,就提交事务。
如果发现是准备阶段,那就再去判断binlog是否已经存在完整的记录,如果是则修改redolog为commit,如果不是则进行回滚,重新执行事务。