一、基础架构:一条SQL查询语句是如何执行的?
下面我给出的是 MySQL 的基本架构示意图,从中你可以清楚地看到 SQL 语句在 MySQL 的各个功能模块中的执行过程。逻辑上来说,MySQL 可以分为 Server 层(主要做的是 MySQL 功能层面的事情)和存储引擎层(负责存储相关的具体事宜)两部分。
从图中不难看出,不同的存储引擎共用一个Server 层,也就是从连接器到执行器的部分。
1.1 面试问答
(1)“为什么不建议使用查询缓存?”
答:只要有对一个表的更新,这个表上所有的查询缓存都会被清空。对于更新压力大的数据库来说,查询缓存的命中率会非常低。除非你的业务就是有一张静态表,很长时间才会更新一次。比如,一个系统配置表,那这张表上的查询才适合使用查询缓存。
二、 日志系统:一条SQL更新语句是如何执行的?
update语句执行过程:分析器会通过词法和语法解析知道这是一条更新语句、优化器决定要使用 ID (如果 ID 是主键的话)这个索引、执行器负责找到这一行然后更新。但与查询流程不一样的是,更新流程还涉及两个重要的日志模块,redo log(重做日志)和 binlog(归档日志)。
2.1 理解 redo log
《孔乙己》这篇文章中,酒店掌柜有一个粉板和一个账本来记录客人的赊账记录,先写粉板,等不忙的时候再写账本。如果今天赊账的不多,掌柜可以等打烊后再整理。但如果某天赊账的特别多,粉板写满了,又怎么办呢?这个时候掌柜只好放下手中的活儿,把粉板中的一部分赊账记录更新到账本中,然后把这些记录从粉板上擦掉,为记新账腾出空间。
Innodb引擎有一个redo log日志模块,先写日志,再写磁盘(WAL 技术,WAL 的全称是 Write-Ahead Logging)。InnoDB 的 redo log 是固定大小的,比如可以配置为一组 4 个文件,每个文件的大小是 1GB,那么这块“粉板”总共就可以记录 4GB 的操作。从头开始写,写到末尾就又回到开头循环写,如下面这个图所示。
2.2 理解 bin log
上面我们聊到的粉板 redo log 是 InnoDB 引擎特有的日志,而 Server 层也有自己的日志,称为 binlog(归档日志)。 这两种日志有以下三点不同。
- redo log 是 InnoDB 引擎特有的;binlog 是 MySQL 的 Server 层实现的,所有引擎都可以使用。
- redo log 是物理日志,记录的是“在某个数据页上做了什么修改”;binlog 是逻辑日志,记录的是这个语句的原始逻辑,比如“给 ID=2 这一行的 c 字段加 1 ”。
- redo log 是循环写的,空间固定会用完;binlog 是可以追加写入的。“追加写”是指 binlog 文件写到一定大小后会切换到下一个,并不会覆盖以前的日志。
2.3 面试问答
(1)redo log 要写到磁盘,数据也要写磁盘,为什么要多此一举?
答:1. 将写操作从「随机写」变成了「顺序写」,提升 MySQL 写入磁盘的性能。2. 记录在了日志上,实现事务的持久性,让 MySQL 有 crash-safe 的能力,能够保证 MySQL 在任何时间段突然崩溃,重启后之前已提交的记录都不会丢失;
参考:
- 《MySQL 实战 45 讲》林晓斌 网名丁奇,前腾讯云数据库负责人
- 小林 coding xiaolincoding.com/mysql/log/h…