基础架构&日志
# 基础架构&日志
# 查询语句
# Server层

- 连接器
1.建立连接之后,就不能再修改权限;只能重新建立新的连接才能够生效。
2.只有释放连接之后才会真正释放资源,如果长时间占用长连接不释放MySQL内存,会导致OOM。因此需要定期断开长连接,程序里面可以判断执行过一个占用内存的大查询之后,断开连接。
- 查询缓存
先前执行过的结果会以key-value的形式保存。key为查询语句,value为对应的查询结果。
⚠️⚠️⚠️一般不建议使用查询缓存,因为使用更新语句之后会清空所有表的缓存数据。对于热点数据而言,缓存命中率比较低。
- 分析器
MySQL会对你的查询语句进行解析,具体分为两个步骤:
1.词法分析:从你的字符串语句当中识别出表名、字段名。
2.语法分析:判断输入的MySQL语句是否符合语法规则。语句会报错“You have an error in your SQL syntax”
- 优化器
表中有多个索引时,优化器决定使用哪一个方案。
- 执行器
执行前会先判断是否有查询权限,如果有权限则会调用InnoDB引擎接口执行查找语句,分为有无索引两种情况:
1.无索引的表:调用“获取表中这一行的数据”这一接口,然后判断是否符合where限制;循环调用“获取下一行数据”接口并执行先相同的判断逻辑。
2.有索引的表:调用“获取满足条件的第一行”这一接口,依次读取下一行。
# 存储引擎层
InnoDB、MyISAM、Memory(基于内存进行存储)
# 更新语句
设计理念:通过日志文件记录当前所有的操作,然后根据日志文件写入磁盘。降低了IO成本、查找成本,提升了效率,同时保存副本以应对写数据时数据库崩溃的问题,用于恢复数据。
WAL(Write-Ahead Logging)机制:预写日志。核心在于先写日志,再写磁盘。
更新语句会将对应数据表的查询缓存的所有数据删除,所有缓存失效。
# 🔥redo log(InnoDB引擎特有)
物理日志:记录的是在哪一个数据页做了什么修改。日志文件固定大小会使用完。因此所有操作记录写满之后需要清除空间。先写日志再写磁盘。
crash-safe:只要redo log写了新的数据,即使数据库异常重启,数据也能够根据redo log进行恢复。(binlog并没有该能力)

checkpoint:当前要擦除的位置
write pos:当前记录的位置
当write pos追上checkpoint之后,则说明当前当前日志已经写满了,因此checkpoint需要先擦掉一些记录之后才能继续执行新的更新。
# 🔥bin log(Server层)
逻辑日志:记录的相当于是SQL语句的原始逻辑内容。日志是追加写的,写完之后会自动切换到下一个。具有"归档"功能,而redo log并不能持久保存。
# 🔥执行流程
1.执行器首先拿到对应的数据(缓存或者是磁盘),并进行修改。
2.调用InnoDB引擎接口,将数据写入到内存,并且会将更新记录更新到redo log。
3.redo log完成后,InnoDB引擎会提醒执行器,随时可以提交事务。此时还处于prepare状态
4.执行器受到通知后,会生成该操作的bin log,并将日志写入磁盘。
5.执行器会调用InnoDB引擎的提交事务接口。将刚刚写入的redo log改成提交状态。
redo log两阶段提交:首先prepare和commit。目的是为了保证redolog和binlog两份文件逻辑一致。如果不采用两阶段提交,可能会存在两种情况:
- 先redo log后bin log:crash之后,数据库能够恢复最新的数据。但是bin log中记载的还是旧数据。如果通过bin log将数据导入临时库,则该库和主数据库对比就没有最新的数据。
- 先bin log后redo log:crash后,由于redo log没有写入最新的数据,因此恢复的数据库是旧数据。而通过bin log构建的临时库则是新数据。
因此,只要涉及到使用binlog搭建备用库(从库),恢复临时库,就会导致主从不一致的问题。两阶段提交是跨系统维持数据逻辑一致性时常用的一个方案。
# 🔥备份时间
一天一备份和一周一备份相比,”最长恢复时间“更短,也就是距离上一次可备份时间的时间间隔更短;但是因为一天一备的备份次数多,因此需要的存储空间也会更多。
从业务角度上看,一天一备更适用于那些被频繁修改的热点数据,这样需要通过备份数据恢复时,所使用的数据可以保证是最新的。
# 细节
# 1.两阶段提交的合理性
下图是两阶段提交发生崩溃的两个不同的时刻:
- A时刻发生崩溃后,恢复时由于redo log处于prepare状态,同时bin log也没有写,因此事务会回滚。
- B时刻发生崩溃后,虽然redo log仍处于prepare状态,但MySQL会验证bin log的完整性,如果是完整的则会提交事务。

换而言之,prepare阶段的redo log加上完整的bin log,重启后数据就能恢复。而之所以需要两阶段提交,是因为事务提交后就不能进行回滚,提交redo log后如果写bin log失败,那么就会无法回滚数据,出现不一致问题。
事实上两阶段提交是经典分布式问题,只有A确认自己“OK”了,那么B好了后才会提交。也就是确保双方的状态都是没问题的。
# 2.redo log与bin log功能
# 2.1redo log
核心作用是用于恢复数据。redo log因为是循环写,上面只会记录未刷盘的数据,经过刷盘持久化后的数据会从redo log删除。而bin log是追加写数据,无法判断上面哪些数据是刷盘后,哪些是没刷盘的。
当crash崩溃后,要想恢复已经写入日志但未刷盘的数据,bin log显然做不到;而对于redo log只需要将所有日志中的数据恢复到内存,并刷盘即可。这就是为什么redo log 具有crash safe的能力。具体包括以下几种情况:
时刻A——change buffer写入,redo log buffer未提交,bin log未fsync到磁盘:崩溃后内存所有日志和数据丢失。
时刻B——change buffer写入,redo log buffer 未提交,bin log已经fsync到磁盘:崩溃后通过bin log恢复redo log,然后再从redo log恢复change buffer。
redo log和bin log都已经持久化:崩溃后将磁盘旧的数据页读入内存,直接根据redo log恢复更新数据,最后将脏页落盘。
# 2.2bin log
作用一:归档,保留历史日志。
作用二:高可用方面,依赖于binlog复制进行备份数据库。