一、MySQL Binlog 三种存储格式
binlog 一共3 种格式,由参数binlog_format控制:
- 1.STATEMENT(语句级)
- 2.ROW(行级)
- 3.MIXED(混合模式)
1. STATEMENT(statement-based replication,SBR)语句模式
记录执行的SQL语句本身。
特点
- • 日志体积小,一条SQL修改多行只存一条语句
- • 节约网络IO
缺点(致命问题)
- • 存在数据不一致风险:非确定性函数执行结果主从不一样
NOW()、RAND()、UUID()、LIMIT、触发器、存储过程 - • 无法精准同步基于行的修改(例如
UPDATE ... LIMIT)
MySQL 5.1 默认早期版本使用,现在几乎不推荐生产使用。
2. ROW(row-based replication,RBR)行模式 ✅生产主流
不记录SQL,记录每行数据变更前后的值
特点
- • 主从数据一致性最高,不存在非确定函数问题
- • 支持离线数据恢复、闪回(binlog2sql、myflash)
缺点
- • 更新大量数据时 binlog 文件暴涨
例:UPDATE t SET name='xxx' WHERE create_time<'2025'修改10万行,会写入10万条行变更日志
附加参数
binlog_row_image控制每行记录内容:
- •
FULL(默认):记录前镜像+后镜像(修改前、修改后完整行) - •
MINIMAL:只记录修改字段+主键,体积更小 - •
NOBLOB:非blob字段完整记录,blob变更只记录变更
3. MIXED(mixed-based replication,MBR)混合模式
自动智能切换:
- •普通SQL → 使用 STATEMENT
- •存在不确定函数/风险SQL → 自动切换为 ROW
优缺点
兼顾体积与一致性,但存在不可控性;
现在主流规范:直接统一使用 ROW,不推荐 Mixed
生产环境最佳实践
binlog_format = ROW binlog_row_image = MINIMAL快速对比汇总表
| 格式 | 记录内容 | 一致性 | 日志大小 | 适用场景 |
| STATEMENT | 原始SQL语句 | 差,有非确定函数隐患 | 小 | 基本淘汰 |
| MIXED | 自动切换语句/行 | 一般,逻辑不可控 | 中等 | 不推荐新项目 |
| ROW | 变更行数据镜像 | 最高 | 偏大 | 生产标准方案、数据恢复、主从同步 |
补充小知识点
MySQL8.0默认 binlog_format=ROW;
5.7 默认也是 ROW;5.6/5.5 早期版本默认 MIXED。
二、使用最左前缀索引,a b c 字段是联合索引, where a=1 and c>2 and b<3 索引使用情况
联合索引idx(a,b,c)
查询:where a=1 and c>2 and b<3
有效用到索引前缀:a + b,c无法走索引范围过滤。
核心原理:最左前缀 + 范围条件阻断规则
联合索引中:范围条件(> < >= <= between like 前缀模糊)后面的列,无法使用索引
先拆解 SQL:
WHERE a=1 AND c>2 AND b<3MySQL优化器会自动调整where条件顺序,不依赖你书写顺序!
优化后逻辑等价:
WHERE a=1 AND b<3 AND c>2索引结构:a → b → c
- 1.
a=1:等值匹配 ✅ 使用索引 - 2.
b<3:范围条件❗
→b之后所有字段(c),丧失索引检索能力
执行流程
- 1. 通过索引,快速定位所有
a=1的索引区间; - 2. 在a=1集合里,利用索引匹配
b<3; - 3.c>2 无法在索引层面过滤
MySQL拿到满足 a=1 and b<3 的索引行,回表读取完整数据,再过滤c>2
重点易错区分(对比实验)
场景1(当前题目)
a=1 and b<3 and c>2
索引使用:idx(a,b),c失效
场景2
a=1 and b=3 and c>2
b是等值,c范围 ✅ 使用idx(a,b,c)
场景3
a>1 and b=3 and c=4
a是范围 → b、c全部失效,仅用到a
补充重要知识点
- 1.等值放前面,范围放联合索引最后一列,是最优设计
良好设计:idx(a,b,c)查询a=? and b=? and c>? - 2. 为什么范围后面列失效?
联合索引是有序B+树:a固定 → b有序 → c有序
当 b 使用范围查询,匹配出来的多条记录中,c不再全局有序,数据库不能利用索引快速筛选c,只能内存过滤。 - 3. 误区纠正
❌ 不是“写在后面的条件不走索引”
✅ 是联合索引中,第一个出现的范围字段,阻断后续所有索引列
执行验证方式
执行 explain 查看 key、key_len
- • key_len = a长度 + b长度 → 证明只用到a、b,没有用到c
优化建议
当前SQL如果查询频繁:
原有索引(a,b,c)不太合适;
调整索引顺序:把范围字段c放到最后
索引:idx(a,b,c)不变,改写SQL尽量保证等值在前;
如果业务经常a=?,b<?,c>?,无法调整条件,只能接受c在server层过滤;
如果数据量巨大,可以考虑覆盖索引减少回表开销:idx(a,b,c,其他查询字段)(覆盖索引,避免回表,虽然c依然不能索引过滤,但减少IO)
极简总结背诵版
联合索引(a,b,c)
where a=1 and c>2 and b<3
优化器重排条件为 a=1 and b<3 and c>2
b是范围条件,阻断后面c
索引有效利用:a、b;c在服务层过滤。
三、MySQL 一条SQL执行完整流程(分为:查询SQL(SELECT)、更新SQL(INSERT/UPDATE/DELETE)两套流程,面试高频)
先明确架构分层:
客户端 → 连接器 → 查询缓存(8.0移除) → 分析器 → 优化器 → 执行器 → 存储引擎(InnoDB)
默认以InnoDB存储引擎讲解(生产主流)
一、整体通用分层流程(SELECT 查询语句)
1. 连接器建立连接 2. 查询缓存(MySQL5.7存在,8.0 删除,不再讨论) 3. 分析器:词法分析 → 语法分析,生成语法树 4. 优化器:生成多种执行计划,选出最优执行计划 5. 执行器:调用存储引擎API,逐行读取数据 6. InnoDB存储引擎:访问B+树索引、返回数据分步详解
1. 连接器
客户端发起 TCP 连接(mysql -h -u -p)
- • 验证账号、密码;
- • 获取该连接对应的权限;
- • 维护连接(长连接/短连接,wait_timeout控制空闲断开)
连接成功后,后续所有SQL都复用这条连接,权限在连接建立时确定,中途修改权限不会立即生效。
2. 查询缓存(废弃知识点)
5.7 支持,MySQL8.0彻底移除
逻辑:以SQL字符串为key,缓存查询结果;
缺陷:只要表发生更新,整张表缓存全部失效,实用性极差,不推荐使用。
3. 分析器
作用:看懂这条SQL是否合法
- 1.词法分析:拆分字符串,识别关键字(select/from/where/and、字段名、表名、常量)
- 2.语法分析:按照MySQL语法规则构建抽象语法树AST
- • 如果语法错误(少逗号、关键字写错),直接返回语法报错;
此时不会校验表、字段是否存在!(表不存在的报错在优化器阶段)
- • 如果语法错误(少逗号、关键字写错),直接返回语法报错;
4. 优化器(核心考点)
拿到语法树,生成、选择最优执行计划
做两件关键事情:
- 1.条件重排:自动调整where条件顺序(之前联合索引例题用到!)
where a=1 and c>2 and b<3→ 内部调整顺序方便匹配索引 - 2.索引选择、连接顺序选择
多条join、多个索引时,计算成本,选择开销最低方案;
最终输出:确定用哪个索引、先扫描哪张表、执行顺序。
explain 看到的内容,就是优化器输出的执行计划
5. 执行器
按照执行计划工作:
- 1. 先校验用户是否拥有这张表的查询权限;
- 2. 调用存储引擎提供的接口
read_row(); - 3. 循环读取引擎返回的数据,经过server层过滤(无法使用索引的条件在这里过滤)
- 4. 组装结果返回客户端
⚠️ 重要区分:
Server层(连接器/分析器/优化器/执行器) 和 存储引擎层(InnoDB)分离
Server层通用,MyISAM/InnoDB共用;索引、事务、锁、MVCC由存储引擎实现。
6. InnoDB存储引擎层
接收执行器指令,操作磁盘数据:
- • 根据索引定位数据页(B+树)
- • 优先访问缓冲池Buffer Pool(内存),不存在再加载磁盘页
- • 根据MVCC读取可见版本(隔离级别控制)
- • 将行数据返回执行器
二、更新SQL流程(UPDATE / INSERT / DELETE,面试重中之重)
UPDATE user SET name='xx' WHERE id=1;整体前期链路一样:连接器 → 分析器 → 优化器 → 执行器
重点区别:更新涉及 redo log、undo log、binlog、事务两阶段提交
执行步骤:
- 1. 执行器调用InnoDB引擎,根据索引找到 id=1 这一行;
- 2.加行锁(事务提交前持有锁)
- 3. 生成undo log(回滚日志,用于事务回滚、MVCC)
- 4. 修改内存中 Buffer Pool 的数据页(内存脏页)
- 5. 写入redo log buffer(准备持久化redo log)
- 6. 告知执行器:引擎层执行完成
- 7. 执行器写入binlog cache
- 8.事务提交,两阶段提交 2PC
- • prepare阶段:redo log持久化到磁盘,打上prepare标记
- • commit阶段:binlog持久化磁盘,redo log打上commit标记
- 9. 事务完成,释放行锁
三大日志简单区分(配套考点)
- 1.redo log(引擎层,InnoDB特有):崩溃恢复,保证事务持久性
- 2.undo log(引擎层):回滚、MVCC多版本
- 3.binlog(server层):主从复制、数据恢复
三、高频面试易错题总结
- 1. 语法报错在【分析器】;表不存在报错在【优化器】
- 2. 查询缓存8.0已经删除,不要再写进答案
- 3. 索引选择是优化器决定,不是执行器
- 4. where条件自动调整顺序发生在优化器阶段(对应你上一题联合索引)
- 5. 索引无法过滤的条件,在【执行器(Server层)】过滤
- 6. SELECT没有redo/binlog写入;DML更新语句会生成三大日志
- 7. MVCC、锁、Buffer Pool 属于存储引擎层能力
精简版
一条查询SQL先经过连接器建立连接,接着分析器做词法和语法解析生成语法树;然后优化器生成并选出最优执行计划;执行器校验权限,调用InnoDB引擎接口;InnoDB通过索引查找数据,借助Buffer Pool读取页面,基于MVCC返回可见数据,最终执行器把结果返回客户端。
更新SQL前期流程一致,引擎找到对应数据加行锁,记录undo log,修改内存数据,写入redo log;上层执行器记录binlog,最后通过两阶段提交保证redo log和binlog数据一致,事务完成释放锁。