MySQL
MySQL 是常用的关系型数据库。学习 MySQL 不能只停留在“会写 select、insert”,还要理解数据是怎么存的、索引为什么能加速、事务为什么能保证一致性、锁为什么会阻塞、慢 SQL 为什么会慢。
零基础可以先抓住一句话:
MySQL 的本质是:把结构化数据按表保存起来,并在并发访问时尽量做到“查得快、写得对、坏了能恢复”。
学 MySQL 要解决什么问题
| 问题 | MySQL 对应能力 | 如果不会会怎样 |
|---|---|---|
| 数据怎么长期保存 | 表、字段、数据类型、约束 | 数据格式混乱,后期无法维护 |
| 查询为什么有快有慢 | 索引、执行计划、优化器 | 慢 SQL 只能靠猜,容易乱加索引 |
| 多人同时改数据怎么办 | 事务、锁、MVCC | 出现超卖、丢失更新、脏数据 |
| 数据库异常后怎么恢复 | redo log、undo log、binlog | 无法解释提交、回滚和主从同步 |
| 数据量大了怎么办 | 分页、归档、索引治理、架构治理 | 表越来越慢,系统容量不可控 |
学习路线
mermaid
flowchart TD
A["SQL 基础"] --> B["表设计"]
B --> C["查询与 Join"]
C --> D["架构分层"]
D --> E["存储结构和 Buffer Pool"]
E --> F["索引和 B+Tree"]
F --> G["EXPLAIN 和优化器"]
G --> H["事务 / 锁 / MVCC"]
H --> I["日志 / 主从 / 备份"]
I --> J["大表治理 / 分库分表 / 面试"]推荐阅读顺序:
- 知识地图与 7 天速学路线:先建立全局坐标,按面试时间选择学习路径。
- SQL 基础:先学会增删改查、分页、条件、逻辑执行顺序。
- SQL 进阶:掌握聚合、窗口函数、CTE、子查询、NULL 和稳定分页。
- MySQL 函数大全与性能边界:系统学习字符串、日期、数值、聚合、窗口、JSON、函数索引和存储函数。
- 安装、连接与核心配置:理解版本、参数作用域、连接和内存预算。
- MySQL 8 新特性与 5.7 升级指南:系统理解 CTE、窗口函数、新索引、数据字典、原子 DDL、安全变化和升级风险。
- 字符集、排序规则与时区:解决乱码、比较规则和跨时区问题。
- JSON、生成列与数据库对象:补齐 JSON 索引、全文检索、视图、触发器等能力边界。
- 从零到生产级掌握:把表设计、索引、执行计划、事务、日志、主从和排查连成课程线。
- 从零到精通验收清单:用可验证任务判断自己是不是真的会了,而不是只看过概念。
- 商业场景训练营:用订单支付、库存、大表、锁、死锁、主从延迟把理论跑起来。
- 表设计:理解字段类型、主键、唯一约束、宽表窄表和反范式。
- 查询与 Join:理解 Join、子查询、N+1、连接字段索引。
- 复杂关联查询实战:掌握一对多放大、预聚合、半/反连接、时态 Join、父子分页和财务核对。
- MySQL 架构分层:理解连接层、Server 层、存储引擎层分别负责什么。
- MySQL 架构分层与请求全过程:把三层、五层、select、update、日志边界和排查分层讲透。
- SQL 执行全过程原理:把连接、解析、优化器、执行器、InnoDB 读页、回表、排序完整串起来。
- 存储引擎与 Buffer Pool:理解 InnoDB、缓存页、脏页、刷盘。
- 存储结构:理解 InnoDB 为什么用页、B+Tree、聚簇索引。
- B+Tree、B-Tree 与数据库索引家族:讲清 MySQL 为什么用 B+Tree,以及 Oracle、PostgreSQL、SQL Server 为什么常说 B-Tree。
- 索引知识点:学习最左前缀、覆盖索引、回表、索引失效。
- EXPLAIN:学会看执行计划,并理解
type、key、key_len、rows、filtered、Extra这些字段从哪里来。 - 优化器原理:理解为什么有索引不一定用、统计信息怎么影响执行计划。
- 事务:理解 ACID、隔离级别、提交和回滚。
- 锁:理解行锁、间隙锁、临键锁、死锁。
- MVCC:理解快照读为什么能做到读写不互相阻塞,以及 undo log 如何提供旧版本。
- redo log 与 binlog:理解崩溃恢复、主从复制、两阶段提交。
- InnoDB 更新事务全过程原理:把行锁、undo、Buffer Pool、redo、binlog、两阶段提交、MVCC 完整串起来。
- 主从复制:理解 binlog 复制、读写分离、主从延迟。
- 备份恢复:理解全量备份、binlog 时间点恢复、误删恢复流程。
- 大表覆盖索引仍然慢:理解覆盖索引无法解决扫描大、深分页、冷热数据等问题。
- 分库分表:理解容量治理、分片键、跨分片问题。
- Apache ShardingSphere:掌握 JDBC/Proxy、路由内核、分片配置、事务、迁移和排障。
- MySQL 高级:把执行计划、锁、事务、慢 SQL 排查串起来。
- 分区、归档与在线 DDL:理解分区裁剪、MDL 和大表结构变更。
- 安全与权限:掌握最小权限、SQL 注入、TLS、备份与敏感数据治理。
- 监控与故障排查:建立慢 SQL、连接、锁、IO 和磁盘故障的证据链。
- 高可用与容灾:理解 RPO/RTO、故障切换、脑裂和演练。
- MySQL 面试:学习重点题的标准回答与追问路径。
- 100 道高频面试题库:分层口述、自测,再训练 10 道生产场景题。
- SQL 查询面试题与答案:用统一表结构完成 30 道参考题和 10 道加试题。
一条 SQL 的执行流程
mermaid
flowchart TD
A["客户端发送 SQL"] --> B["连接器<br/>认证 / 权限 / 连接管理"]
B --> C["解析器<br/>词法分析 / 语法分析"]
C --> D["预处理<br/>检查表和字段是否存在"]
D --> E["优化器<br/>选择索引 / 选择连接顺序"]
E --> F["执行器<br/>调用存储引擎接口"]
F --> G["InnoDB<br/>读页 / 查索引 / 加锁"]
G --> H["返回结果给客户端"]这条链路里最容易出问题的是优化器和存储引擎:
| 环节 | 初学者常见误解 | 正确理解 |
|---|---|---|
| 解析器 | SQL 能写出来就一定高效 | 语法正确只代表能执行,不代表执行代价低 |
| 优化器 | 有索引就一定用索引 | 优化器会估算成本,认为全表扫描便宜时可能不用索引 |
| 执行器 | 查询就是从表里取几行 | 实际可能要扫描大量索引页、回表、排序、临时表 |
| InnoDB | 数据是一行一行读 | 磁盘和 Buffer Pool 通常以页为单位读写 |
InnoDB 要同时解决三件事
mermaid
flowchart TD
A["InnoDB"] --> B["性能<br/>B+Tree / Buffer Pool / 索引"]
A --> C["并发<br/>事务 / 锁 / MVCC"]
A --> D["可靠<br/>redo log / undo log / 崩溃恢复"]如果只学 SQL,不学 InnoDB,很容易出现这些问题:
- 看到慢 SQL 只会加单列索引,不知道联合索引顺序怎么设计。
- 遇到死锁只会重启服务,不知道锁加在索引上。
- 不理解为什么普通
select不阻塞update,但select ... for update会阻塞。 - 不知道长事务为什么会导致 undo log 堆积。
- 不知道为什么自增主键比随机 UUID 更适合 InnoDB 聚簇索引。
SQL Demo:从建表到看执行计划
准备一张用户表:
sql
create table users (
id bigint primary key auto_increment,
username varchar(50) not null,
status tinyint not null default 1,
created_at datetime not null,
updated_at datetime not null,
unique key uk_username (username),
key idx_status_created_at (status, created_at)
) engine = InnoDB default charset = utf8mb4;插入数据:
sql
insert into users(username, status, created_at, updated_at)
values
('tom', 1, now(), now()),
('jerry', 1, now(), now()),
('bob', 0, now(), now());查询启用用户:
sql
select id, username
from users
where status = 1
order by created_at desc
limit 20;查看执行计划:
sql
explain
select id, username
from users
where status = 1
order by created_at desc
limit 20;观察重点:
| 字段 | 应该怎么看 |
|---|---|
key | 是否使用 idx_status_created_at |
type | 是否避免了大表 ALL 全表扫描 |
rows | 预估扫描行数是否明显小于总行数 |
Extra | 是否出现 Using filesort、Using temporary |
学习 MySQL 时要养成一个习惯:写完高频 SQL 后,必须用 EXPLAIN 验证执行计划。如果只看 SQL 语法,不看执行计划,很难发现线上慢 SQL。
高频知识点速查
| 知识点 | 你要能讲清楚什么 |
|---|---|
| B+Tree | 为什么适合范围查询,为什么树高低能减少 IO |
| 聚簇索引 | 为什么主键叶子节点就是整行数据 |
| 二级索引 | 为什么查询非索引列可能回表 |
| 联合索引 | 为什么要遵守最左前缀 |
| 覆盖索引 | 为什么只查索引字段可以减少回表 |
| 事务隔离 | 为什么不同隔离级别看到的数据不同 |
| MVCC | 为什么普通查询可以读历史版本 |
| 行锁 | 为什么 InnoDB 行锁加在索引记录上 |
| 间隙锁 | 为什么 RR 下范围查询可能锁住不存在的数据 |
| redo log | 为什么提交后宕机还能恢复 |
| undo log | 为什么事务能回滚,快照读能看旧版本 |
| binlog | 为什么主从同步和数据恢复依赖它 |
常见学习误区
| 误区 | 问题 | 正确做法 |
|---|---|---|
| SQL 能查出来就行 | 数据量小看不出性能问题 | 建表阶段就考虑高频查询和索引 |
| 每个字段都建索引 | 写入变慢,空间变大,优化器选择变复杂 | 根据真实 SQL 设计联合索引 |
| 慢 SQL 一定是没索引 | 也可能是返回太多、排序、锁等待、网络慢 | 结合 EXPLAIN、慢日志和监控定位 |
| 事务越大越安全 | 长事务持锁久,undo 堆积,阻塞清理 | 事务只包住必须原子的一小段逻辑 |
| 只背隔离级别定义 | 遇到 RC、RR 行为差异仍然不会分析 | 结合 Read View 和当前读理解 |
最小练习路线
- 建一张表,包含主键、唯一索引、普通联合索引。
- 写 5 条查询 SQL,用
EXPLAIN看是否使用索引。 - 故意写一个索引失效 SQL,例如
where date(created_at) = ?,观察执行计划变化。 - 开两个 MySQL 会话,模拟事务 A 更新不提交,事务 B 更新同一行等待。
- 在 RR 隔离级别下模拟 MVCC,观察普通
select和select ... for update的差异。
这些练习做完后,再去看锁、MVCC、redo/undo/binlog,会更容易把概念和现象对应起来。
