1、SQL 语句执行流程
MySQL 大体上可分为 Server 层和存储引擎层两部分。
Server 层:
� 连接器:TCP 握手后服务器来验证登陆用户身份,A 用户创建连接后,
管理员对 A 用户权限修改了也不会影响到已经创建的链接权限,必须重新
登陆。
� 查询缓存:查询后的结果存储位置,MySQL8.0 版本以后已经取消,因
为查询缓存失效太频繁,得不偿失。
� 分析器:根据语法规则,判断你输入的这个 SQL 语句是否满足 MySQL
语法。
� 优化器:多种执行策略可实现目标,系统自动选择最优进行执行。
� 执行器:判断是否有权限,将最终任务提交到存储引擎。
存储引擎层
负责数据的存储和提取。其架构模式是插件式的,支持 InnoDB、MyISAM、
Memory 等多个存储引擎。现在最常用的存储引擎是 InnoDB,它从 MySQL
5.5.5 版本开始成为了默认存储引擎(经常用的也是这个)。
SQL 执行顺序
2、BinLog、RedoLog、UndoLog
BinLog
BinLog 是记录所有数据库表结构变更(例如 create、alter table)以及表数
据修改(insert、update、delete)的二进制日志,主从数据库同步用到的都
是 BinLog 文件。BinLog 日志文件有三种模式。
STATEMENT 模式
内容:binlog 只会记录可能引起数据变更的 sql 语句
优势:该模式下,因为没有记录实际的数据,所以日志量和 IO 都
消耗很低,性能是最优的
劣势:但有些操作并不是确定的,比如 uuid() 函数会随机产生唯
一标识,当依赖 binlog 回放时,该操作生成的数据与原数据必然
是不同的,此时可能造成无法预料的后果。
ROW 模式
内容:在该模式下,binlog 会记录每次操作的源数据与修改后的目
标数据,StreamSets 就要求该模式。
优势:可以绝对精准的还原,从而保证了数据的安全与可靠,并且
复制和数据恢复过程可以是并发进行的
劣势:缺点在于 binlog 体积会非常大,同时,对于修改记录多、
字段长度大的操作来说,记录时性能消耗会很严重。阅读的时候也
需要特殊指令来进行读取数据。
MIXED 模式
内容:是对上述 STATEMENT 跟 ROW 两种模式的混合使用。
细节:对于绝大部分操作,都使用 STATEMENT 来进行 binlog 的
记录,只有以下操作使用 ROW 来实现:表的存储引擎为 NDB,
使用了 uuid() 等不确定函数,使用了 insert delay 语句,使用了
临时表
主从同步流程:
1、主节点必须启用二进制日志,记录任何修改了数据库数据的事件。
2、从节点开启一个线程(I/O Thread)把自己扮演成 mysql 的客户
端,通过 mysql 协议,请求主节点的二进制日志文件中的事件 。
3、主节点启动一个线程(dump Thread),检查自己二进制日志中
的事件,跟对方请求的位置对比,如果不带请求位置参数,则主节
点就会从第一个日志文件中的第一个事件一个一个发送给从节点。
4、从节点接收到主节点发送过来的数据把它放置到中继日志(Relay
log)文件中。并记录该次请求到主节点的具体哪一个二进制日志文
件内部的哪一个位置(主节点中的二进制文件会有多个)。
5、从节点启动另外一个线程(sql Thread ),把 Relay log 中的
事件读取出来,并在本地再执行一次。
mysql 默认的复制方式是异步的,并且复制的时候是有并行复制能力的。主库
把日志发送给从库后不管了,这样会产生一个问题就是假设主库挂了,从
库处理失败了,这时候从库升为主库后,日志就丢失了。由此产生两个概
念。
1. 全同步复制
主库写入 binlog 后强制同步日志到从库,所有的从库都执行完成后
才返回给客户端,但是很显然这个方式的话性能会受到严重影响。
1. 半同步复制
半同步复制的逻辑是这样,从库写入日志成功后返回 ACK 确认给主
库,主库收到至少一个从库的确认就认为写操作完成。
还可以延伸到由于主从配置不一样、主库大事务、从库压力过大、网络震
荡等造成主备延迟,如何避免这个问题?主备切换的时候用可靠性优先原则还
是可用性优先原则?如何判断主库 Crash 了?互为主备情况下如何避免主备
循环复制?被删库跑路了如何正确恢复?(⊙o⊙)… 感觉越来越扯到 DBA
的活儿上去了。
RedoLog
可以先通过下面 demo 理解:
饭点记账可以把账单写在账本上也可以写在粉板上。有人赊账或者还账的话,
一般有两种做法:
1、直接把账本翻出来,把这次赊的账加上去或者扣除掉。
2、先在粉板上记下这次的账,等打烊以后再把账本翻出来核算。
生意忙时选后者,因为前者太麻烦了。得在密密麻麻的记录中找到这个人
的赊账总额信息,找到之后再拿出算盘计算,最后再将结果写回到账本上。
同样在 MySQL 中如果每一次的更新操作都需要写进磁盘,然后磁盘也要找
到对应的那条记录,然后再更新,整个过程 IO 成本、查找成本都很高。而
粉板和账本配合的整个过程就是 MySQL 用到的是 Write-Ahead Logging 技
术,它的关键点就是先写日志,再写磁盘。此时账本 = BinLog,粉板 =
RedoLog。
1、 记录更 新时,InnoDB 引擎就会先把记录写到 RedoLog(粉 板)
里面,并更新内存。同时,InnoDB 引擎会在空闲时将这个操作记录
更新到磁盘里面。
2、 如果更新太多 RedoLog 处理不了的时候,需先将 RedoLog 部
分数据写到磁盘,然后擦除 RedoLog 部分数据。RedoLog 类似转盘。
RedoLog 有 write pos 跟 checkpoint
write pos :是当前记录的位置,一边写一边后移,写到第 3 号文
件末尾后就回到 0 号文件开头。
check point:是当前要擦除的位置,也是往后推移并且循环的,擦
除记录前要把记录更新到数据文件。
write pos 和 check point 之间的是粉板上还空着的部分,可以用来记录新的
操作。如果 write pos 追上 checkpoint,表示粉板满了,这时候不能再执行
新的更新,得停下来先擦掉一些记录,把 checkpoint 推进一下。
有了 redo log,InnoDB 就可以保证即使数据库发生异常重启,之前提交的
记录都不会丢失,这个能力称为 crash-safe。
redolog 两阶段提交:
为了让 binlog 跟 redolog 两份日志之间的逻辑一致。提交流程大致如下:
1 prepare 阶段 --> 2 写 binlog --> 3 commit
1. 当在 2 之前崩溃时,重启恢复后发现没有 commit,回滚。备份恢复:
没有 binlog 。一致
2. 当在 3 之前崩溃时,重启恢复发现虽没有 commit,但满足 prepare
和 binlog 完整,所以重启后会自动 commit。备份:有 binlog. 一致
binlog 跟 redolog 区别:
1. redo log 是 InnoDB 引擎特有的;binlog 是 MySQL 的 Server 层实现
的,所有引擎都可以使用。
2. redo log 是物理日志,记录的是在某个数据页上做了什么修改;binlog
是逻辑日志,记录的是这个语句的原始逻辑,比如给 ID=2 这一行的 c 字段
加 1。
3. redo log 是 循 环写的,空 间 固 定会用完; binlog 是可 以追加写入 的 。
追加写是指 binlog 文件写到一定大小后会切换到下一个,并不会覆盖以前
的日志。
UndoLog
UndoLog 一般是逻辑日志,主要分为两种:
1. insert undo log