MySQL 核心知识梳理:从底层原理到实战优化

MySQL 核心知识梳理:从底层原理到实战优化

  • [MySQL 核心知识梳理:从底层原理到实战优化](#MySQL 核心知识梳理:从底层原理到实战优化)
    • [1. MySQL 整体架构](#1. MySQL 整体架构)
    • [2. InnoDB 存储引擎(目前默认,也是重点)](#2. InnoDB 存储引擎(目前默认,也是重点))
    • [3. Buffer Pool ------ InnoDB 的内存加速器](#3. Buffer Pool —— InnoDB 的内存加速器)
    • [4. 日志系统:Redo Log vs Binlog](#4. 日志系统:Redo Log vs Binlog)
      • [4.1 Redo Log(重做日志,引擎层)](#4.1 Redo Log(重做日志,引擎层))
      • [4.2 Binlog(归档日志,Server 层)](#4.2 Binlog(归档日志,Server 层))
      • [4.3 为什么要两个日志?](#4.3 为什么要两个日志?)
    • [5. 索引](#5. 索引)
      • [5.1 B+ 树索引(InnoDB 默认)](#5.1 B+ 树索引(InnoDB 默认))
      • [5.2 自适应哈希索引(AHI)](#5.2 自适应哈希索引(AHI))
      • [5.3 其他索引](#5.3 其他索引)
      • 索引使用原则(面试高频)
    • [6. 事务与隔离级别](#6. 事务与隔离级别)
    • [7. MVCC(多版本并发控制)](#7. MVCC(多版本并发控制))
    • [8. 锁机制](#8. 锁机制)
      • [8.1 锁粒度](#8.1 锁粒度)
      • [8.2 锁类型](#8.2 锁类型)
      • [8.3 死锁](#8.3 死锁)
    • [9. SQL 优化实战(常见思路)](#9. SQL 优化实战(常见思路))
      • [9.1 慢查询定位](#9.1 慢查询定位)
      • [9.2 索引失效场景](#9.2 索引失效场景)
      • [9.3 分页优化](#9.3 分页优化)
      • [9.4 写优化](#9.4 写优化)
    • [10. 常用运维与监控](#10. 常用运维与监控)
    • 写在最后

MySQL 核心知识梳理:从底层原理到实战优化

一篇尽量系统但不说废话的 MySQL 知识地图,帮助你理解它为什么快、怎么保证不丢数据、以及如何写出高效的 SQL。


1. MySQL 整体架构

MySQL 分为 Server 层存储引擎层,这种分层设计让它支持多种存储引擎(InnoDB、MyISAM、Memory 等)。

复制代码
客户端连接
    ↓
连接器(管理连接、权限验证)
    ↓
查询缓存(8.0 已移除)→ 解析器(词法/语法分析)→ 优化器(选择索引、决定 join 顺序)→ 执行器(调用存储引擎接口)
    ↓
存储引擎(默认 InnoDB)
    ↓
磁盘文件(.ibd、.frm、binlog、redo log 等)
  • Server 层:负责连接管理、查询解析、优化、执行,以及 binlog、慢查询日志等。
  • 引擎层:负责数据的实际存储与读取,提供 ACID 事务、行锁、MVCC 等特性。

2. InnoDB 存储引擎(目前默认,也是重点)

InnoDB 是一个兼顾高可靠和高性能的通用存储引擎,适用于绝大多数 OLTP 场景。

核心特性

  • ACID 事务:支持原子性、一致性、隔离性、持久性。
  • 行级锁:默认使用行锁,并发性能远高于表锁。
  • 多版本并发控制(MVCC):实现非阻塞读,读写不冲突。
  • 外键约束:保证数据完整性。
  • Crash Safe:崩溃自动恢复(通过 Redo Log 和 Undo Log)。
  • 聚簇索引:数据和主键索引存储在一起,二级索引回表。

物理存储结构(了解即可)

  • 表空间(Tablespace) :逻辑存储单元,包括系统表空间、独立表空间(.ibd)、通用表空间等。
  • 段(Segment):数据段、索引段、回滚段。
  • 区(Extent):1 区 = 64 个连续页(默认 1MB)。
  • 页(Page):默认 16KB,是 InnoDB 读写的最小单位。

3. Buffer Pool ------ InnoDB 的内存加速器

Buffer Pool 是 InnoDB 的 内存核心,所有的数据读写优先经过它。

  • 作用:缓存磁盘上的数据页(包含表数据、索引、插入缓冲、自适应哈希索引等)。
  • 加速原理:读 -- 先从 Buffer Pool 命中,否则从磁盘读取并缓存;写 -- 先修改 Buffer Pool 中的页,标记为"脏页",后台线程择机刷盘。
  • 数据结构
    • free list:空闲页
    • LRU list:已被使用的页,采用 改进 LRU(分成 young 区和 old 区,防止全表扫描污染缓存)
    • flush list:脏页列表,按修改时间排序
  • 配置建议innodb_buffer_pool_size 设为服务器物理内存的 50%~75%;高并发下可设置 innodb_buffer_pool_instances 拆分成多个实例以降低争用。

4. 日志系统:Redo Log vs Binlog

4.1 Redo Log(重做日志,引擎层)

  • 记录内容:物理日志,例如 "在表空间 X、页号 Y、偏移量 Z 处将值 A 改成 B"。
  • 写入方式:固定大小、循环写入(写满后会覆盖旧的日志)。
  • 作用 :保证事务的持久性,即 Crash-Safe 能力。事务提交时,Redo Log 先行落盘,即使宕机,重启后也能根据 Redo Log 重放未完成的页修改。
  • 相关参数innodb_log_file_sizeinnodb_log_files_in_group

4.2 Binlog(归档日志,Server 层)

  • 记录内容 :逻辑日志,例如 UPDATE t SET c = c+1 WHERE id = 1
  • 写入方式:追加写,文件写满后切换下一个文件,不会覆盖。
  • 作用
    • Point-in-Time 恢复:利用 binlog 回放恢复到任意时刻。
    • 主从复制:从库订阅主库的 binlog 实现数据同步。
  • 格式:STATEMENT(记录 SQL)、ROW(记录行变更,推荐)、MIXED。

4.3 为什么要两个日志?

  • 早期 MySQL 默认引擎 MyISAM 没有 Crash-Safe 能力,靠 binlog 无法恢复。
  • InnoDB 加入后,为了实现自己的崩溃恢复,引入了 Redo Log;同时为了兼容 binlog 的复制/恢复机制,保留两者。
  • 两阶段提交 :保证 Redo Log 和 Binlog 逻辑一致,避免主从数据不一致。过程:
    1. Prepare:Redo Log 写入并标记为 prepare 状态。
    2. Commit:Binlog 写入成功 → 将 prepare 的 Redo Log 改为 commit 状态。

5. 索引

5.1 B+ 树索引(InnoDB 默认)

  • 聚簇索引(主键索引):叶子节点存储完整行数据
  • 二级索引(辅助索引):叶子节点存储主键值,查询数据需要"回表"。
  • 为什么用 B+ 树?
    • 矮胖:树高通常 3~4 层,适合磁盘 IO。
    • 叶子节点双向链表,支持范围扫描。
    • 非叶子节点只存索引,一个页可放更多键。

5.2 自适应哈希索引(AHI)

  • InnoDB 自动为热点索引页在内存中构建哈希索引,只针对等值查询
  • 优点:O(1) 定位,比 B+ 树更快。
  • 缺点:消耗内存、高并发下可能有争用。
  • 参数:innodb_adaptive_hash_index(默认 ON)。

5.3 其他索引

  • 全文索引:MATCH AGAINST 支持,适用于文本搜索。
  • 空间索引:用于地理数据(GIS)。

索引使用原则(面试高频)

  • 最左前缀原则 :联合索引 (a,b,c),查询条件必须从 a 开始,才能用到该索引。
  • 覆盖索引:select 的字段都在索引中,可避免回表。
  • 索引下推(ICP):在索引遍历过程中,提前过滤掉不符合条件的记录,减少回表次数。
  • 不要建冗余/重复索引

6. 事务与隔离级别

ACID 回顾

  • Atomicity(原子性):通过 Undo Log 实现。
  • Consistency(一致性):由数据库约束 + 业务逻辑保证。
  • Isolation(隔离性):由锁 + MVCC 实现。
  • Durability(持久性):通过 Redo Log 实现。

四种隔离级别

隔离级别 脏读 不可重复读 幻读
READ UNCOMMITTED ✅ 可能 ✅ 可能 ✅ 可能
READ COMMITTED ✅ 可能 ✅ 可能
REPEATABLE READ(MySQL 默认) ❌(InnoDB 用间隙锁解决了)
SERIALIZABLE
  • READ COMMITTEDREPEATABLE READ 都是通过 MVCC 实现的快照读。
  • REPEATABLE READ 下,普通的 SELECT 不会加锁,而是读取快照版本;加锁读(SELECT ... FOR UPDATE)会使用间隙锁防止幻读。

7. MVCC(多版本并发控制)

MVCC 使 InnoDB 在加锁的情况下实现 非阻塞读

  • 核心思想:每行数据可能有多个版本(通过 Undo Log 串联)。
  • 每个事务启动时,会生成一个 Read View,包含当前活跃事务 ID 列表。
  • 可见性判断:根据版本的事务 ID 与 Read View 比较,决定该行是否对当前事务可见。
  • 不同隔离级别的 Read View 生成时机不同:
    • RC:每次查询都生成新的 Read View → 会出现不可重复读。
    • RR:只在事务第一次查询时生成 Read View → 保证重复读一致。

8. 锁机制

8.1 锁粒度

  • 表锁LOCK TABLES ... 或 MyISAM 默认锁。
  • 行锁:InnoDB 默认,通过索引实现,不是直接锁行,而是锁索引记录。
  • 间隙锁(Gap Lock):锁定一个范围(不包含记录本身),防止幻读。
  • 临键锁(Next-Key Lock):行锁 + 间隙锁,是 RR 级别下默认的锁。

8.2 锁类型

  • 共享锁(S)SELECT ... LOCK IN SHARE MODE
  • 排他锁(X)SELECT ... FOR UPDATEUPDATEDELETE
  • 意向锁:表级锁,表示事务想要在表中某行加 S 或 X 锁,用于快速判断表锁是否可行。

8.3 死锁

  • 两个或多个事务相互持有对方需要的锁。
  • InnoDB 会自动检测死锁,回滚代价较小的事务(可通过 innodb_deadlock_detect 控制)。

9. SQL 优化实战(常见思路)

9.1 慢查询定位

  • 开启慢查询日志:slow_query_log=1,设置 long_query_time
  • 使用 EXPLAIN 分析执行计划,关注:
    • type:从好到差依次是 system > const > eq_ref > ref > range > index > ALL
    • possible_keys / key:实际使用的索引。
    • rows:预估扫描行数。
    • ExtraUsing filesortUsing temporary 是优化重点。

9.2 索引失效场景

  • 对索引列使用函数、表达式(如 WHERE DATE(create_time) = '2025-01-01')。
  • 隐式类型转换(如 varchar 字段与 int 比较)。
  • LIKE 以 % 开头('%abc')。
  • OR 条件中,部分字段没有索引(除非覆盖所有 OR 字段)。

9.3 分页优化

  • 避免 LIMIT 1000000,10 → 会扫描前 100 万行再丢掉。
  • 改进方法:
    • 延迟关联:SELECT * FROM t JOIN (SELECT id FROM t ORDER BY id LIMIT 1000000,10) tmp ON t.id = tmp.id
    • 记住上一页最大 ID:WHERE id > last_id ORDER BY id LIMIT 10(适用于主键自增且无删除)。

9.4 写优化

  • 批量插入:INSERT INTO ... VALUES (1,2),(3,4)... 比单条快很多。
  • 适当调整 innodb_flush_log_at_trx_commit
    • 1(默认)------ 每次提交都刷盘,最安全。
    • 0 / 2 ------ 牺牲一点持久性,提升写入性能。

10. 常用运维与监控

  • SHOW ENGINE INNODB STATUS:查看 InnoDB 内部状态(锁、事务、缓冲池等)。
  • SHOW PROCESSLIST:查看当前连接与执行语句。
  • performance_schemasys 库:用于诊断锁等待、查询性能。
  • pt-query-digest:分析慢查询日志的工具。

写在最后

MySQL 的知识体系非常庞杂,但只要你理清 架构分层InnoDB 存储引擎索引日志事务与锁 这几条主线,剩下的细节都可以按图索骥。

如果能亲手在本地搭建一个 MySQL,结合 EXPLAINSHOW ENGINE 去观察 SQL 的行为,会比只看文章深刻得多。

如果你对某个点(比如 MVCC 底层、Redo Log 的组提交、Online DDL 原理等)想深入细节,也可以告诉我,我再单独展开。

希望这篇梳理对你有帮助。

相关推荐
Rain的Java大神之路2 小时前
如何快速上传10G文件
java·spring boot·redis·后端·mysql·spring cloud·面试
大海星辰7984 小时前
一次对账SQL“灵异事件”排查:NOT IN返回空集的坑
mysql
Linux-lucky4 小时前
32-38-Linux学习之旅之MySQL综合
linux·运维·学习·mysql·ubuntu
&不羁之风&7 小时前
从 MySQL 到 MongoDB:80 万系统日志(sys_log)平滑迁移完整实战(含 Windows 环境 mongoimport 安装与避坑)
mysql·mongodb
这个DBA有点耶8 小时前
InnoDB页结构深入:页分裂、页合并、填充因子——B+树底层机制全解析
数据库·mysql·架构
山岚的运维笔记8 小时前
mysql 专业笔记 -- 第 36 章:MySQL 管理
运维·数据库·笔记·后端·mysql·oracle·dba
霸道流氓气质10 小时前
SQL 里的 AND / OR 优先级陷阱:一个括号引发的“数据越界“
mysql
爱奥尼欧13 小时前
【MySQL】建库就是建目录?字符集校验规则、备份恢复与alter改表实操
mysql
大虾别跑13 小时前
mysql5.7升级
mysql
geovindu13 小时前
sql: Transaction & Concurrency Patterns using mysql 9.0
mysql·数据库开发·数据库架构