mysql: MySQL索引基础概念

在 MySQL(以 InnoDB 存储引擎 为主流实现)中,索引的核心结构是 B+Tree 。下面我将从整体概念 → 物理结构 → 不同索引类型 → 查询过程 → 设计要点几个层次,系统地讲解 MySQL 的索引结构。


一、为什么 MySQL 使用 B+Tree 作为索引结构

索引的本质是 加速数据定位的数据结构。数据库索引需要同时满足:

  • 磁盘友好(减少 I/O 次数)

  • 支持范围查询(BETWEEN> <ORDER BY

  • 支持高效查找、插入、删除

常见数据结构对比

结构 优点 缺点
数组 查找快(O(1)) 插入、删除代价高
链表 插入快 查找慢
二叉搜索树 有序 容易退化
红黑树 平衡 树高大,磁盘 I/O 多
B+Tree 低树高 + 顺序访问友好 结构稍复杂

结论:B+Tree 是磁盘数据库索引的最优解之一。


二、B+Tree 在 InnoDB 中的物理结构

1. 基本特征

InnoDB 的 B+Tree 具有以下特点:

  1. 非叶子节点只存索引键,不存数据

  2. 所有数据都存放在叶子节点

  3. 叶子节点之间通过双向链表连接

  4. 树是多叉平衡树(不是二叉)

示意结构:

复制代码
          [ 10 | 20 ]
         /     |     \
    [1,5]   [10,15]  [20,30]
      |        |        |
   叶子节点(存数据,且有链表)

2. 页(Page)是最小存储单位

InnoDB 并不是一条一条存数据,而是:

  • 以页(Page)为单位存储

  • 默认页大小:16KB

一个 B+Tree 节点 ≈ 一个 Page

一个 Page 可以存放:

  • 多个索引 key

  • 或多行数据(叶子节点)


三、聚簇索引(Clustered Index)

1. 什么是聚簇索引

InnoDB 中:

表数据本身就是一棵 B+Tree

这棵树的 key 是 主键

这棵树叫做:聚簇索引

2. 聚簇索引的结构

  • 叶子节点:存储完整的一行数据
    (逻辑上存放一行数据,物理上实际存放一页数据,叶子节点就是数据本身)

  • 非叶子节点:存主键值 + 指向子节点的指针

示意:

复制代码
主键B+Tree(聚簇索引)

叶子节点:
[ id=1 | row data ]
[ id=5 | row data ]
[ id=10| row data ]

3. 关键结论

  • 一张 InnoDB 表 有且只有一个聚簇索引

  • 通常是 PRIMARY KEY

  • 如果没有主键:

    1. 选唯一非空索引

    2. 再没有 → 隐式生成 row_id


四、二级索引(Secondary Index / 非聚簇索引)

1. 二级索引的结构

二级索引同样是 B+Tree,但叶子节点存的不是整行数据,而是:

索引列值 + 主键值

示意:

复制代码
name 索引 B+Tree(二级索引)

叶子节点:
[ "Alice" | id=5 ]
[ "Bob"   | id=10 ]

2. 回表

当使用二级索引查询时:

  1. 在二级索引中查到 主键 id

  2. 再回到 聚簇索引 中查整行数据

这一步叫:回表


五、一次查询的索引查找过程示例

假设有表:

复制代码
CREATE TABLE user (
  id INT PRIMARY KEY,
  name VARCHAR(50),
  age INT,
  INDEX idx_name(name)
);

表中的字段为(id , name ,age),其中id为主键值,此外还有一个二级索引,存储了(主键列值name, 主键值id)

查询 1:主键查询

指在 SQL 中通过表的主键(PRIMARY KEY)作为查询条件,直接在聚簇索引上定位并读取目标行数据的查询方式

复制代码
SELECT * FROM user WHERE id = 10;

过程:

  • 直接在 聚簇索引 上查

  • 一次 B+Tree 查找

  • 不回表


查询 2:二级索引查询

指 SQL 查询通过非主键索引(Secondary Index)作为访问路径,先在二级索引 B+Tree 中定位记录,再(通常)通过主键回到聚簇索引获取完整行数据的查询方式

复制代码
SELECT * FROM user WHERE name = 'Bob';

过程:

  1. idx_name 中查到 id = 10

  2. 回到主键 B+Tree 查询整行数据

2 次索引查找


查询 3:覆盖索引

是指一次查询中,所需的所有列都能直接从某个索引中获得不需要回到聚簇索引读取整行数据的查询方式

复制代码
SELECT id FROM user WHERE name = 'Bob';
  • idx_name 叶子节点已经包含 id

  • 不需要回表

  • 这叫 覆盖索引,


六、B+Tree 对范围查询的支持

由于叶子节点是 有序链表

复制代码
SELECT * FROM user WHERE id BETWEEN 10 AND 100;

流程:

  1. 找到 id=10

  2. 顺着叶子节点链表顺序扫描

  3. 非常高效(顺序 I/O)

这也是 B+Tree 相比 Hash 索引的重要优势。


七、其他索引结构(简要)

1. Hash 索引(Memory 引擎)

  • 基于哈希表

  • 只能等值查询

  • 不支持范围 / 排序

  • InnoDB 不直接支持(自适应 Hash 除外)


2. 全文索引(FULLTEXT)

  • 使用倒排索引

  • 适用于文本搜索

  • 与 B+Tree 索引完全不同


八、索引设计中的几个关键结论

1. 主键设计

  • 主键 越短越好

  • 尽量使用 自增整数

  • 避免 UUID(会导致页分裂)


2. 联合索引与最左前缀

复制代码
INDEX idx_a_b_c (a, b, c)
  • 可用:

    • a

    • a, b

    • a, b, c

  • 不可用:

    • b

    • c

最左前缀

当使用联合索引(Composite Index)时,MySQL 只能从索引的最左列开始,连续地使用索引列 来进行查找;
一旦中间断开或跳过某一列,该列及其右侧列将无法再用于索引定位。


3. 索引不是越多越好

  • 占用磁盘空间

  • 写操作成本增加

  • 优化器选择成本上升


九、一句话总结

MySQL(InnoDB)的索引本质是 B+Tree:
主键索引是聚簇索引,数据存于叶子节点;
二级索引的叶子节点存主键,需要回表;
叶子节点链表结构使范围查询极其高效。

相关推荐
蜂蜜黄油呀土豆2 小时前
MySQL 事务原理深度解析:从 ACID 到并发控制机制
mysql·mvcc·并发控制·数据库事务·acid
king_harry2 小时前
PostgreSQL WAL 原理剖析、日志堆积治理与流复制监控
数据库·postgresql·wal·流复制
默默前行的虫虫2 小时前
nicegui网页多用户数据隔离总结
数据库·sql
特立独行的猫a2 小时前
PostgreSQL客户端工具介绍:从性能测试到跨平台管理
数据库·docker·postgresql·客户端·pgadmin4
微爱帮监所写信寄信2 小时前
微爱帮监狱写信寄信小程序:MySQL核心日志与备份恢复安全架构
数据库·mysql·小程序·邮局·监狱寄信·挂号信·邮政
isNotNullX3 小时前
数据迁移怎么做?有什么好用的数据库迁移工具推荐吗?
数据库·数字化·数据迁移·企业管理
云老大TG:@yunlaoda3603 小时前
华为云国际站代理商DAS的跨境合规适配的应用场景有哪些?
网络·数据库·华为云
3824278273 小时前
python3网络爬虫开发实战 第二版:绑定回调
开发语言·数据库·python
BIBI20493 小时前
Windows 上配置 Nacos Server 3.x.x 使用 MySQL 5.7
java·windows·spring boot·后端·mysql·nacos·配置