Mysql

总体来说,MYSQL分为Server层和存储引擎层两部分。Server 层包括连接器、查询缓存、分析器、优化器、执行器等,涵盖 MySQL 的大多数核 心服务功能,以及所有的内置函数(如日期、时间、数学和加密函数等),所有跨存储引擎 的功能都在这一层实现,比如存储过程、触发器、视图等。

存储引擎层负责数据的存储和提取。其架构模式是插件式的,支持 InnoDB、MyISAM、 Memory 等多个存储引擎。现在最常用的存储引擎是 InnoDB,它从 MySQL 5.5.5 版本开 始成为了默认存储引擎。不同的存储引擎公用同一个Server层。

连接器

第一步,你会先连接到这个数据库上,这时候接待你的就是连接器。连接器负责跟客户端建 立连接、获取权限、维持和管理连接。show processlist命令可以看到连接状态。

查询缓存

MySQL 拿到一个查询请求后,会先到查询缓存看看,之前是不是执行过这条语句。之前执 行过的语句及其结果可能会以 key-value 对的形式,被直接缓存在内存中。key 是查询的 语句,value 是查询的结果。如果你的查询能够直接在这个缓存中找到 key,那么这个 value 就会被直接返回给客户端。如果语句不在查询缓存中,就会继续后面的执行阶段。执行完成后,执行结果会被存入查询 缓存中。你可以看到,如果查询命中缓存,MySQL 不需要执行后面的复杂操作,就可以直接返回结果,这个效率会很高。

大多数情况不建议使用缓存,因为弊大于利。查询缓存的失效非常频繁,只要有对一个表的更新,这个表上所有的查询缓存都会被清空。 因此很可能你费劲地把结果存起来,还没使用呢,就被一个更新全清空了。对于更新压力大 的数据库来说,查询缓存的命中率会非常低。

分析器

分析器先会做“词法分析”。你输入的是由多个字符串和空格组成的一条 SQL 语句, MySQL 需要识别出里面的字符串分别是什么,代表什么。做完了这些识别以后,就要做“语法分析”。根据词法分析的结果,语法分析器会根据语法 规则,判断你输入的这个 SQL 语句是否满足 MySQL 语法。

优化器

经过分析器,MYSQL知道客户端要干什么了,在开始执行前,还需要先经过优化器的处理。优化器是在表里面有多个索引的时候,决定使用哪个索引;或者在一个语句有多表关联 (join)的时候,决定各个表的连接顺序。

执行器

开始执行的时候,要先判断一下你对这个表 T 有没有执行查询的权限,如果没有,就会返 回没有权限的错误。如果有权限,就打开表继续执行。打开表的时候,执行器就会根据表的引擎定义,去使用这 个引擎提供的接口。

日志系统

redo log

更新流程涉及两个重要的日志模块,redo log重做日志 和binlog 归档日志

在 MySQL 里,如果每一次的更新操作都需要写进磁盘,然后磁盘也要找到对应的那条记录,然后再更新,整个过程 IO 成本、查找成本都很高。为了解决问题,MYSQL采用了粉板(暂存)加账本的方法来提升效率。也就是MySQL 里经常说到的 WAL 技术,WAL 的全称 是 Write-Ahead Logging,它的关键点就是先写日志,再写磁盘,也就是先写粉板,等不忙的时候再写账本。

具体来说,当有一条记录需要更新的时候,InnoDB 引擎就会先把记录写到 redo log(粉板)里面,并更新内存,这个时候更新就算完成了。同时,InnoDB引擎会在适当的时候, 将这个操作记录更新到磁盘(账本)里面,而这个更新往往是在系统比较空闲的时候做,这就像打烊以后掌柜做的事。

如果粉板写满了,就只能把粉板中的一部分记录更新到账本中,然后把这些记录从粉板中擦掉,为新账腾出空间。与此类似,InnoDB 的 redo log 是固定大小的,比如可以配置为一组 4 个文件,每个文件 的大小是 1GB,那么这块“粉板”总共就可以记录 4GB 的操作。从头开始写,写到末尾就 又回到开头循环写,

write pos 是当前记录的位置,一边写一边后移,写到第 3 号文件末尾后就回到 0 号文件开头。checkpoint 是当前要擦除的位置,也是往后推移并且循环的,擦除记录前要把记录 更新到数据文件。write pos 和 checkpoint 之间的是“粉板”上还空着的部分,可以用来记录新的操作。如 果 write pos 追上 checkpoint,表示“粉板”满了,这时候不能再执行新的更新,得停下 来先擦掉一些记录,把 checkpoint 推进一下。

有了 redo log,InnoDB 就可以保证即使数据库发生异常重启,之前提交的记录都不会丢 失,这个能力称为crash-safe。

binlog

MySQL 整体来看,其实就有两块:一块是 Server 层,它主要做的是 MySQL 功能层面的事情;还有一块是引擎层,负责存储相关的具体事宜。上面我们聊到的 粉板 redo log 是 InnoDB 引擎特有的日志,而 Server 层也有自己的日志,称为 binlog(归档日志)。

  • redo log 是InnoDB引擎特有的日志,而Server层也有自己的日志,称为binlog。两种日志有以下三种不同之处。

  • redo log 是 InnoDB 引擎特有的;binlog 是 MySQL 的 Server 层实现的,所有引擎都 可以使用。

  • redo log 是物理日志,记录的是“在某个数据页上做了什么修改”;binlog 是逻辑日 志,记录的是这个语句的原始逻辑,比如“给 ID=2 这一行的 c 字段加 1 ”。 3. redo log 是循环写的,空间固定会用完;binlog 是可以追加写入的。“追加写”是指 binlog 文件写到一定大小后会切换到下一个,并不会覆盖以前的日志。

一个update的例子

1
2
3
4
5
6
7
8
9
1. 执行器先找引擎取 ID=2 这一行。ID 是主键,引擎直接用树搜索找到这一行。如果 ID=2 这一行所在的数据页本来就在内存中,就直接返回给执行器;否则,需要先从磁盘 读入内存,然后再返回。

2. 执行器拿到引擎给的行数据,把这个值加上 1,比如原来是 N,现在就是 N+1,得到新 的一行数据,再调用引擎接口写入这行新数据。

3. 引擎将这行新数据更新到内存中,同时将这个更新操作记录到 redo log 里面,此时 redo log 处于 prepare 状态。然后告知执行器执行完成了,随时可以提交事务。

4. 执行器生成这个操作的 binlog,并把 binlog 写入磁盘。

5. 执行器调用引擎的提交事务接口,引擎把刚刚写入的 redo log 改成提交(commit)状 态,更新完成。

将 redo log 的写入拆成了两个步骤: prepare 和 commit,这就是”两阶段提交”。

binlog 会记录所有的逻辑操作,并且是采用“追加写”的形式。如果你 的 DBA 承诺说半个月内可以恢复,那么备份系统中一定会保存最近半个月的所有 binlog,同时系统会定期做整库备份。