从零起步学习MySQL || 第八章:索引深入理解及高级运用(结合常见优化问题讲解)

一、为什么要创建索引(Index)?

索引的作用:

索引就像一本书的"目录",让数据库在查询数据时可以"快速定位"记录,而不是全表扫描。

优点:

  • 大大提高数据检索速度

  • 加快表之间的连接(join)

  • 在分组(GROUP BY)、排序(ORDER BY)时也能提高效率

缺点:

  • 索引需要占用额外的磁盘空间

  • 插入、删除、更新数据时,索引也要维护,可能会变慢


二、什么时候需要创建索引

可以简单理解为一句话:

"凡是经常出现在 WHEREJOINORDER BYGROUP BY 的列,都值得考虑建立索引。"

具体场景:

  1. 主键和唯一键

    • 主键会自动创建唯一索引。

    • 唯一键(UNIQUE)可以保证数据唯一性。

  2. 经常用作查询条件的字段

    复制代码
    SELECT * FROM user WHERE email = 'test@xupt.edu.cn';

    应给 email 创建索引。

  3. 用于排序的字段

    复制代码
    SELECT * FROM article ORDER BY create_time DESC;

    create_time 建索引可避免文件排序。

  4. 用于分组统计的字段

    复制代码
    SELECT department, COUNT(*) FROM employee GROUP BY department;

    department 列可建索引。

  5. 多表连接时用作连接条件的字段

    复制代码
    SELECT * FROM student s JOIN score c ON s.id = c.student_id;

    student.idscore.student_id 都应建索引。


三、什么时候不需要创建索引

索引不是越多越好,错误的索引会拖慢性能。

不建议建索引的情况:

  1. 数据量很小的表

    • 比如只有几百行,MySQL 直接全表扫描更快。
  2. 频繁更新的字段

    • 每次更新都要维护索引,会拖慢性能。
  3. 高重复度的字段

    • 如"性别"、"是否删除(0/1)",区分度太低。

    • 索引选择性低,优化效果几乎没有。

  4. 查询中很少用到的字段

    • 从不出现在 WHEREORDER BYGROUP BY 中的列没必要建索引。

四、索引优化方法

接下来讲几个常见的索引优化技巧,在面试中也经常被问到


1️⃣ 前缀索引优化(Prefix Index)

当字符串字段太长(如邮箱、URL、UUID)时,索引整个字段会浪费空间。

可以只取前几个字符建立索引。

复制代码
ALTER TABLE user ADD INDEX idx_email (email(10));

优点:

  • 占用空间小,比较速度快。

缺点:

  • 可能降低"区分度",MySQL 仍可能要回表验证。

实战建议:

SELECT COUNT(DISTINCT LEFT(email, N)) / COUNT(*) 来测试前缀长度的区分度。


2️⃣ 覆盖索引优化(Covering Index)

"覆盖索引"指的是查询的字段都在索引中,不用回表读取数据。

复制代码
-- 索引包含 (id, name)
SELECT id, name FROM student WHERE id = 1;

优点:

  • 避免回表(减少IO),查询更快。

优化手段:

只查需要的字段;用 EXPLAIN 查看 Extra 字段中是否有 Using index


3️⃣ 主键索引自增优化(Auto Increment Primary Key)

InnoDB 的主键索引是聚簇索引(Clustered Index) ,数据按照主键顺序存储。

如果主键是随机的(比如 UUID),容易导致数据页分裂、碎片多、写入慢。

建议:

复制代码
id BIGINT AUTO_INCREMENT PRIMARY KEY

自增主键能保证数据顺序插入,性能最优。


4️⃣ 索引列设置为 NOT NULL

MySQL 在处理 NULL 时无法高效使用索引(特别是范围查询、排序时)。

建议:

  • 避免在索引列中使用 NULL

  • 可以设置默认值,比如 DEFAULT ''DEFAULT 0


5️⃣ 防止索引失效的情况

索引建立了 ≠ 一定会被用到。

常见的"索引失效"场景如下

场景 例子 原因
使用 OR WHERE a=1 OR b=2 可能导致全表扫描
函数操作 WHERE YEAR(create_time)=2025 函数操作让索引失效
模糊匹配 % 开头 LIKE '%abc' 无法利用前缀索引
隐式类型转换 WHERE num = '123' 类型不同会触发转换
复合索引未遵守"最左前缀原则" 索引(a,b,c),只用 b 查询 无法使用索引

解决方法:

  • 保持字段类型一致

  • 避免对索引列进行计算或函数操作

  • 对字符串匹配尽量使用前缀匹配 LIKE 'abc%'

  • 使用复合索引时遵守"最左前缀原则"


五、总结速记表

类型 原则/技巧 说明
创建索引 WHERE / JOIN / ORDER / GROUP字段 提高查询效率
不建索引 小表 / 高频更新 / 低区分度字段 节省资源
前缀索引 email(10) 节省空间,需测试区分度
覆盖索引 查询字段全在索引中 避免回表
主键自增 AUTO_INCREMENT 防止页分裂
NOT NULL 索引列不应为NULL 提高效率
索引失效 函数、OR、%abc、类型不匹配 避免这些写法
相关推荐
蜂蜜黄油呀土豆1 天前
ThreadLocal 深度解析:它解决了什么、原理是什么、如何正确使用(含代码与实战建议)
java·并发编程·内存泄漏·threadlocal
v***87041 天前
Spring Boot实现多数据源连接和切换
spring boot·后端·oracle
哈哈哈笑什么1 天前
企业级追踪业务数据变动的通用组件
后端
毕设源码-郭学长1 天前
【开题答辩全过程】以 高校教室管理系统为例,包含答辩的问题和答案
java·spring boot
万邦科技Lafite1 天前
API接口地址解析地区码操作指南
网络·数据库·redis·缓存·开放api·电商开放平台
稚辉君.MCA_P8_Java1 天前
Gemini永久会员 go数组中最大异或值
数据结构·后端·算法·golang·哈希算法
罗不丢1 天前
UTC,Date,LocalDate转换问题解决方法
java
此生只爱蛋1 天前
【Redis】常用命令
数据库·redis·缓存
Klong.k1 天前
谈谈session、application存储对象
java·tomcat
Moe4881 天前
Spring Boot启动魔法:SpringApplication.run()源码全流程拆解
java·后端·面试