内连接:通过条件查询,两个表求交集(结果求交集,条件都满足)
外连接:左外连接,右外连接,全外连接
左外连接:左表查询出来的结果在结果集中一定有,右表不满足的用null代替
右外连接:右表查询出来的结果在结果集中一定有,左表不满足的用null代替
全外连接:左表和右表的并集
- DDL:数据定义语言 — 定义修改数据库结构
- DML:数据操作语言 — 增删改
- DQL:数据查询语言 — 查
- DCL:数据控制语言 — 权限
- TCL:事务控制语言
- 主键约束 : primary
- 唯一约束 : unique
- 外键约束 : foreignkey
- 非空约束 : not null
- 检查约束 : check
- 默认约束 : default
视图是虚拟表,并不是真实存在的,主要用来存储查询语句的返回结果;视图实际上是存储查询,并不存储数据本身,当基本表的数据发生更改时,视图会自动反应变化
作用:
1.简化复杂查询
2.限制用户查询查询子集,保证数据的安全性
3.视图提供逻辑数据独立性,当基础表的结构发生变化时,如果这些变化被隐藏在视图后面
更改:
1.间接改变视图:当基本表改变时,视图中对应数据会自动反映
2.直接改变视图:取决于视图的类型和定义,某些视图是支持更新操作的,但大多数情况下,尤其是那些包含JOIN、GROUP BY等复
杂操作的视图,是不可更新的。直接改变视图(可以看作一张表)时,有时候会检查条件是否满足,这主要取决于查询语句有没有检
查条件,cascade会级联检查关联的视图,local仅检查当前视图的条件。
- 事务:是一组不可分割的原子操作,要么全部成功,要么全部失败。有ACID四个特性,包括原子性、一致性、持久性、隔离性。
- 锁:是数据库管理系统控制并发访问的核心机制,通过限制多个事务同时操作共享资源(如数据行、表等),确保数据的一致性和完整性。主要用来解决脏读、不可重复读、幻读;锁主要有两种,排他锁和共享锁。
(ACID)
- 原子性:事务的所有操作要么全部完成,要么全部不完成,不存在中间状态。主要通过undolog(回滚日志)来实现,记录事务对数据修改的反向操作,用于回滚事务未提交或失败的事务。
- 持久性:事务提交后,对数据的修改是永久的,即时系统崩溃也能恢复。主要通过redolog(重做日志)和 Binary Log(Binlog,二进制日志),redolog记录物理层面的数据修改,用于崩溃恢复时重建数据;Binary记录数据库的逻辑变更(如SQL语句),用于主从复制和数据恢复。
- 隔离性:事务之间互不干扰,一个事务的中间结果对其他事务不可见。主要通过锁机制和MVCC实现。
- 一致性:事务执行前后,数据库从一个合法状态转换到另一个合法状态,符合业务规则(如约束、触发器等)。依赖其他三个特性。
- 读未提交:最低隔离级别,允许事务读取其他事务未提交(未提交即可能回滚)的数据。可能会出现脏读、不可重复读、幻读
- 读已提交:事务只能读取其他事务已提交的数据。可能会出现不可重复读和幻读。
- 可重复读:事务内多次读取同一数据的结果始终一致(除非本事务自己修改)。可能会出现幻读
- 串行化:最高隔离级别,事务串行执行,完全避免并发问题。
- 脏读:读到另一个事务未提交数据
- 不可重复读:同个事务中读取同一数据结果不一样。
- 幻读:事务内多次查询同一条件的结果集数量不一样
- 按锁的粒度分:页级锁、表级锁、行级锁
- 按锁的模式分:排他锁、共享锁、意向锁
- 按使用方式划分:悲观锁、乐观锁
- 特殊锁类型:间隙锁、临键锁、元数据锁
1.悲观锁在事务开始时就对数据加锁,直到事务结束才释放锁。在高并发场景下,多个事务对同一资源的请求会被阻塞,导致系统吞吐量降低。
2.有死锁风险,多个事务互相等待对方释放锁,循环等待,导致系统僵局
3.会造成其他线程阻塞和等待,用户体验差
1.占用一定的存储空间
2.写操作变慢,在进行写操作时,也要同步维护索引
3.维护成本变高
- 按索引性质分:唯一索引、主键索引、普通索引
- 按数据结构分:B+树索引、Hash索引、全文索引
- 按字段范围分:单列索引、联合索引
- 按存储位置分:聚簇索引、非聚簇索引
- 按其他特性分:覆盖索引、空间索引、前缀索引
聚簇索引底层的数据结构是B+树,MySQL数据库对其进行了优化,添加了指向相邻节点的指针,其核心特点是数据行的物理存储顺序与索引键的逻辑顺序一致。聚簇索引支持范围查询,且非叶子结点存储键值,可以存储更多的数据,每个结点可以有多个子节点,所以树的层级较浅,查询速度快。通过数据与索引物理合一的结构,显著提升了范围查询、主键查询和关联操作的性能,但需权衡写入开销和主键设计
1.对常用于查询、排序、分组的字段建立索引
2.对查询频繁的表建立索引
3.尽量使用联合索引。减少单列索引,查询时,联合索引很多时候可以覆盖索引,节省空间
4.减少 I/O:通过索引、缓存和分区。
5.降低锁竞争:优化事务和并发控制。
6.持续监控与调优:根据实时数据调整策略。
- 针对于数据量较大,且查询比较频繁的表建立索引。
- 针对于常作为查询条件(where)、排序(order by)、分组(group by)操作的字段建立索引。
- 尽量选择区分度高的列作为索引,尽量建立唯一索引,区分度越高,使用索引的效率越高。
- 如果是字符串类型的字段,字段的长度较长,可以针对于字段的特点,建立前缀索引。
- 尽量使用联合索引,减少单列索引,查询时,联合索引很多时候可以覆盖索引,节省存储空间,避免回表,提高查询效率。
- 要控制索引的数量,索引并不是多多益善,索引越多,维护索引结构的代价也就越大,会影响增删改的效率。
- 如果索引列不能存储NULL值,请在创建表时使用NOT NULL约束它。当优化器知道每列是否包含NULL值时,它可以更好地确定哪个索引最有效地用于查询。
1.选择合适的连接类型。
2.在关联字段上考虑建立索引
3.尽可能的缩小查询范围
分库分表的核心目的是解决单库单表的性能瓶颈和扩展性问题:
1.分表方法:
2.分库方法:
通过以下机制实现数据同步与一致性:
1.主从复制:
- 异步复制:主库不等待从库确认,延迟低但可能丢失数据。
- 半同步复制:主库等待至少一个从库确认后再返回,平衡延迟与可靠性。
- 全同步复制:主库等待所有从库确认,延迟高但数据零丢失(需权衡性能)。
2.中间件管理:
- 使用ShardingSphere等工具统一管理分片数据,确保分片间数据路由和事务一致性。
- 定期校验数据(如_checksum校验),修复主从不一致问题。
3.冲突处理:
- 避免跨分片事务,或通过分布式事务(如Seata)保证最终一致性。
- 通过唯一约束和幂等设计减少数据冲突。
常见问题:
脏读、不可重复读、幻读:事务隔离级别不足导致读到未提交或中间状态的数据。
锁竞争:高并发读写时,行锁或表锁导致读请求阻塞。
热点数据读慢:频繁访问同一数据页,导致缓存命中率低或锁竞争加剧。
解决方案:
- 调整事务隔离级别:使用READ COMMITTED(默认)或REPEATABLE READ(InnoDB默认)避免脏读和不可重复读。
- 优化索引与查询:确保查询命中索引,减少全表扫描和锁范围。
- 读写分离:将读请求分发到从库,降低主库压力(需处理主从延迟问题)。
- 缓存加速:使用Redis/Memcached缓存高频读数据,减少直接访问数据库。
- 水平扩容:通过分库分表分散读压力,避免单点成为瓶颈。
- 减少热点:采用哈希分片分散热点数据,或设计业务逻辑避免集中访问。
1NF:数据库表中的字段必须是单一值,即每个字段都只能包含一个值,不能存储多个值或重复组。
2NF:除了满足第一范式外,还要求所有非主键字段完全依赖于整个主键,而不是部分主键(适用于复合主键的情况)。
3NF:除了满足第二范式外,还要求所有非主键字段直接依赖于主键,不允许存在传递依赖(即非主键字段A依赖于另一个非主键字段B,而B又依赖于主键)。
- 事务日志:记录数据库中所有事务及其对数据所做的更改
- 重做日志(redo log):主要用于数据库恢复过程。它记录了所有已提交但尚未写入数据文件的更改信息。在数据库崩溃后重启时,可以使用这些日志重新应用这些更改,以恢复到崩溃前的状态。
- 撤销日志(undo log):用于支持事务回滚操作。当一个事务需要被回滚时,撤销日志包含了必要的信息来撤消该事务执行的所有更改,使数据库返回到事务开始之前的状态。
- 归档日志:对于一些数据库管理系统,当重做日志文件达到一定大小或条件时,会自动将它们归档。归档日志对于时间点恢复(Point-in-Time Recovery)非常重要,因为它允许从某个历史时刻的数据状态进行恢复。
- 错误日志:包含数据库运行期间发生的各种错误信息、警告以及关键的通知。这些日志对于诊断和解决数据库运行中的问题非常有用。
- 审计日志:记录数据库用户的行为,特别是安全相关的活动,如登录尝试、权限变更等。这有助于监控数据库的安全状况,并满足合规要求。
- 主键:是一列或一组列,用于标识唯一的一行,每个表中只有一个主键,并且主键值不为null
- 超键:一列或多个列的集合,,其中包含足够的信息来唯一标识表中的每一行记录。换句话说,超键是能够唯一确定表中一行的所有属性集。
- 候选键:候选键是最小超键,没有冗余的属性。
- 外键:外键是一个列或一组列的组合,其值与另一个表的主键(或候选键)相匹配。外键用于建立和加强两个表之间的连接,维护引用完整性。
- DROP 语句用于删除数据库对象,如表、视图等。对于表而言,它不仅删除了表中的所有数据,还删除了表的结构定义。
- DELETE用于删除表中行数据
- TRUNCATE 是一个DDL(数据定义语言)操作,它会快速地移除表中的所有数据,而不删除表本身。
- IN:当使用 IN 子查询时,外部查询会等待子查询返回所有符合条件的结果集,然后逐一比较外部查询的每一行是否在这个结果集中。
- EXISTS:EXISTS 子查询则是基于“存在性检查”,即一旦找到匹配项就会立即停止搜索并返回结果,不会继续检查剩余的记录。因此,EXISTS 更加高效,特别是在子查询可能返回大量数据的情况下。
在MySQL中,默认的事务隔离级别是 可重复读(Repeatable Read)。这是由InnoDB存储引擎提供的默认设置。在这个隔离级别下,事务能够看到自己所做的一系列变更,并且在同一事务内的多次读取之间不会看到其他事务所做的更改,除非这些更改被提交。这意味着,在一个事务内执行的多次相同查询会得到同样的结果,即使在这期间有其他事务对数据进行了修改并提交。
读未提交: 事务隔离级别的最低级别,一个事务读到另一个事务未提交数据,可能出现脏读、不可重复读和幻读
读已提交:只允许一个事务读另一个事务已提交事务,可能会出现不可重复读和幻读
可重复读:默认的事务隔离机制,事务内多次读取同一数据前后保持一致,可能会出现幻读。
串行化:事务隔离级别的最高级别,事务串行执行。
- 全文扫描:没有索引的阶段
- 二叉排序树(BST):解决全文扫描效率低
- 平衡二叉树:解决BST的不平衡问题。
- B-tree索引:为适应磁盘I/O特性,解决平衡二叉树的I/O效率问题。
- B+tree索引:在B树基础上进一步优化,成为数据库索引的主流结构(如InnoDB的默认索引)。
- hash索引:针对等值查询(如WHERE id = 1)的极致优化。
- InnoDB:支持事务,支持行锁,支持外键,支持B+树索引和自适应Hash索引
- MyISAM:不支持事务,支持表锁,支持B+树索引
- Memory:不支持事务,支持表锁,支持B+树索引和Hash索引,存储在内存中,
InnoDB引擎通过多版本并发控制(MVCC, Multi-Version Concurrency Control)来提高数据库的并发性能,并实现非锁定读取。MVCC允许查询操作读取旧版本的数据,而写操作则可以创建新版本的数据,这样就减少了读写操作之间的冲突。
主要通过隐藏字段、undo日志(版本链)、readView(读视图)实现
隐藏字段:
- DB_TRX_ID:最近更改这行记录的事务ID,每次修改都会更新此值。
- DB_ROLL_PTR:回滚指针,指向undo日志记录,用于存储旧版本的数据。
- MyISAM:不支持Hash索引,不支持事务,不支持外键,支持表锁
- InnoDB:支持自适应Hash索引,支持事务,支持外键,支持行锁
1.性能损耗。外键需要依赖索引实现约束,每次插入、更新或删除数据时,数据库必须维护外键关联的索引(如主表的主键索引和从表的外键索引),导致额外的I/O操作和计算开销。
2.并发风险。高并发场景下,多个事务可能同时操作关联表(如订单和订单项),数据库需为外键约束加锁,导致锁竞争加剧,甚至引发死锁
3.分布式系统的不兼容性。当数据量增大时,通常需要分库分表。但外键约束无法跨数据库或分片生效,导致关联表可能分布在不同节点,无法保证数据一致性
4.开发灵活性降低,外键的存在限制了表结构的修改(如删除主表字段需先处理从表约束),增加维护复杂度。
物理删除:delete语句直接删除行数据,这样就在数据库中删除了
逻辑删除:在表中添加字段用以标识是否删除(is_deleted),数据物理上还存在
日常开发中,两种方式都会涉及到,物理删除主要是那些不太重要的数据,缓存(如缓存),逻辑删除主要用于类似于订单表这种,需要后续进行审计
内连接:通过条件查询,两个表求交集(结果求交集,条件都满足)
外连接:左外连接,右外连接,全外连接
左外连接:左表查询出来的结果在结果集中一定有,右表不满足的用null代替
右外连接:右表查询出来的结果在结果集中一定有,左表不满足的用null代替
全外连接:左表和右表的并集
自连接:自连接(Self Join) 是一种 SQL 语句中的连接操作,指将同一张表视为两个或多个独立的表,通过表的别名(Alias)进行连接,从而实现对表内数据的关联查询。它主要用于处理表中存在层次关系或行间关联的场景,例如员工与经理的关系、分类的父子层级等。例如员工与经理、分类的父子层级、组织结构等。
-- 查询员工及其经理的姓名
SELECT
e1.name AS employee_name,
e2.name AS manager_name
FROM
employee e1 -- 别名 e1 表示员工
INNER JOIN
employee e2 -- 别名 e2 表示经理
ON
e1.manager_id = e2.id; -- 关联条件:员工的经理ID等于经理的ID
会锁表,但锁表时间取决于 MySQL 版本和配置。
- 数据一致性保障:创建索引时,数据库需要确保索引构建过程中数据的一致性。如果允许其他事务同时修改数据(如插入、更新或删除),可能会导致索引构建过程中数据不一致(例如索引未包含新插入的行,或包含已删除的行)
- 操作原子性:索引创建是一个原子性操作,必须保证要么完全完成,要么完全回滚。锁表可以避免中途中断导致索引损坏。
- 聚簇索引:在主键上创建(若未显式定义主键,InnoDB 自动创建隐藏主键),叶子结点存储的是行数据(数据与索引物理上合并),每个表只能有一个。
- 非聚簇索引:非主键字段上创建,叶子结点存储的是主键,每个表可以生成多个。
主键索引通常是聚簇索引,但聚簇索引不一定是主键索引(依赖表设计)。其生成规则优先主键,次选唯一非空索引,最后生成隐藏ROWID。
关系型数据库以结构化数据和强事务为核心,适合复杂业务;非关系型数据库以灵活性和扩展性为优势,适合海量数据和高并发场景。选择时需根据业务需求权衡一致性、扩展性和查询复杂度。
关系型数据库:
- 结构化数据,基于表格(行和列),遵循关系模型
- 支持ACID事务(原子性、一致性、隔离性、持久性),保证强一致性,
- 使用SQL(结构化查询语言),支持复杂查询(如JOIN、事务)。
- 水平扩展困难,依赖分库分表
非关系数据库:
- 支持文档、键值、图等模型
- 使用自定义查询语言(如MongoDB的JSON查询、Redis的命令行),灵活性高
- 通常弱化事务支持(如Redis支持单命令原子性,但不保证多命令事务)
- 天然支持水平扩展,适合海量数据和高并发场景(如NoSQL的分布式设计)。
1.建立连接:客户端与 MySQL 服务建立通信连接。
2.查询缓存:如果命中,快速返回缓存结果,避免重复执行相同查询。
3.SQL 解析:验证 SQL 语法并生成执行计划的输入。
4.查询优化:生成最高效的执行计划
5.查询执行:实际执行 SQL 并获取数据。
6.结果返回:将查询结果返回给客户端。
7.连接管理:维护连接状态或释放连接。
1.减少数据查询范围,解决全文扫描带来的效率低下
2.加速数据查找范围
3.优化排序和分组操作
索引的三种常见底层数据结构是 哈希表(Hash)、B+树(B+Tree) 和 有序数组(Sorted Array)
数据结构 | 等值查询 | 范围查询 | 插入/删除 | 空间开销 | 适用场景 |
---|---|---|---|---|---|
哈希表 | O(1) | 不支持 | O(1) | 低(无冗余) | 纯等值查询(缓存、键值存储) |
B+树 | O(log n) | O(log n) | O(log n) | 较高 | 通用数据库索引 |
有序数组 | O(log n) | O(log n) | O(n) | 最低 | 静态数据或只读场景 |
- B树索引:支持范围查询,InnoDB默认结构)。
- 哈希索引:(等值查询高效,无范围支持)。
- 唯一/主键索引:(约束唯一性,加速查询)。
- 聚集/非聚集索引:(数据存储方式差异)。
- 全文索引:(倒排索引,文本检索)。
- 复合索引:(多列联合查询,最左前缀原则)。
- MyISAM:主键索引的叶子节点存储数据地址(物理指针)。辅助索引的叶子节点存储数据地址(与主键索引结构相同)。
- InnoDB:主键索引的叶子节点存储行数据。辅助索引的叶子节点存储主键值(而非数据地址)。
- 节点存储效率更高:B+树的非叶子节点仅存储索引键值,不存储实际数据,因此每个节点可以容纳更多键值(例如,一个节点可存储数千个键),树的高度更矮。
- 减少磁盘访问次数:对于主键查询(如 SELECT * FROM table WHERE id=1),B+树的主键索引叶子节点直接存储数据行,只需一次 I/O(从根到叶子节点)。对于范围查询(如 WHERE age BETWEEN 20 AND 30),叶子节点的双向链表允许按顺序遍历,利用磁盘预读特性减少随机 I/O。
- 叶子节点有序且链表连接:B+树的叶子节点按键值顺序排列并形成链表,范围查询时只需遍历相邻节点,无需回溯到根节点。
- 插入/删除效率。树高稳定:B+树的高度通常在 3~4 层(即使数据量达到数十亿),插入/删除操作仅需调整局部节点,无需频繁重组树结构。页分裂优化:InnoDB 的页(Page)大小为 16KB,节点分裂时仅需调整指针,避免大规模数据移动。
- 数据有序性。天然支持排序和分组:B+树的有序性使 ORDER BY、GROUP BY 等操作无需额外排序,直接按叶子节点顺序读取即可。
覆盖索引:覆盖索引是指查询所需的所有字段都能在索引中找到,无需通过索引回表查询数据行
索引下推:索引下推是 InnoDB 在 5.6 版本引入的优化技术,允许在索引遍历时提前过滤条件,减少不必要的回表操作
1.头部模糊匹配
2.or前后没有同时使用索引
3.字符串没有用单引号
4.在索引列运算
5.如果MySQL评估使用索引比全表更慢,则不使用索引。
Change Buffer(写缓冲区) 是 InnoDB引擎 的一种优化机制,用于减少磁盘I/O,提升写操作(INSERT/UPDATE/DELETE)的性能。其核心思想是:将对非唯一二级索引的变更操作延迟合并到磁盘页中。
行扫描数(Rows Examined) 是MySQL执行查询时实际扫描的行数,通常通过 EXPLAIN 命令的 rows 列(预估行数)和 Rows_examined(实际行数)体现。
Redo Log:
- InnoDB内部机制,关注数据页的物理一致性。
- 必须存在,即使未开启Binlog。
- Crash-Safe:通过Redo Log保证事务即使崩溃也能恢复。
Binlog:
- MySQL服务器层功能,提供逻辑操作记录。
- 需手动开启,用于主从同步和逻辑恢复。
- 不保证实时性:仅在事务提交时写入。
保证事务持久性:
- 事务提交后,数据可能暂时只存在于内存的Buffer Pool中(脏页),若此时数据库崩溃,数据会丢失。
- Redo Log通过WAL(Write-Ahead Logging)机制,先将事务的物理修改记录到日志中(先写Redo Log,再写数据页),确保即使崩溃后也能通过日志恢复数据。
解决磁盘IO性能问题:
- 直接将数据页写入磁盘存在两大问题:
- 随机IO效率低:数据页可能分散在磁盘不同位置,频繁随机写入耗时。
- 浪费资源:修改少量数据需写入整个16KB数据页。
- Redo Log记录物理修改的最小变更(如页号、偏移量、新值),日志文件小且顺序写入,大幅减少IO开销。
支持崩溃恢复:
- 在数据库重启时,Redo Log可重做(Redo)已提交但未刷盘的事务,确保数据一致性。
物理层恢复能力:
Redo Log记录的是数据页的物理变更,可直接定位到磁盘上的具体位置进行修复。例如,若数据页因崩溃未完全写入,Redo Log可重做缺失的修改。
Binlog仅记录逻辑操作(如UPDATE user SET age=25 WHERE id=1),无法直接修复物理损坏的数据页。
事务提交的强依赖:Redo Log是事务提交的必要条件(提交前必须写入),而Binlog是事务提交后的可选操作。若未配置Binlog,不影响事务的持久性保障。
性能与效率:
- Redo Log的顺序写入效率远高于Binlog的随机写入(Binlog需记录完整SQL语句或行数据)。
1.重启时加载数据页到Buffer Pool:
从磁盘读取数据页到内存,但可能包含未提交或未完全刷盘的事务修改。2.Redo Log重做(Redo)已提交事务:
步骤:
- 从Redo Log的检查点(Checkpoint)开始,按顺序重做所有已提交事务的修改。
- 将数据页恢复到崩溃前的最新状态。
原理:Redo Log记录了所有未刷盘的物理修改,确保数据页与Redo Log一致。
3.Undo Log回滚未提交事务:
步骤:
- 扫描所有未提交的事务(通过事务表)。
- 使用Undo Log撤销这些事务的修改(如将数据页恢复到修改前的值)。
原因:未提交的事务可能修改了数据页,但未生效,需通过Undo Log回滚到一致状态。
1.内存缓冲区(Redo Log Buffer):
事务执行时,修改操作首先记录到内存的Redo Log Buffer中(非阻塞,提升性能)。2.刷盘时机:
由参数 innodb_flush_log_at_trx_commit 控制:
- 值为1(默认):事务提交时,Redo Log Buffer立即刷盘。
- 值为0:每秒刷盘一次(性能最高,但可能丢失1秒数据)。
- 值为2:事务提交时刷盘到OS Buffer,每秒由OS刷盘(折中方案)。
3.顺序写入磁盘:
- Redo Log文件是固定大小的循环日志(如ib_logfile0、ib_logfile1),写满后从头开始覆盖。
- LSN(Log Sequence Number):记录日志的写入位置,用于追踪和恢复。
1.事务开始:
- 事务启动,分配Undo Log空间用于回滚。
2.修改数据:
- 读取数据页到Buffer Pool(若未加载)。
- 修改内存中的数据页(形成脏页),同时生成对应的Redo Log记录。
3.Redo Log写入Buffer:
- 将修改的物理信息(页号、偏移量、新值)写入Redo Log Buffer。
4.事务提交:
关键步骤:
- 将Redo Log Buffer刷盘(根据innodb_flush_log_at_trx_commit配置)。
- 更新事务的提交状态(如设置COMMIT标志)。
- 此时事务对数据的修改逻辑上完成,但数据页可能未刷盘。
5.后台刷盘与Checkpoint:
- 主线程(Master Thread):定期将脏页刷盘,并推进Checkpoint,减少Redo Log的覆盖范围。
- 日志组提交(Group Commit):多个事务的Redo Log合并一次刷盘,提升效率。
6.崩溃恢复流程:
步骤:
- 重启时加载数据页到Buffer Pool。
- 从Checkpoint开始,重做(Redo)所有已提交的Redo Log记录。
- 回滚未提交的事务(通过Undo Log)。
结果:数据恢复到崩溃前的最新一致状态。
binlog是MySQL的二进制日志,记录数据库所有逻辑变更(如SQL语句或行数据修改),用于主从复制、数据恢复和操作审计。它不能保证crash-safe,因为崩溃时未提交的事务可能未记录,且物理层恢复需依赖InnoDB的Redo Log。
两阶段提交(2PC)是分布式事务的协调协议,分准备阶段(参与者投票是否提交)和提交阶段(协调者统一通知提交或回滚),确保所有节点达成一致,但可能因超时或网络问题导致阻塞。
MySQL通过检查binlog文件的EOF标记和校验和,确保日志写入完整无截断;同时,事务提交时binlog需先写入磁盘(由sync_binlog参数控制),避免崩溃时日志不完整。
WAL(Write-Ahead Logging,预写日志)是先将数据修改记录到日志再写入磁盘的技术,优点包括:
- 提升性能:通过顺序写日志减少随机IO;
- 保证崩溃恢复:日志可重做未刷盘的修改,确保数据一致性。
- STATEMENT:记录SQL语句(可能因非确定性操作导致复制不一致);
- ROW:记录行级变更(精确复制,但日志体积大);
- MIXED:混合模式,根据语句自动选择格式。
Redo Log记录物理页的修改,包含:
- LSN(日志序列号):日志位置标识;
- 页号:修改的数据页地址;
- 操作类型(如插入、更新)和数据块:记录具体修改内容,用于崩溃后重做数据。
- 全表扫描(缺少索引);
- 锁竞争(高并发导致阻塞);
- 索引失效(如函数操作或范围条件后跟NULL);
- 临时表过大(复杂查询生成大临时表)。
解决方案:添加合理索引、重写查询、优化锁策略或调整配置(如增大tmp_table_size)。
InnoDB数据页大小为16KB,结构包含:
- 页头:元信息(如页号、LSN、checksum);
- 单元数组:存储行数据或索引条目;
- 空闲空间:未使用的区域;
- 页目录:快速定位单元的索引。
通过Redo Log和事务ACID机制:
- WAL技术:事务提交前先写Redo Log,确保崩溃后可重做未刷盘的数据;
- 双1机制:innodb_flush_log_at_trx_commit=1时,事务提交前Redo Log强制刷盘,保证持久性。
- 立即停止写入:避免覆盖数据;
- 使用备份恢复:从最近备份恢复并回放binlog;
- 回放binlog:通过mysqlbinlog定位误删前的语句重放;
- InnoDB的Undo Log:通过 flashback功能(需开启innodb_undo_log_truncate=OFF)或第三方工具回滚。