Database基础
概念总结
| 分类 | 概念 | 含义 | 举例或说明 |
|---|---|---|---|
| 基本概念 | 数据(Data) | 描述事物的符号记录,是数据库的基本对象 | 学号=1001,姓名=张三 |
| 数据库(DB) | 存放数据的集合,具有组织性、共享性、独立性和冗余控制 | MySQL 中的一个数据库 student_db | |
| 数据库管理系统(DBMS) | 管理数据库的软件系统,用于定义、创建、操作和维护数据库 | MySQL、PostgreSQL、Oracle | |
| 数据库系统(DBS) | 含数据库、DBMS、应用程序和用户的完整系统 | 企业人事管理系统 | |
| 数据模型 | 概念模型 | 描述现实世界到信息世界的抽象(如E-R图) | 实体-联系模型 |
| 逻辑模型 | 面向数据结构与操作的模型(关系模型最常见) | 表、行、列形式 | |
| 物理模型 | 描述数据在物理存储介质上的组织方式 | 索引、文件块、页 | |
| 关系数据库 | 关系(Relation) | 数据表的逻辑结构 | student(id, name, age) |
| 元组(Tuple) | 表中的一行记录 | (1001, 张三, 20) | |
| 属性(Attribute) | 表中的一列字段 | name、age | |
| 主键(Primary Key) | 唯一标识元组的属性 | id | |
| 外键(Foreign Key) | 关联其他表主键的属性 | student.course_id → course.id | |
| 候选键(Candidate Key) | 可唯一标识记录的所有属性集合 | id、身份证号 | |
| 完整性约束 | 实体完整性 | 主键不能为空且唯一 | id 不可重复 |
| 参照完整性 | 外键值必须引用存在的主键 | course_id 必须在 course 表中存在 | |
| 用户定义完整性 | 用户自定义的数据规则 | age > 0 | |
| 操作类型 | 查询(SELECT) | 从数据库读取数据 | SELECT * FROM student; |
| 插入(INSERT) | 添加新记录 | INSERT INTO student VALUES(1001, ‘张三’, 20); | |
| 更新(UPDATE) | 修改现有记录 | UPDATE student SET age=21 WHERE id=1001; | |
| 删除(DELETE) | 删除记录 | DELETE FROM student WHERE id=1001; | |
| 范式(Normalization) | 第一范式(1NF) | 每个属性不可再分 | 一列不能同时存多个值 |
| 第二范式(2NF) | 消除部分函数依赖 | 依赖于主键整体 | |
| 第三范式(3NF) | 消除传递依赖 | 非主属性只依赖主键 | |
| 事务(Transaction) | 原子性(Atomicity) | 事务要么全做要么全不做 | 银行转账不能只扣款不加款 |
| 一致性(Consistency) | 数据前后状态保持一致 | 转账前后总金额相同 | |
| 隔离性(Isolation) | 并发事务互不影响 | A、B 同时转账互不干扰 | |
| 持久性(Durability) | 提交后结果永久保存 | 崩溃后仍能恢复提交数据 | |
| 索引 | 索引(Index) | 加速查询的数据结构 | B+树索引、哈希索引 |
| SQL分类 | DDL(数据定义语言) | 定义表结构 | CREATE、ALTER、DROP |
| DML(数据操作语言) | 操作数据 | SELECT、INSERT、UPDATE、DELETE | |
| DCL(数据控制语言) | 权限管理 | GRANT、REVOKE | |
| TCL(事务控制语言) | 控制事务 | COMMIT、ROLLBACK |
drop,delete和truncate
| 对比项 | DROP | DELETE | TRUNCATE |
|---|---|---|---|
| 作用对象 | 整个表(结构+数据一起删除) | 表中的数据(可带条件) | 表中的所有数据(不带条件) |
| 语法示例 | |
|
|
| 是否可带 WHERE 条件 | ❌ 否 | ✅ 是 | ❌ 否 |
| 是否删除表结构 | ✅ 是(表不再存在) | ❌ 否(仅删除数据) | ❌ 否(仅清空数据) |
| 是否可恢复(回滚) | ❌ 不可回滚 | ✅ 可回滚(在事务中) | ⚠️ 不可回滚(多数数据库) |
| 是否触发触发器(Trigger) | ❌ 否 | ✅ 是 | ❌ 否(但部分数据库可配置) |
| 自增计数器(AUTO_INCREMENT) | 删除表 → 计数器消失 | 不受影响 | ✅ 计数器会被重置 |
| 执行速度 | 🚀 最快(直接删除元数据) | 🐢 最慢(逐行删除) | ⚡ 较快(不逐行删除) |
| 事务日志记录方式 | 记录表对象的删除 | 记录每行删除操作 | 记录页释放操作 |
| 释放空间 | ✅ 彻底释放 | ❌ 通常不释放(除非手动优化) | ✅ 释放表数据页 |
| 常见使用场景 | 删除整个表、重建表结构 | 按条件删除部分数据 | 快速清空表中所有数据 |
NoSQL
| 分类 | 概念 | 含义 | 优点 | 缺点 | 常见代表 | 典型场景 |
|---|---|---|---|---|---|---|
| 基本定义 | NoSQL(Not Only SQL) | 一类非关系型数据库,强调高性能、可扩展性、灵活数据结构 | 高扩展性、灵活结构、读写快 | 不支持复杂查询、事务弱 | —— | 大数据、缓存、实时分析等 |
| 主要特征 | 无固定表结构 | 不需要预定义模式(Schema) | 方便快速迭代 | 结构不统一难以约束 | MongoDB | 动态数据结构存储 |
| 高可扩展性 | 易于水平扩展(分片) | 大规模数据存储 | 分布式一致性难 | Cassandra | 分布式系统 | |
| 高性能 | 读写性能远高于关系型数据库 | 快速响应 | 不适合复杂事务 | Redis | 缓存系统 | |
| 弱一致性 | 通常采用“最终一致性”而非强一致性 | 提升可用性 | 事务支持较弱 | DynamoDB | 高并发环境 | |
| 数据模型分类 | 键值型(Key-Value) | 通过键直接访问值 | 极高性能、简单 | 不支持复杂查询 | Redis、Riak、Amazon DynamoDB | 缓存、会话管理、排行榜 |
| 文档型(Document) | 以 JSON/BSON/XML 存储文档 | 结构灵活、支持复杂查询 | 不适合多表关联 | MongoDB、CouchDB | 内容管理系统、用户画像 | |
| 列族型(Column Family) | 数据按列族存储,适合大规模数据 | 高压缩、高读写性能 | 学习成本高 | Cassandra、HBase | 日志系统、时间序列存储 | |
| 图型(Graph) | 节点和边组成的图结构 | 擅长关系查询 | 数据分布复杂 | Neo4j、JanusGraph | 社交网络、推荐系统 | |
| 一致性模型 | CAP 理论 | 一致性(C)、可用性(A)、分区容错性(P)不可兼得 | 选择灵活 | 一致性权衡复杂 | —— | 分布式设计指导 |
| 事务支持 | ACID 弱化 | 多数 NoSQL 仅支持单文档或单键原子操作 | 性能高 | 不支持复杂事务 | —— | 高并发、非关键金融业务 |
| 查询语言 | 无标准 SQL | 各数据库自定义查询接口或 API | 自由灵活 | 学习成本高 | MongoDB Query、Redis CLI | 应用程序直连查询 |
| 索引机制 | 支持多种自定义索引 | 可基于键、字段、二级索引等 | 提高查询性能 | 部分实现复杂 | MongoDB 二级索引 | 查询优化 |
| 存储结构 | 多为内存+磁盘混合 | 提升性能与容错 | 性能高 | 占内存大 | Redis、Cassandra | 热数据与冷数据分层存储 |
| 扩展方式 | 水平扩展(Sharding) | 通过分片分布到多节点 | 可线性扩容 | 一致性维护难 | 大多数 NoSQL | 分布式部署 |
Sql语法
| 操作 | 关键语句 | 作用说明 | 示例 |
|---|---|---|---|
| C:Create(插入) | |
向表中插入新数据 | |
| R:Read(查询) | |
查询数据(最核心语句) | |
|
条件筛选行 | |
|
|
逻辑组合条件 | |
|
|
排序结果集 | |
|
|
按降序排序 | |
|
|
限制返回的行数(分页常用) | |
|
|
从第几行开始取数据(分页) | |
|
|
按字段分组(常与聚合函数结合) | |
|
|
对分组结果再过滤(类似 WHERE) | |
|
|
去重 | |
|
|
模糊匹配 | |
|
|
判断字段值是否在集合内 | |
|
|
判断字段值是否在区间内 | |
|
|
给列或表起别名 | |
|
|
连接多张表 | |
|
| U:Update(更新) | |
修改数据(可带条件) | |
| D:Delete(删除) | |
删除满足条件的数据 | |
| D:Truncate(清空) | |
快速清空整张表 | |
常用聚合函数(与 一起用)
GROUP BY
| 函数 | 含义 | 示例 |
|---|---|---|
|
统计行数 | |
|
求和 | |
|
平均值 | |
|
最大值 | |
|
最小值 | |
关系型数据库总结
| 方面 | 描述 |
|---|---|
| 基本概念 | 基于关系模型的数据管理系统,使用表格形式存储和管理数据 |
| 核心结构 | 表(Table)、行(Row)、列(Column)、主键(Primary Key)、外键(Foreign Key) |
| 数据组织 | 数据以二维表格形式组织,每行代表一条记录,每列代表一个属性 |
| 关系类型 | 一对一、一对多、多对多关系 |
| 主要特点 | – 结构化数据 – ACID事务特性 – 数据完整性约束 – 标准化设计 |
| 常见产品 | MySQL、PostgreSQL、Oracle、SQL Server、SQLite |
| 查询语言 | SQL(结构化查询语言) |
| 优势 | ✅ 数据一致性 ✅ 复杂查询能力 ✅ 事务支持 ✅ 数据完整性 ✅ 标准化 |
| 劣势 | ❌ 扩展性限制 ❌ 固定schema ❌ 处理非结构化数据困难 ❌ 性能瓶颈 |
| 适用场景 | 财务系统、ERP、CRM、需要复杂查询和事务保证的系统 |
| ACID特性 | Atomicity(原子性) Consistency(一致性) Isolation(隔离性) Durability(持久性) |
| 规范化 | 减少数据冗余,提高数据一致性(1NF, 2NF, 3NF, BCNF) |
| 索引机制 | B-tree、Hash索引等,提高查询性能 |
| 约束类型 | 主键、外键、唯一性、非空、检查约束 |
字段类型
| 分类 | 数据类型 | 说明 | 示例 | 适用场景 |
|---|---|---|---|---|
| 数值类型 | INT/INTEGER | 整数类型 | |
年龄、数量、ID |
| BIGINT | 大整数 | |
主键、大数据量 | |
| SMALLINT | 小整数 | |
状态码、标志位 | |
| DECIMAL(p,s) | 精确小数 | |
金额、价格 | |
| FLOAT/REAL | 浮点数 | |
分数、百分比 | |
| 字符串类型 | CHAR(n) | 定长字符串 | |
固定长度编码 |
| VARCHAR(n) | 变长字符串 | |
姓名、标题 | |
| TEXT | 长文本 | |
文章、描述 | |
| 日期时间 | DATE | 日期 | |
出生日期 |
| TIME | 时间 | |
登录时间 | |
| DATETIME | 日期时间 | |
创建时间 | |
| TIMESTAMP | 时间戳 | |
更新时间 | |
| 布尔类型 | BOOLEAN/BOOL | 布尔值 | |
状态标志 |
| TINYINT(1) | 微小整数 | |
MySQL中的布尔 | |
| 二进制类型 | BLOB | 二进制大对象 | |
图片、文件 |
| BINARY(n) | 定长二进制 | |
哈希值 | |
| 特殊类型 | ENUM | 枚举类型 | |
有限选项 |
| JSON | JSON数据 | |
结构化数据 | |
| UUID | 唯一标识符 | |
分布式ID |
选择原则
数值类型: 根据数值范围和精度选择字符串类型: 根据长度和是否固定选择日期类型: 根据是否需要时间部分选择空间考虑: 选择能满足需求的最小类型
MySQL基础架构
MySQL 基础架构总结

MySQL 核心组件功能总结
| 组件名称 | 主要功能 | 详细说明 | 特点与备注 |
|---|---|---|---|
| 连接器 | 身份认证与权限验证 | – 验证用户名密码 – 检查数据库访问权限 – 管理用户连接 |
登录阶段执行,建立连接后权限验证完成 |
| 查询缓存 | 缓存查询结果 | – 缓存SELECT查询结果 – Key-Value形式存储 – Key是查询语句,Value是结果 |
🚨 MySQL 8.0已移除 ❌ 实用性较差,更新频繁时缓存命中率低 |
| 分析器 | SQL语法分析与语义分析 | 词法分析:识别关键词、表名、列名等 语法分析:检查SQL语法正确性 语义分析:验证语句逻辑合法性 |
SQL语句的”翻译官”,构建解析树 |
| 优化器 | 生成最优执行计划 | – 选择使用哪个索引 – 决定表连接顺序 – 重写查询以提高效率 |
基于成本评估,选择”MySQL认为”最优方案 |
| 执行器 | 执行SQL语句并返回结果 | – 操作存储引擎接口 – 执行前进行权限验证 – 返回查询结果给客户端 |
无权限时报错,调用存储引擎进行数据操作 |
| 存储引擎 | 数据存储与读取 | – 管理数据存储格式 – 处理磁盘I/O操作 – 实现事务、锁等特性 |
插件式架构,支持多种引擎 默认引擎:InnoDB 其他引擎:MyISAM、Memory等 |
工作流程
连接器 → 分析器 → 优化器 → 执行器 → 存储引擎
重要说明
✅ InnoDB推荐:绝大多数场景下的最佳选择❌ 查询缓存:已从MySQL 8.0移除,因实际效果不佳🔒 权限验证:分别在连接器和执行器两个阶段进行
InnoDB vs MyISAM 存储引擎对比
| 特性 | InnoDB | MyISAM |
|---|---|---|
| 事务支持 | ✅ 支持ACID事务 | ❌ 不支持事务 |
| 锁级别 | 🔒 行级锁 | 🔒 表级锁 |
| 外键约束 | ✅ 支持外键 | ❌ 不支持外键 |
| 崩溃恢复 | ✅ 支持崩溃后的安全恢复 | ❌ 崩溃后易损坏 |
| 并发性能 | 🚀 高并发,读写不阻塞 | ⚠️ 写操作会锁表 |
| 存储文件 | 📁 .ibd(数据+索引) 📁 ibdata1(系统表空间) |
📁 .frm(表结构) 📁 .MYD(数据文件) 📁 .MYI(索引文件) |
| 索引结构 | 🌳 B+树聚簇索引 | 🌳 B+树非聚簇索引 |
| 数据存储 | 📦 数据按主键顺序存储 | 📦 数据按插入顺序存储 |
| COUNT(*)操作 | ⏳ 需要全表扫描 | ⚡ 直接返回记录数 |
| 全文索引 | ✅ 5.6+版本支持 | ✅ 支持全文索引 |
| 压缩特性 | ✅ 支持表压缩 | ✅ 支持压缩表 |
| 缓存机制 | 📊 缓冲池缓存数据和索引 | 📊 只缓存索引 |
| MVCC | ✅ 多版本并发控制 | ❌ 不支持 |
| 热备份 | ✅ 支持在线热备份 | ⚠️ 有限支持 |
| 默认引擎 | ✅ MySQL 5.5+ 默认 | ❌ 旧版本默认 |
适用场景总结
| 引擎 | 推荐场景 | 不适用场景 |
|---|---|---|
| InnoDB | ✅ 需要事务的应用 ✅ 高并发读写 ✅ 数据一致性要求高 ✅ 需要外键约束 ✅ 在线热备份需求 |
❌ 只读应用且数据量巨大 ❌ 内存有限且读多写极少 |
| MyISAM | ✅ 读密集型应用 ✅ 不需要事务 ✅ COUNT(*)频繁 ✅ 全文索引(旧版本) ✅ 数据仓库类应用 |
❌ 需要事务保证 ❌ 高并发写操作 ❌ 数据一致性要求高 ❌ 需要外键约束 |
选择建议
绝大多数场景选择 InnoDB仅特殊场景考虑 MyISAMMySQL 5.5+ 版本默认使用 InnoDB
索引
优缺点
| 方面 | 优点 ✅ | 缺点 ❌ |
|---|---|---|
| 查询性能 | 极大提升查询速度(10-100倍),避免全表扫描 | – |
| 写操作 | – | 降低INSERT/UPDATE/DELETE性能 |
| 存储空间 | – | 额外占用10%-30%存储空间 |
| 数据完整性 | 保证数据唯一性(唯一索引)、主外键约束 | – |
| 排序分组 | 优化ORDER BY、GROUP BY操作效率 | – |
| 表连接 | 加速JOIN操作性能 | – |
| 设计维护 | – | 增加设计复杂度和维护成本 |
| 内存占用 | – | 占用Buffer Pool内存空间 |
| 使用限制 | 支持覆盖索引,避免回表查询 | 有最左前缀原则,某些场景会索引失效 |
| 适用场景 | 读多写少、大数据量、高区分度列 | 写多读少、小数据量、低区分度列 |
树总结
| 树类型 | 特点 | 查找 | 插入 | 删除 | 空间复杂度 | 用途 |
|---|---|---|---|---|---|---|
| 普通二叉树 | 每个节点最多有两个子节点;不保证顺序 | O(n) | O(n) | O(n) | O(n) | 基础树结构、表达式树 |
| 二叉搜索树 (BST) | 左子树 < 根 < 右子树 | O(h) 平均 O(log n),最坏 O(n) | O(h) | O(h) | O(n) | 查找、排序、字典 |
| AVL树 | 自平衡二叉搜索树;每个节点左右子树高度差 ≤ 1 | O(log n) | O(log n) | O(log n) | O(n) | 高速查找、要求严格平衡的场景 |
| 红黑树 | 自平衡二叉搜索树,允许一定程度不平衡,易于实现 | O(log n) | O(log n) | O(log n) | O(n) | Java TreeMap/TreeSet、Linux 内核调度 |
| B树 | 多路平衡搜索树,每节点可有多个子节点 | O(log n) | O(log n) | O(log n) | O(n) | 数据库、文件系统(磁盘优化) |
| B+树 | B树的变种,叶子节点链表存储所有数据,非叶子节点只存索引 | O(log n) | O(log n) | O(log n) | O(n) | 数据库索引、键值存储系统 |
| Trie (前缀树) | 字典树,按字符分支存储字符串 | O(m) m = 字符串长度 | O(m) | O(m) | O(ALPHABET × n) | 自动补全、字典查找、字符串匹配 |
索引类型
| 索引类型 | 数据结构/实现 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|---|
| B树/B+树索引 | B树或B+树 | 支持范围查询、排序,查找/插入/删除 O(log n),平衡 | 内存消耗相对高;范围查询性能高但不适合全文匹配 | 主键索引、普通索引、数据库存储索引(MySQL InnoDB默认) |
| 哈希索引 | 哈希表 | 查找速度极快,O(1) 时间复杂度 | 不支持范围查询和排序;冲突需要解决 | 精确匹配查询(=) |
| 全文索引 (Full-text Index) | 倒排索引(Inverted Index) | 支持自然语言全文检索 | 占用空间大;更新成本高;不适合精确匹配 | 搜索引擎、文章/文本搜索 |
| 位图索引 (Bitmap Index) | 位图 | 占用空间小;适合低基数列(性别、状态等) | 高基数列效率低;更新成本高 | OLAP 系统、数据仓库、维度列 |
| 空间索引 (Spatial Index) | R树或四叉树 | 支持地理位置查询、范围查询 | 实现复杂;只适合空间数据 | GIS、地图、地理位置查询 |
| 联合索引 (Composite Index) | B+树(多列组合) | 支持多列联合查询 | 顺序敏感,只能从最左列开始匹配 | 多列查询优化 |
| 唯一索引 (Unique Index) | B+树 | 保证唯一性 | 插入时会检查冲突 | 主键、唯一约束 |
| 聚簇索引 (Clustered Index) | B+树 | 数据物理顺序与索引顺序一致,范围查询快 | 一个表只能有一个聚簇索引 | 主键索引(InnoDB默认) |
| 非聚簇索引 (Non-clustered Index) | B+树 | 可以有多个,支持灵活查询 | 查到索引后还需回表查询数据 | 辅助索引、覆盖索引优化 |
索引下推
索引下推(Index Condition Pushdown,ICP)是数据库优化器在使用索引查询时的一种优化策略,主要用来减少回表(访问表数据)次数,提高查询效率。
SELECT * FROM users WHERE age > 30 AND name = 'Alice';
普通索引扫描:
使用 索引查找
age 的行号。回表读取每行完整数据,再判断
age > 30。
name = 'Alice'
索引下推(ICP):
使用 索引查找时,同时在索引阶段检查
age 是否满足。只有满足条件的行才回表读取,减少回表次数。
name = 'Alice'
日志
在事务执行过程中,每执行一条修改语句(DML)时,都会写入 redo log buffer(不是立即刷盘),
但 binlog 只有在事务提交时才会一次性写入。
| 日志类型 | 生成时机 | 刷盘时机 | 记录粒度 | 作用 |
|---|---|---|---|---|
| redo log | 每执行一条 DML 语句时 | 通常在事务提交时(或后台刷盘) | 物理页修改 | 保证持久性 |
| binlog | 事务提交时一次性写入 | 同上 | 逻辑操作(语句/行) | 主从复制、恢复 |
| undo log | 每执行一条 DML 时 | 跟随事务提交或回滚 | 修改前的值 | 原子性 + MVCC |
| 日志类型 | 主要作用 | 存储位置 | 使用场景 / 特点 | 是否持久化到磁盘 |
|---|---|---|---|---|
| 重做日志(Redo Log) | 用于保证事务的持久性(Durability),即使数据库崩溃,也可以通过重做日志将已提交的数据恢复到磁盘。 | 通常存放在磁盘上的预写日志文件(redo log file),但InnoDB也先写入日志缓冲区再刷盘。 | 崩溃恢复,InnoDB事务提交时必须先写redo log,再修改数据页。 | 是,事务提交时刷盘。 |
| 回滚日志(Undo Log) | 用于保证事务的原子性(Atomicity),实现事务回滚,并支持多版本并发控制(MVCC)。 | 一般存放在Undo Tablespace(InnoDB)中,默认在磁盘上。 | 事务回滚、读取旧版本数据(支持一致性读)。 | 是,事务回滚时需要读取。 |
| 二进制日志(Binlog / Binary Log) | 用于记录数据库的所有更改操作(非事务性的DDL和DML),主要用于复制、审计和数据恢复。 | 存放在磁盘上的二进制日志文件。 | 主从复制、数据恢复、审计。 | 是,记录事务执行情况,提交后写入磁盘。 |
redo log
redo log(重做日志)是 InnoDB 存储引擎独有的,它让 MySQL 拥有了崩溃恢复能力。
MySQL 中数据是以页为单位,你查询一条记录,会从硬盘把一页的数据加载出来,加载出来的数据叫数据页,会放入到 中。
Buffer Pool
后续的查询都是先从 中找,没有命中再去硬盘加载,减少硬盘 IO 开销,提升性能。
Buffer Pool
更新表数据的时候,也是如此,发现 里存在要更新的数据,就直接在
Buffer Pool 里更新。
Buffer Pool
然后会把“在某个数据页上做了什么修改”记录到重做日志缓存()里,接着刷盘到 redo log 文件里。
redo log buffer
刷盘时机:
事务提交:当事务提交时,log buffer 里的 redo log 会被刷新到磁盘(可以通过参数控制,后文会提到)。log buffer 空间不足时:log buffer 中缓存的 redo log 已经占满了 log buffer 总容量的大约一半左右,就需要把这些日志刷新到磁盘上。事务日志缓冲区满:InnoDB 使用一个事务日志缓冲区(transaction log buffer)来暂时存储事务的重做日志条目。当缓冲区满时,会触发日志的刷新,将日志写入磁盘。Checkpoint(检查点):InnoDB 定期会执行检查点操作,将内存中的脏数据(已修改但尚未写入磁盘的数据)刷新到磁盘,并且会将相应的重做日志一同刷新,以确保数据的一致性。后台刷新线程:InnoDB 启动了一个后台线程,负责周期性(每隔 1 秒)地将脏页(已修改但尚未写入磁盘的数据页)刷新到磁盘,并将相关的重做日志一同刷新。正常关闭服务器:MySQL 关闭的时候,redo log 都会刷入到磁盘里去。
innodb_flush_log_at_trx_commit
nnoDB 支持三种刷盘策略(由 参数控制):
innodb_flush_log_at_trx_commit
| 参数值 | 刷盘行为 | 特点 |
|---|---|---|
| 0 | 每秒将日志缓冲区写入日志文件,但不刷磁盘 | 性能最高,但可能丢失最后1秒的事务 |
| 1 | 每次事务提交时写入日志缓冲区并刷磁盘 | 最安全(保证事务持久性),但性能最低 |
| 2 | 每次事务提交写入日志缓冲区,每秒刷盘一次 | 折中方案,性能比 1 好,可能丢失1秒的事务 |
binlog
本质上是 逻辑日志,记录 SQL 语句或行的变更,而不是数据页的修改。
主要用于:
主从复制:从库通过 Binlog 重放主库操作。数据恢复:可以用来 增量恢复 数据。审计/追踪:记录谁对数据库做了什么操作。
MySQL 支持三种 Binlog 格式:
| 类型 | 描述 | 优点 | 缺点 |
|---|---|---|---|
| STATEMENT | 记录 SQL 语句 | 占用空间小,可读 | 某些语句非确定性(如 、)可能导致主从不一致 |
| ROW | 记录 行数据变化(Insert/Update/Delete 具体数据) | 精准、主从一致性高 | 日志量大,占用磁盘多 |
| MIXED | 混合模式,默认 | 自动选择 STATEMENT 或 ROW | 兼顾性能和一致性 |
Binlog 写入流程概览
事务执行 SQL
用户执行 /
INSERT /
UPDATE /
DELETE 等操作。
DDL
写入 Binlog Cache(内存)
每个会话有一个 session binlog cache(内存缓冲区),SQL 语句或行变更先写入这里。如果开启了 事务,写入的是事务操作,而不是立即刷盘。
事务提交(COMMIT)
MySQL 会将 session binlog cache 写入 全局 binlog buffer(Server 内存)再刷新到磁盘上的 binlog 文件(顺序写,提高性能)对于 事务型 DML,只有 提交成功才写入磁盘,保证主从一致性
刷盘方式
依赖系统调用 或
fsync() 打开文件
O_SYNC 参数控制:
sync_binlog
→ 依赖操作系统刷盘(性能高,但可能丢失少量事务)
sync_binlog = 0 → 每次提交都刷盘(最安全,但性能低)
sync_binlog = 1 → 每 N 次提交刷盘一次(折中方案)
sync_binlog = N
主从复制
Binlog 刷盘后,从库 IO 线程读取 Binlog 并发送给 SQL 线程执行事务提交完成后,才能保证从库也能完全重放
两阶段提交

第一阶段:准备阶段(Prepare Phase)
目的:询问所有参与者是否准备好提交动作:每个参与者执行事务操作,写入redo log等,但不真正提交结果:
所有参与者都回复”YES” → 进入第二阶段任一参与者回复”NO”或超时 → 立即回滚
第二阶段:提交阶段(Commit Phase)
目的:正式完成事务提交动作:协调者通知所有参与者正式提交执行顺序:
先写binlog(逻辑日志)再写redo log提交记录最后更新内存数据
1. Undo Log → 2. Redo Log (Prepare) → 3. Binlog → 4. Redo Log (Commit)
| 阶段 | 主要步骤 | Redo Log (InnoDB引擎层) | Binlog (MySQL Server层) | Undo Log (InnoDB引擎层) |
|---|---|---|---|---|
| 事务执行中 | SQL执行,数据修改 | 在内存中记录数据页的物理变化 | – | 先于数据修改写入 1. 记录回滚所需的逻辑信息 2. 其自身的生产也被记入Redo Log,保证持久性 |
| 阶段一 (Prepare) | 开始,第一步 |
1. 刷盘 2. 标记状态为 此时事务已做好提交准备,但需等待Binlog确认 |
– | – |
| 阶段二 (Commit) | 写入Binlog | 保持 状态,等待 |
1. 刷盘 (由参数控制) Binlog的写入成功是最终提交的判决依据 |
– |
| 阶段三 (Finalize) | 最终确认 | 2. 标记状态为 (此步多为内存操作,快速) 事务正式提交成功 |
– | – |
| 崩溃恢复 | MySQL重启后 | 扫描Redo Log: – 状态为 -> 直接提交 – 状态为 -> 检查Binlog是否完整 |
作为崩溃恢复的判决依据: – Binlog完整 -> 通知InnoDB提交事务 – Binlog缺失 -> 通知InnoDB回滚事务 | 如果决定回滚事务,则使用Undo Log执行反向操作,撤销修改 |
核心要点解读
的写入时机最早:它在事务执行过程中、数据页修改前就必须生成,以确保回滚能力。它的持久化不是直接刷盘,而是通过将其产生也记录到
Undo Log 中来保证的。
Redo Log 的 Prepare 状态是桥梁:它标志着事务已准备就绪,并将最终决定权交给了 Binlog。
Redo Log 的写入是“判决”阶段:Binlog 是否成功写入,是决定事务最终命运(提交还是回滚)的最终依据。
Binlog 的 Commit 状态是收尾:这个标记意味着整个两阶段提交流程圆满完成。
Redo Log
这个精巧的设计,通过 和
Prepare 两个状态,将两个独立的日志系统绑定在一起,形成了一个分布式事务(在MySQL内部),确保了在任何崩溃场景下,主从数据的一致性和事务的持久性。
Commit
undo log
与Redo Log的关系
| 对比维度 | Undo Log | Redo Log |
|---|---|---|
| 目的 | 回滚事务,提供历史版本 | 重做事务,保证持久性 |
| 内容 | 修改前的旧数据 | 修改后的新数据 |
| 生命周期 | 事务结束后可清理 | 需要长期保留 |
| 恢复方向 | 向后恢复(回滚) | 向前恢复(重做) |
Mysql事务隔离级别
| 特性维度 | READ UNCOMMITTED 读未提交 | READ COMMITTED 读已提交 | REPEATABLE READ 可重复读 (MySQL默认) | SERIALIZABLE 串行化 |
|---|---|---|---|---|
| 脏读 (Dirty Read) | ✅ 会出现 | ❌ 不会出现 | ❌ 不会出现 | ❌ 不会出现 |
| 不可重复读 (Non-repeatable Read) | ✅ 会出现 | ✅ 会出现 | ❌ 不会出现 | ❌ 不会出现 |
| 幻读 (Phantom Read) | ✅ 会出现 | ✅ 会出现 | ⚠️ 基本解决 (通过Next-Key Lock) | ❌ 不会出现 |
| 并发性能 | 🟢 最高 | 🟢 高 | 🟡 中等 | 🔴 最低 |
| 锁开销 | 🟢 最小 | 🟢 小 | 🟡 中等 | 🔴 最大 |
| 数据一致性 | 🔴 最差 | 🟡 较好 | 🟢 好 | 🟢 最好 |
| 实现机制 | 无锁读取 | MVCC快照读 | MVCC + 一致性读 | 完全加锁 |
| 锁范围 | 行锁(写时) | 行锁 | Next-Key Locking | 范围锁 |
| 适用场景 | 数据仓库 统计分析 非关键业务 | Web应用 OLTP系统 高并发写 | 金融业务 报表查询 需要一致性读 | 资金结算 对账系统 强一致性要求 |
| 问题类型 | 现象描述 | 示例场景 | 影响 |
|---|---|---|---|
| 脏读 Dirty Read | 读取到其他事务 未提交的数据 | 事务A修改数据未提交, 事务B读取到修改后的数据, 事务A回滚导致数据不一致 | 数据准确性受损, 业务逻辑错误 |
| 不可重复读 Non-repeatable Read | 同一事务内多次读取 同一数据结果不同 | 事务A读取数据后, 事务B修改并提交该数据, 事务A再次读取得到不同结果 | 事务内数据不一致, 影响业务决策 |
| 幻读 Phantom Read | 同一事务内多次查询 返回的记录数不同 | 事务A查询符合条件记录数后, 事务B插入新记录并提交, 事务A再次查询记录数增加 | 统计结果不准确, 范围操作受影响 |
锁机制对比表格
| 操作类型 | READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE |
|---|---|---|---|---|
| 普通SELECT | 无锁 | 快照读(无锁) | 快照读(无锁) | 共享锁 |
| SELECT…FOR UPDATE | 行锁 | 行锁 | Next-Key Lock | Next-Key Lock |
| UPDATE/DELETE | 行锁 | 行锁 | Next-Key Lock | Next-Key Lock |
| INSERT | 行锁 | 行锁 | Next-Key Lock | Next-Key Lock |
| 范围查询 | 行锁 | 行锁 | Next-Key Lock (防幻读) | 范围锁 |
InnoDB MVCC
核心原理:数据版本链 + 隐藏字段 + undo 日志 + Read View
数据的多版本存储
本质是一行数据在多次修改过程中形成的历史版本链表
每行数据除了实际值,还包含多个隐藏字段(以 InnoDB 为例):
:记录最后修改该数据的事务 ID(事务开始时会分配唯一 ID,自增)。
DB_TRX_ID:回滚指针,指向该数据的上一个版本(存储在 undo 日志中)。
DB_ROLL_PTR:标记数据是否被删除(逻辑删除,而非物理删除)。
DB_DELETED
当事务修改数据时,不会直接覆盖旧数据,而是生成一个新的版本,并通过回滚指针关联旧版本,形成一条 “版本链”。
undo 日志:版本链的存储载体
每次修改数据时,旧版本会被写入 undo 日志( undo log ),用于:
事务回滚(撤销修改);
供 MVCC 的读操作访问历史版本。
版本链的头部是最新版本,尾部是最早的历史版本。
Read View:判断版本可见性的 “快照”
当事务执行 “快照读”(如,不加锁的读)时,数据库会生成一个Read View(读视图),作为判断数据版本是否对当前事务可见的依据。
select * from table
Read View 包含 4 个核心参数:
:当前活跃(未提交)的事务 ID 列表。
m_ids:
min_trx_id中最小的事务 ID。
m_ids:下一个将要分配的事务 ID(即当前最大事务 ID+1)。
max_trx_id:生成该 Read View 的事务 ID。
creator_trx_id
可见性规则:对于版本链中的某个数据版本(其为
DB_TRX_ID):
trx_id
若:当前事务修改的版本,可见。若
trx_id == creator_trx_id:修改该版本的事务已提交,可见。若
trx_id < min_trx_id:修改该版本的事务在当前事务之后启动,不可见。若
trx_id > max_trx_id:若
min_trx_id ≤ trx_id ≤ max_trx_id在
trx_id中(事务未提交),不可见;否则(已提交),可见。
m_ids
事务会从版本链头部开始,依次判断每个版本是否符合可见性规则,直到找到第一个可见版本。
不同隔离级别的 MVCC 差异
读已提交(Read Committed):每次执行快照读时,都会重新生成 Read View。因此,同一事务中两次读可能看到不同结果(能读到其他事务已提交的修改)。可重复读(Repeatable Read):仅在事务第一次执行快照读时生成 Read View,之后复用该视图。因此,同一事务中多次读结果一致(不受其他事务提交影响)。
快照读的完整流程(三部分协同)
事务发起快照读:例如执行(不加锁)。生成 Read View:根据隔离级别,生成一次或复用之前的 Read View(包含
select * from t where id=1、
m_ids等参数)。遍历版本链:从数据最新版本开始,通过
min_trx_id依次访问历史版本(从内存到 Undo 日志)。判断可见性:对每个版本的
DB_ROLL_PTR应用 Read View 的规则,找到第一个符合条件的可见版本。返回结果:将该可见版本的数据返回给事务,完成快照读。
DB_TRX_ID
| 问题 | 高分答案 |
|---|---|
| 1️⃣ 什么是快照读(Snapshot Read)? | 读取的是历史版本的数据,不加锁。典型如 |
| 2️⃣ 什么是当前读(Current Read)? | 读取的是最新版本的数据,并加锁。典型如 |
| 3️⃣ InnoDB 的 MVCC 是通过哪些机制实现的? | 通过三部分:① undo log(回滚日志) ② 隐藏列(trx_id、roll_pointer) ③ Read View(读视图) |
| 4️⃣ undo log 在 MVCC 中起什么作用? | 存储旧版本数据,通过回滚指针(roll_pointer)可以访问历史版本,实现快照读取。 |
| 5️⃣ Read View 是什么? | 表示一个事务能“看到”的事务版本范围,是一个由一组事务 ID(trx_id)构成的视图。 |
| 6️⃣ 不同隔离级别下 MVCC 的表现? | – 读已提交(RC):每次读取都会生成新的 Read View(看到最新提交的版本)。 – 可重复读(RR):同一事务内多次读取共用一个 Read View(看到一致的快照)。 |
| 7️⃣ MVCC 能解决哪些问题? | 解决读写冲突,提高并发性能,避免加锁带来的阻塞。 |
| 8️⃣ MVCC 能否解决幻读? | 在 RR(可重复读) 下,普通快照读不能防止幻读,但当前读 + 间隙锁可以避免幻读。 |
| 9️⃣ MVCC 适用于哪些语句? | 适用于非锁定读(普通 SELECT),不适用于加锁操作(UPDATE、DELETE、SELECT FOR UPDATE)。 |
| 🔟 MVCC 的核心优势? | “读不阻塞写,写不阻塞读”,提升事务并发度。 |
CheckPoint
| 类别 | 具体类型/方面 | 详细说明 | 触发条件/特点 | 影响与用途 |
|---|---|---|---|---|
| 基本概念 | 定义 | 数据库一致性状态标记 | 内存与磁盘数据的协调点 | 数据持久性保障机制 |
| 核心目的 | 保证数据一致性、提高恢复效率 | 协调WAL机制 | 崩溃恢复、日志回收、性能优化 | |
| 工作原理 | 无Checkpoint问题 | 数据丢失风险大、恢复时间长 | 崩溃时全部重做日志 | 系统不可用 |
| 有Checkpoint方案 | 定期刷脏页、标记恢复点 | 从最后Checkpoint恢复 | 快速恢复、空间回收 | |
| 类型对比 | Sharp Checkpoint | 完全检查点 | 数据库关闭、备份时 | 高I/O压力,数据完全同步 |
| Fuzzy Checkpoint | 模糊检查点 | 运行期间定期触发 | 主流方式,性能友好 | |
| InnoDB实现 | Master Thread | 定时检查点 | 每秒/每十秒异步执行 | 维持系统健康状态 |
| FLUSH_LRU_LIST | LRU列表检查点 | 空闲页不足时 | 保证Buffer Pool空间 | |
| Async/Sync Flush | 日志刷新检查点 | Redo Log使用率>75%/90% | 防止Redo Log写满 | |
| Dirty Page Too Much | 脏页过多检查点 | 脏页比例超过阈值 | 控制内存脏页数量 | |
| 数据库对比 | MySQL InnoDB | 自动Fuzzy Checkpoint | 参数控制触发条件 | 生产环境主流方案 |
| PostgreSQL | Checkpoint Process | 时间与日志大小触发 | WAL管理机制 | |
| SQL Server | 自动+手动检查点 | 恢复间隔控制 | 灵活的手动控制 | |
| 执行流程 | 步骤1 | 开始最小事务 | 保证操作原子性 | 一致性保障 |
| 步骤2 | 记录当前LSN | 获取日志序列号 | 确定恢复起始点 | |
| 步骤3 | 写入检查点信息 | 持久化元数据 | 崩溃恢复依据 | |
| 步骤4 | 刷脏页到磁盘 | 根据类型刷页 | 数据持久化 | |
| 步骤5 | 提交检查点 | 完成操作 | 检查点生效 | |
| 参数配置 | 检查点频率 | 执行时间间隔 | 太频繁影响性能 | 平衡性能与恢复时间 |
| 脏页阈值 | innodb_max_dirty_pages_pct | 通常70-80% | 控制刷盘频率 | |
| 日志大小 | Redo Log文件大小 | 足够避免频繁触发 | 减少强制检查点 | |
| 优势代价 | 优势 | 快速崩溃恢复 | 从最近点恢复 | 提高可用性 |
| 优势 | 日志空间回收 | 循环使用Redo Log | 资源高效利用 | |
| 代价 | I/O压力增大 | 刷脏页操作 | 可能性能抖动 | |
| 代价 | 实现复杂度高 | 需要精细调参 | 运维成本 | |
| 应用场景 | OLTP系统 | 高频检查点 | 快速恢复需求 | 保证业务连续性 |
| 数据仓库 | 低频检查点 | 批量加载优先 | 优化加载性能 | |
| 高可用集群 | 协调检查点 | 多节点一致性 |
————————————–
MySQL为什么用B+树不用其他树结构?
MySQL的InnoDB存储引擎使用B+树作为索引的数据结构,主要是因为它相比其他树结构(如二叉树、B树、哈希表)在磁盘I/O和范围查询方面有巨大优势。

B+树的核心优势:
更矮胖的树,磁盘I/O次数更少
B+树的一个节点(通常设置为一个页的大小,如16KB)可以存储非常多的索引键(比如上千个),使得树的高度非常低(3-4层就能存储千万级数据)。这意味着查找任何记录最多只需要3-4次磁盘I/O。
非常适合范围查询
B+树的所有数据都存储在叶子节点,并且叶子节点之间通过指针相连形成双向链表。进行范围查询时,只需要找到起始点,然后沿着链表顺序遍历即可,效率极高。
查询效率更加稳定
任何查询都需要从根节点走到叶子节点,路径长度相同,查询时间稳定。
更利于全表扫描
只需要遍历叶子节点的链表即可,相当于对索引进行了一次顺序遍历。
总结:B+树是为磁盘存储和数据库查询模式(特别是范围查询)量身定做的数据结构。
联合索引ABC三列,查询条件只有AC会怎么样?
这是一个关于最左前缀原则的经典问题。
结论:联合索引 (A, B, C) 在只有 WHERE A = ? AND C = ? 的条件下,只能使用到索引的A列,无法使用C列。
总结:
WHERE A AND C 只能部分使用索引(A列)。SELECT A, B, C 是索引覆盖查询,效率极高。SELECT * 需要回表,效率取决于筛选出的数据量。
分库分表:既能按user_id查,也能按order_id查
分库分表:既能按user_id查,也能按order_id查
对于核心交易订单类业务,为了保证强一致性和高可用性,通常采用方案一(双写),并通过消息队列的最终一致性来降低双写的复杂性。对于查询维度多的业务,方案三(查询分离) 也非常流行。
InnoDB实现事务
修改前先写Undo Log,修改后先写Redo Log,最后再改内存。提交时只保证Redo Log落地即可。
————————————————
RDB和AOF
RDB 是“快照”,小而快,但会丢数据;AOF 是“日志”,大而全,但恢复慢。两者结合是王道。

Redis过期键删除策略
Redis 的过期键删除是惰性删除和定期删除的协同合作:
“防君子” (定期删除):
定期删除像个巡逻的保安,每隔一段时间就随机抽查一些键,清理掉过期的。它保证了即使某些键永不被访问,也有很大概率被清理掉。
“防小人” (惰性删除):
惰性删除像个门口的安检,任何键在被使用时都必须先过安检(检查是否过期)。它保证了你读到的数据绝对是有效的,没过期的。
Redis事务的实现
Redis 事务是一个提供了命令打包和隔离执行功能的批处理脚本,它缺乏回滚机制,但可以通过 WATCH 命令来实现简单的乐观锁并发控制。 不要把它和关系型数据库的 ACID 事务混为一谈。
Redis 事务的本质是:将多个命令打包,然后按顺序一次性、串行化地执行。在执行过程中,不会被其他客户端的命令请求所打断。
它不保证原子性(Atomicity)在数据库意义上的“全部成功或全部失败”,它更像一个命令批处理(Batch)的脚本。
MULTI – 开启事务
输入 MULTI 命令后,Redis 会将客户端从“普通模式”切换到“事务模式”。
此后,客户端发送的所有命令(除了 EXEC, DISCARD, WATCH 等管理命令)不会被立即执行,而是被 Redis 服务器放入一个队列中。入队命令
在 MULTI 之后,你输入的所有操作命令(如 SET, GET, SADD 等)都会收到一个 QUEUED 的回复,表示命令已进入队列,正在等待执行。EXEC – 执行事务
当你输入 EXEC 命令时,Redis 会按顺序依次执行队列中的所有命令。
所有命令的执行结果会以一个数组的形式一次性返回给客户端。DISCARD – 取消事务
在 MULTI 之后、EXEC 之前,你可以输入 DISCARD 来清空事务队列并退出事务模式。
数据库 (如MySQL): 全部成功或全部失败。失败后会自动回滚。
Redis:
Redis 事务在执行 (EXEC) 过程中是原子的:一旦开始执行,所有命令都会被执行完毕,中间不会插入其他命令。
但它没有回滚能力! 如果在 EXEC 执行过程中某条命令出错了(例如对字符串执行 SADD 操作),Redis 不会停止事务,也不会撤销之前已执行的命令。它会继续执行队列中的剩余命令,并且之前命令的错误不会影响后续命令。
只有在命令入队时发生的语法错误(例如命令名写错),才会导致整个事务在 EXEC 时被拒绝执行。
乐观锁Watch:
是什么? WATCH 命令用于监视一个或多个 key。如果在 EXEC 命令执行之前,这些被监视的 key 被其他客户端修改了,那么整个事务将会被放弃(执行 EXEC 时会返回 nil,表示事务失败)。

MVCC
MVCC在MySQL InnoDB中的实现主要是为了提高数据库并发性能,用更好的方式去处理读-写冲突,做到即使有读写冲突时,也能做到不加锁,非阻塞并发读MVCC就是为了实现读-写冲突不加锁,而这个读指的就是快照读, 而非当前读,当前读实际上是一种加锁的操作,是悲观锁的实现MVCC + 悲观锁 MVCC解决读写冲突,悲观锁解决写写冲突
MVCC + 乐观锁 MVCC解决读写冲突,乐观锁解决写写冲突
MVCC实现
MVCC模型在MySQL中的具体实现则是由 4个隐式字段,undo日志 ,Read View 等去完成的,具体可以看下面的MVCC实现原理
隐藏字段
DB_ROW_ID 6byte, 隐含的自增ID(隐藏主键),如果数据表没有主键,InnoDB会自动以DB_ROW_ID产生一个聚簇索引DB_TRX_ID 6byte, 最近修改(修改/插入)事务ID:记录创建这条记录/最后一次修改该记录的事务IDDB_ROLL_PTR 7byte, 回滚指针,指向这条记录的上一个版本(存储于rollback segment里)DELETED_BIT 1byte, 记录被更新或删除并不代表真的删除,而是删除flag变了
undo logRead View
Read View就是事务进行快照读操作的时候生产的读视图(Read View),在该事务执行的快照读的那一刻,会生成数据库系统当前的一个快照,记录并维护系统当前活跃事务的ID(当每个事务开启时,都会被分配一个ID, 这个ID是递增的,所以最新的事务,ID值越大)m_ids 一个列表,包含了在生成 Read View 那一刻,系统中所有活跃(即尚未提交)的事务的 ID。min_trx_id m_ids 集合中的最小值。如果 m_ids 为空,则 min_trx_id 为 max_trx_id。max_trx_id 生成 Read View 时,系统应该分配给下一个事务的 ID。注意:并不是当前最大事务ID,而是最大值+1creator_trx_id 创建这个 Read View 的事务本身的 ID。对于一个只读事务,这个值可能是 0。
慢查询日志的作用
定义:记录执行时间超过 秒的 SQL。
long_query_time
作用:
定位性能瓶颈,分析哪些 SQL 执行慢;配合 分析执行计划;优化索引、SQL 结构;监控业务性能随时间的变化。
EXPLAIN
开启方式:
set global slow_query_log = 1;
set global long_query_time = 1;
redo log 保证事务的持久性(Durability)
作用:在事务提交前,InnoDB 先把修改写入 redo log buffer;即使数据库宕机,只要 redo log 已落盘,就能在恢复时重放日志,确保事务结果不会丢失。流程(WAL 机制:Write-Ahead Logging):
事务执行 → 修改缓存在 Buffer Pool;同时记录修改操作到 redo log buffer;事务提交时,将 redo log buffer 刷盘(fsync);若系统崩溃,恢复时根据 redo log 重做未落盘的页。
页修改之后为什么不直接刷盘?
原因:
磁盘 IO 成本高:每次修改都写盘会极大影响性能;局部性差:随机写非常慢;多次修改同一页没必要每次都刷盘;解决方案:先写 redo log(顺序写、效率高),之后由后台线程(如 )定期把 Buffer Pool 的脏页刷回磁盘。
flush_list
机制名称:这就是 WAL(Write Ahead Logging)策略。
binlog 和 redo log 的区别
| 对比项 | binlog | redo log |
|---|---|---|
| 所属层 | Server 层(所有引擎通用) | InnoDB 引擎层 |
| 记录内容 | 逻辑操作(如“给 id=1 的行加1”) | 物理页修改(某页某偏移量写入什么) |
| 写入时机 | 事务提交时一次性写入 | 事务执行过程中不断写入 |
| 用途 | 主从复制、恢复数据 | 保证事务持久性、Crash 恢复 |
| 是否循环使用 | 否,会不断生成新文件 | 是,固定大小循环使用 |
| 是否与引擎绑定 | 否 | 是(InnoDB 专属) |
undo log 如何保证事务的原子性(Atomicity)
作用:记录事务执行前的数据快照(即被修改前的值)。机制:
当事务修改一条记录时,InnoDB 生成一条 undo log;若事务执行失败或回滚,InnoDB 可根据 undo log 恢复到修改前的状态;事务提交后,undo log 进入回收阶段,由后台线程异步清理。
同时:undo log 也是 MVCC(多版本并发控制) 的关键基础,用于“可重复读”场景下的历史版本读取。
MySQL读的时候会上锁吗
取决于引擎与 SQL 类型:
InnoDB(默认):普通 (非
SELECT /
FOR UPDATE)通常不加行锁,而是使用 MVCC(一致性读) 来读取历史快照(不阻塞写,也不被写阻塞,表层面可能有意向锁但不影响普通读取)。
LOCK IN SHARE MODE
例外:若 使用
SELECT 或
FOR UPDATE,则会加行级锁(共享/排他)。有时在非重复读/可重复读设置下,某些读取会改用当前读(如
LOCK IN SHARE MODE 进行索引查找并返回最新值,会对二级索引记录加读锁?这较少见,通常是行锁在有显式锁定或一致性读之外的操作才会出现)。
SELECT ... WHERE x = const
MyISAM:读操作会在表级加读锁(阻塞写)。Memory 引擎:根据配置可能有锁。
总结:在 InnoDB 下,普通读取不会主动加行锁(依赖 MVCC),而显式锁才会加锁。
MVCC底层原理?
核心思想:为每个行的不同版本保留历史版本(通过 undo log/回滚链),读操作读取事务快照而不是当前写入,读不阻塞写,写只影响版本链。
InnoDB 实现要点:
每行记录头 存储隐藏字段:(创建/修改该行的事务 id)、
DB_TRX_ID(指向 undo log 的指针,链向旧版本)。undo 日志(回滚段):新旧版本数据存放在 undo 日志中(用于回滚与版本回溯)。当事务修改行时,InnoDB 会把旧版本写入 undo,并把行头的
DB_ROLL_PTR 指向该 undo。事务 ID(trx_id):每个事务开始获得一个递增的事务号,用于版本比较。Read View(快照):读取时创建一个快照(read view),该快照包含当前活跃事务集合或边界信息(见下题),决定哪些修改对当前读可见。读时回溯:当读到一条行时,若该行由较新的 trx 修改,读取者会通过
DB_ROLL_PTR 回溯 undo,直到找到对当前 read view 可见的版本,然后返回该版本。GC(purge):当所有可能的读快照都不再需要某些历史版本时,后台 purge 线程会回收 undo 日志,释放空间。
DB_ROLL_PTR
Read View 底层是什么?四个字段是存储在哪里的?
概念:Read View 是 InnoDB 为事务一致性读构建的“快照”,用于判断哪些事务的更改对当前读可见。Read View 的内容决定了读者是否需要沿 undo 链寻找旧版本。
典型包含的字段(概念性“四个字段”):(不同资料表述略有差异,但核心是这些元信息)
creator_trx_id:创建该 read view 的事务 id(表示谁创建了快照)。low_limit_trx_id / first_active_trx_id:最老的活跃事务 id(低边界),任何 trx id < low_limit 都被视为已提交且可见。up_limit_trx_id / next_trx_id:下一个将用于分配的 trx id(高边界),通常等于当前分配器值。active_trx_id_list(或 snapshot list):当前活跃事务的 id 列表(read view 保存了在创建时刻仍然活跃、可能与读共享冲突的事务集合)。
存储位置:
Read View 作为运行时数据结构(C 结构体)保存在 InnoDB 内存中(和事务结构相关联),不是持久化到磁盘的。当事务执行一致性读时,InnoDB 会在内存中创建一个 Read View 对象并挂到该事务的上下文里。行的版本信息(,
DB_TRX_ID)存储在数据页/记录头和 undo log(磁盘)上;Read View 用来比较这些字段判断可见性。
DB_ROLL_PTR
总结:Read View 保存了创建快照时刻的事务视图(活跃事务集合/边界信息),在内存中维护;行版本与 undo 指针实际存放在磁盘页(记录头)与 undo 区域。
Redo Log 满了怎么办?什么时候清除?清除的是哪些数据?
满了怎么办: Redo Log 文件是循环写入的,有固定大小。当写满时,会强制触发 Checkpoint 操作,将缓冲池中已经提交的脏页刷新到磁盘的数据文件中。在此期间,所有新的 DML 操作都会被阻塞,直到有可用的 Redo Log 空间。所以,如果 Redo Log 设置过小,会导致频繁的 Checkpoint,影响性能。什么时候清除: 当 Redo Log 文件写满,或者系统比较空闲时,会触发 Checkpoint。清除哪些数据: 清除的是 已经被刷新到磁盘数据文件中的旧 Redo Log 记录。Checkpoint 会标记一个位置,表示这个位置之前的 Redo Log 对应的数据修改都已经持久化到磁盘了,那么这些 Redo Log 占用的空间就可以被安全地覆盖重用。
是事务执行过程中边写 Redo Log 边写数据,还是 Commit 的时候写?先写数据还是先写 Redo Log?
这个过程遵循 WAL 原则。
事务执行过程中:
数据修改首先在 Buffer Pool 中进行。同时,这些修改会立即被顺序地写入到 Redo Log Buffer 中。
事务提交时:
根据 的设置,将 Redo Log Buffer 中的内容 刷新到磁盘的 Redo Log 文件 中。一旦 Redo Log 落盘,即使此时 Buffer Pool 中的脏页还没有刷盘,事务的持久性也已经得到保证。
innodb_flush_log_at_trx_commit
后台进程:
InnoDB 有专门的线程,在合适的时机将 Buffer Pool 中的 脏页 刷新到磁盘的数据文件中。
结论:
先写 Redo Log,后写数据文件。Redo Log 是 顺序写,而数据文件是 随机写,顺序写的性能远高于随机写。通过 WAL 机制,将随机写转换为了顺序写,大大提升了数据库的写入性能和数据恢复能力。


