MySQL 学习心得(一):从表结构到索引

本文记录我对关系型数据库和 MySQL InnoDB 索引的入门理解。数据库不只是“像 Excel 一样的表格”:它还负责定义数据结构、保证约束、处理并发读写,并在需要时通过索引定位数据。

1. 表、行、列与 SQL

关系型数据库用表组织数据。列描述字段及其类型,例如订单编号、用户编号、创建时间;行保存一条记录。NULL 表示缺失或未知值,不等同于数字 0 或空字符串。

SQL 是与数据库交互的语言。常见操作包括查询(SELECT)、插入(INSERT)、更新(UPDATE)和删除(DELETE)。学习底层索引之前,建议先练习基本查询、筛选、排序、分组和连接。

2. 为什么需要索引

没有可用索引时,数据库可能需要逐行检查记录,数据量变大后成本会很高。索引是一种额外的数据结构,帮助数据库缩小查找范围。建立索引会占用存储空间,也会增加插入、更新和删除时维护索引的成本,所以索引不是越多越好。

InnoDB 常用 B+ 树组织索引。树的内部节点保存键和子节点信息,叶子节点保存索引记录;相邻叶子页可按键顺序遍历,因此既能定位范围起点,也能继续读取一段范围。

3. InnoDB 的聚簇索引

InnoDB 表的行数据按一个聚簇索引组织。通常,聚簇索引使用主键;如果没有合适的主键,InnoDB 会选择符合条件的唯一非空索引,仍没有时会创建内部行标识。不同表的具体选择要看表定义。

聚簇索引的叶子页包含行数据,因此按聚簇索引查到叶子记录时,就能取得该行。可以把它理解为“数据按索引键组织”,但不要把整个表简单等同于一个没有其他结构的单独 B+ 树。

4. 二级索引和回表

普通二级索引的叶子记录包含索引列和对应行的主键值。查询通过二级索引找到主键后,如果查询还需要索引中没有的其他列,数据库通常还要再按主键访问聚簇索引,这一步常称为回表。

如果查询所需的列都能从二级索引记录中得到,数据库可能直接使用索引返回结果,这通常称为覆盖索引,此时不需要再读取聚簇索引中的行数据。最终执行方式应以查询计划为准。

5. 页、树高与查询成本

InnoDB 以页作为读写和缓存管理的重要单位。默认页大小通常为 16 KiB,但可以配置,不能把这个数当成所有实例固定不变的事实。B+ 树一个节点通常对应一个索引页,节点能容纳多少键取决于键大小、页大小和记录开销。

树的层数通常较少,但不能据此断言“百万行只要固定三次查询”。实际查询还受树高、缓存命中、数据分布、回表、范围大小和执行计划影响。可以用 EXPLAIN 查看 MySQL 选择的访问方式。

6. 一个简单的索引示例

假设有订单表:

1
2
3
4
5
6
7
CREATE TABLE orders (
id BIGINT PRIMARY KEY,
user_id BIGINT NOT NULL,
created_at DATETIME NOT NULL,
amount DECIMAL(10, 2) NOT NULL,
INDEX idx_user_created (user_id, created_at)
);

下面的查询可以利用以 user_id 开头的联合索引缩小范围:

1
2
3
4
SELECT id, created_at
FROM orders
WHERE user_id = 42
ORDER BY created_at;

id 是主键,InnoDB 的二级索引记录会包含主键值;created_at 是索引列,因此这个查询有机会由索引覆盖。是否实际如此,应通过 EXPLAIN 和实际数据验证。

7. 建议的学习顺序

  1. 熟悉 SQL 基础和表约束。
  2. 学会用 EXPLAIN 观察查询计划。
  3. 学习单列索引、联合索引及最左前缀规则。
  4. 通过小数据集比较有索引和无索引时的执行方式。
  5. 再学习事务、隔离级别、锁和日志等主题。

练习资源:LeetCode 高频 SQL 50 题。本文是入门笔记,索引优化要结合 MySQL 版本、表结构和实际查询验证。