一、索引的定义与核心作用
1. 定义
索引是 MySQL 中用于优化查询效率的数据结构,类比书籍的"目录",无需遍历全表即可快速定位数据位置。
2. 核心作用
提升查询速度:避免全表扫描(Full Table Scan),减少磁盘 I/O 和 CPU 资源消耗;
优化排序/分组:支持 GROUP BY ORDER BY 操作快速完成(无需额外排序);
加速表连接:优化 JOIN 操作中关联字段的匹配效率。
二、索引的工作逻辑
当执行 SELECT 查询时,MySQL 执行流程如下:
-
解析查询语句,识别查询的表和字段;
-
检查该字段是否存在索引:
若有索引:遍历索引表(数据结构如 B+ 树),快速定位到数据记录行的物理地址,直接读取数据;
若无索引:执行全表扫描,逐行遍历表中所有数据,匹配目标结果(效率低、资源消耗高)。
三、索引的副作用(不可忽视)
索引并非"越多越好",存在以下代价:
-
占用额外磁盘空间:索引表独立于数据表格,会消耗磁盘存储(如大表的组合索引可能占用大量空间);
-
增加更新开销:修改(
INSERT/UPDATE/DELETE)含索引的表时,需同步更新对应的索引表(如修改主键值时,主键索引需重新排序); -
不合理索引降低效率:如在低选择性字段创建索引,可能导致 MySQL 放弃使用索引,直接全表扫描。
四、索引的创建依据(适合/不适合场景)
1. 适合创建索引的场景
主键和外键:默认创建主键索引,外键常用于表连接,必须建索引;
大数据量表:记录数超过 300 行的表,全表扫描代价过高;
高频查询字段:WHERE 子句中频繁出现的字段(如用户查询、筛选条件);
连接/排序/分组字段:JOIN 关联字段、GROUP BY/ORDER BY 操作的字段;
高选择性字段:字段不同值占比高(如身份证号、手机号,选择性接近 1),索引过滤效果好;
小字段:优先在 INT、VARCHAR(短) 等小字段建索引(长文本、BLOB 等大字段索引开销极高)。
2. 不适合创建索引的场景
低选择性字段:如性别(男/女)、布尔值(0/1),索引过滤效果差,不如全表扫描;
更新频繁的字段:如订单状态(高频更新),索引同步开销会抵消查询收益;
小表(<300 行):全表扫描速度快,索引带来的开销大于收益;
高频全表查询字段:若查询常使用 SELECT * 且无过滤条件,索引无效。
五、MySQL 常见索引类型及特点
| 索引类型 | 核心特点 | 适用场景 |
|---|---|---|
| 主键索引(PRIMARY KEY) | 唯一、非空,一张表仅一个,默认自动创建,底层为聚簇索引(数据与索引存储在一起) | 表的唯一标识(如用户 ID、订单 ID) |
| 唯一索引(UNIQUE KEY) | 字段值唯一(允许 NULL 值,仅一个 NULL),避免重复数据 | 用户名、邮箱等需唯一约束的字段 |
| 组合索引(复合索引) | 基于多个字段创建(如 idx_name_age (name, age)),遵循"最左前缀原则" |
多字段联合查询(如 WHERE name='xxx' AND age=xx) |
| 全文索引(FULLTEXT) | 支持长文本模糊匹配(如文章内容、评论),不支持精确查询 | 博客、新闻等文本内容的关键词搜索 |
补充:组合索引"最左前缀原则"
示例:创建组合索引 idx_a_b_c (a, b, c),仅支持以下查询场景命中索引:
-
WHERE a=?(左前缀匹配) -
WHERE a=? AND b=?(连续前缀匹配) -
WHERE a=? AND b=? AND c=?(全匹配)
不命中场景:WHERE b=? WHERE a=? AND c=?(跳过中间字段)。
六、索引与慢查询的关联
1. 慢查询与索引的关系
慢查询定义:默认情况下,执行时间超过 2 秒的 SELECT 语句(可通过 long_query_time 配置修改);
核心原因之一:查询未使用索引(全表扫描),导致耗时过长;
配置日志记录:在 /etc/my.cnf 中开启以下配置,记录未使用索引的慢查询:
TOML
[mysqld]
slow_query_log = 1 # 开启慢查询日志
slow_query_log_file = /var/lib/mysql/mysql-slow.log # 日志存储路径
long_query_time = 2 # 慢查询阈值(单位:秒)
log_queries_not_using_indexes = 1 # 记录未使用索引的 SQL
配置后需重启 MySQL 服务生效。
2. 验证索引有效性:EXPLAIN 工具
作用:分析 SQL 执行计划,查看是否使用索引、索引类型、扫描行数等;
用法:在查询语句前加 EXPLAIN,示例:
SQL
EXPLAIN SELECT * FROM user WHERE id=1;
关键字段解读:
-
type:索引使用类型(ALL表示全表扫描,ref/range/eq_ref表示使用索引); -
key:实际使用的索引名称(NULL表示未使用索引); -
rows:预估扫描的行数(值越小,效率越高)。
七、索引底层与优化技巧
1. 索引底层数据结构(MySQL 默认)
采用 B+ 树 结构,优势:
叶子节点有序排列,支持范围查询(如 BETWEEN IN);
叶子节点存储数据地址(非聚簇索引)或数据本身(聚簇索引),查询效率稳定;
树高度低(百万级数据仅需 3-4 层),磁盘 I/O 次数少。
2. 聚簇索引 vs 非聚簇索引
聚簇索引:索引与数据存储在一起(如主键索引),查询无需"回表",效率最高;
非聚簇索引:索引与数据分离,叶子节点存储主键值,查询需通过主键值二次查找数据(回表),效率略低。
3. 索引失效的常见场景(避坑!)
索引字段使用函数/运算:WHERE SUBSTR(name,1,2)='张'(无法命中 name 索引);
模糊查询以 % 开头:WHERE name LIKE '%三'(全模糊 %三% 也失效);
OR 条件中部分字段无索引:WHERE id=1 OR age=20(若 age 无索引,整个查询可能全表扫描);
隐式类型转换:WHERE phone='123456'(phone 为 INT 类型,字符串与数字转换导致索引失效);
联合查询中违背最左前缀原则(见组合索引部分)。
4. 索引优化技巧
覆盖索引:查询字段仅包含索引列(如 SELECT id, name FROM user WHERE id=1,id 为主键索引),避免回表;
定期维护索引:删除冗余索引(如已存在 idx_a_b,无需再建 idx_a)、优化碎片索引(OPTIMIZE TABLE 表名);
避免过度索引:一张表索引数量建议不超过 5 个,过多索引会导致更新变慢。
八、核心小结
-
索引核心价值:加速查询,减少全表扫描开销;
-
创建原则:"高频查询、高选择性、小字段"优先,避开"更新频繁、低选择性"字段;
-
验证工具:用
EXPLAIN检测索引是否生效,结合慢查询日志优化索引; -
平衡取舍:索引并非越多越好,需权衡查询效率与更新开销。