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 小时前
SSM智慧社区家政服务系统80q7o(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面
数据库·ssm 框架
松涛和鸣3 小时前
72、IMX6ULL驱动实战:设备树(DTS/DTB)+ GPIO子系统+Platform总线
linux·服务器·arm开发·数据库·单片机
likangbinlxa3 小时前
【Oracle11g SQL详解】UPDATE 和 DELETE 操作的正确使用
数据库·sql
r i c k4 小时前
数据库系统学习笔记
数据库·笔记·学习
野犬寒鸦4 小时前
从零起步学习JVM || 第一章:类加载器与双亲委派机制模型详解
java·jvm·数据库·后端·学习
IvorySQL5 小时前
PostgreSQL 分区表的 ALTER TABLE 语句执行机制解析
数据库·postgresql·开源
·云扬·5 小时前
MySQL 8.0 Redo Log 归档与禁用实战指南
android·数据库·mysql
IT邦德5 小时前
Oracle 26ai DataGuard 搭建(RAC到单机)
数据库·oracle
惊讶的猫5 小时前
redis分片集群
数据库·redis·缓存·分片集群·海量数据存储·高并发写
不爱缺氧i5 小时前
完全卸载MariaDB
数据库·mariadb