📚 目录

  1. 什么是索引?
  2. 索引的分类
  3. B+树结构详解
  4. MySQL 为什么使用 B+树而不是 B 树?
  5. 聚簇索引 vs 非聚簇索引
  6. 覆盖索引、最左前缀原则
  7. 索引失效的常见原因
  8. 索引优化建议
  9. 图解演示 B+树查找过程

1. ✅ 什么是索引?

索引是用于加速数据查询的数据结构,类似于书籍的目录。它能在大量数据中快速定位所需的记录,显著提高 SELECT 查询效率。

通俗比喻:

  • 没有索引:全表扫描,就像翻书每一页找人名;
  • 有索引:看目录直接跳页,定位迅速。

2. 📂 索引的分类(MySQL InnoDB)

索引类型说明
主键索引聚簇索引,按主键排序存储数据
普通索引非唯一索引,可以有重复值
唯一索引索引列必须唯一,允许 NULL
组合索引多列联合创建的索引,遵循最左前缀原则
覆盖索引查询字段只在索引中即可完成,无需回表
全文索引对文本字段进行全文匹配搜索(MyISAM 支持)

3. 🌳 B+树结构详解

MySQL(InnoDB)使用 B+树(BPlus Tree) 作为默认索引结构。

🧱 结构特性

  • 所有数据都存储在叶子节点
  • 叶子节点之间通过双向链表连接,便于范围查找;
  • 非叶子节点仅存储键值指向子节点的指针
  • 每个节点可以存储多个键,减少树的高度;

🧠 时间复杂度

查找效率为 O(logm N),其中 m 为节点的分支因子(高扇出性带来低高度)。


🖼️ B+树结构图(示意)

        [10 | 20 | 30]
       /     |     \
    ...     ...    ...
   [5,7,9] [12,18] [21,27,29]  <- 叶子节点存储数据
  • 所有的 key 都出现在叶子节点;
  • 中间节点只用于索引定位;
  • 叶子节点顺序排列,便于区间扫描。

4. ❓ 为什么使用 B+树而不是 B 树?

特性B 树B+ 树(MySQL 使用)
数据存储位置所有节点都存储数据只在叶子节点存储数据
查找效率所有节点都有数据,路径不统一路径统一,便于磁盘页缓存命中
范围查询不方便叶子节点链表连接,范围查询优秀
I/O 访问次数少,适合磁盘块预读
实际使用情况较少MySQL InnoDB、Oracle 使用

5. 🧩 聚簇索引 vs 非聚簇索引

✅ 聚簇索引(Clustered Index)

  • 主键索引,叶子节点存储整行数据
  • 表数据与索引结构合并在一起
  • 一个表只能有一个聚簇索引(主键或唯一非空索引);

🔁 非聚簇索引(Secondary Index)

  • 叶子节点存储主键值而非完整行;
  • 查询时需通过回表操作找到真正数据行;
  • 可有多个非聚簇索引。

6. 📌 覆盖索引、最左前缀原则

覆盖索引(Covering Index)

如果一个查询中所需的字段都能从索引中获取,就不会回表,大大提高查询效率。

-- 假设已建立索引 idx_name_age(name, age)
SELECT name FROM user WHERE name = 'Tom'; -- 覆盖索引

最左前缀原则(重要)

组合索引只能命中最左连续字段:

INDEX(name, age, gender)

WHERE name = ?                -- 命中 ✅  
WHERE name = ? AND age = ?    -- 命中 ✅  
WHERE age = ?                 -- 不命中 ❌  
WHERE name LIKE 'T%'          -- 命中 ✅  
WHERE name LIKE '%T'          -- 不命中 ❌

7. ⚠️ 索引失效的常见原因

情况是否索引生效
OR 查询中部分列无索引
索引列参与函数/表达式
% 通配符在前的模糊匹配
隐式类型转换(int = ‘123abc’)
使用 != 或 <>
使用 IS NULL / IS NOT NULL✅/❌ 视情况

8. 📈 索引优化建议

  • 优先使用 高区分度列建索引(选择性高);
  • 使用覆盖索引避免回表;
  • 多条件查询时遵循最左前缀原则
  • 避免对索引列使用函数、表达式、类型不一致等;
  • 控制组合索引的列数,避免冗余;
  • 利用 EXPLAIN 分析 SQL 是否使用索引。

9. 🔍 图解查找过程(以 name 索引查找为例)

查询 name = 'Tom'
↓
B+树根节点
  ↓二分查找找到区间
    ↓顺着指针进入下一层子节点
      ↓直到叶子节点
        → 精确匹配 name = 'Tom'
          → 读取整行(聚簇)或回表读取(非聚簇)

📘 推荐阅读与工具


如你需要我继续写一篇关于:

  • 🔁 Hash索引 VS B+树索引性能比较;
  • ✅ 多字段联合索引的设计实践;
  • 📊 EXPLAIN 分析 SQL 查询优化;

欢迎继续告诉我,我可以继续生成详细内容。