java面试必问14:MySQL 索引类型:从基础到优化,面试官给你点赞

MySQL 索引类型:从基础到优化,一篇讲透

面试官:"MySQL 有哪些索引类型?"

你:"主键索引、唯一索引、普通索引、复合索引、全文索引。索引能大大加快查询速度,但会降低增删改的性能。"

面试官:"那复合索引的最左前缀原则是什么?为什么会有这个原则?"

你:"......"

很多人能列出索引类型,但一追问"什么时候索引会失效""如何设计高效索引"就含糊了。本文从索引的底层结构出发,讲透各种索引的特点和使用场景。


一、索引是什么?

索引是数据库中的一种数据结构 ,类似于书的目录,可以快速定位数据所在的位置,避免全表扫描。MySQL 中常用的索引结构是 B+Tree(InnoDB 存储引擎)。索引虽然能加速查询,但需要额外的存储空间,并且在数据插入、更新、删除时需要同步维护,因此会降低写入性能。


二、五种索引类型详解

1. 主键索引(PRIMARY KEY)

  • 特点:唯一且非空,一个表只能有一个主键索引。
  • 底层:聚簇索引(Clustered Index),叶子节点直接存储整行数据。
  • 创建
sql 复制代码
CREATE TABLE user (
    id INT PRIMARY KEY,   -- 主键索引
    name VARCHAR(50)
);
-- 或单独添加
ALTER TABLE user ADD PRIMARY KEY (id);
  • 注意:InnoDB 中,如果没有显式定义主键,会自动选择一个唯一非空索引作为聚簇索引;如果也没有,则隐式生成一个 6 字节的 rowid 作为主键。建议每个表都显式指定主键。

2. 唯一索引(UNIQUE)

  • 特点:索引列的值必须唯一,但允许 NULL(可以有多个 NULL)。
  • 作用:保证数据唯一性,同时加速查询。
  • 创建
sql 复制代码
CREATE TABLE user (
    id INT PRIMARY KEY,
    email VARCHAR(100) UNIQUE   -- 唯一索引
);
-- 或
CREATE UNIQUE INDEX idx_email ON user(email);

3. 普通索引(INDEX / KEY)

  • 特点:最基本索引,无唯一性约束,允许重复值。
  • 作用:加速查询,是最常用的索引类型。
  • 创建
sql 复制代码
CREATE INDEX idx_name ON user(name);

4. 复合索引(Composite Index)

  • 特点 :在多个列上建立一个索引,遵循最左前缀原则
  • 作用 :同时加速对多个列的查询,尤其适合 WHERE 条件中包含多个字段的场景。
  • 创建
sql 复制代码
CREATE INDEX idx_name_age ON user(name, age);

查询 WHERE name = '张三' AND age = 25 可以利用该索引;但 WHERE age = 25 不能使用该索引(因为没有使用索引的最左列 name)。

5. 全文索引(FULLTEXT)

  • 特点 :用于全文搜索(类似搜索引擎),仅支持 MyISAMInnoDB(MySQL 5.6+)。
  • 作用 :对文本内容进行关键词匹配,比 LIKE '%keyword%' 高效得多。
  • 创建
sql 复制代码
CREATE TABLE article (
    id INT PRIMARY KEY,
    content TEXT,
    FULLTEXT(content)
);
-- 查询
SELECT * FROM article WHERE MATCH(content) AGAINST('数据库优化');
  • 注意:全文索引有停用词、最小词长度等限制,适合大文本字段的搜索场景。

三、索引的优缺点

优点 缺点
大大加快 SELECT 查询速度 占用额外磁盘空间
加速 ORDER BYGROUP BY 降低 INSERTUPDATEDELETE 速度(需维护索引)
唯一索引能保证数据唯一性 索引设计不合理会导致查询优化器选错索引

权衡:索引不是越多越好。一般建议对查询频繁、区分度高的列建索引,避免在低基数列(如性别)或频繁更新的列上建索引。


四、复合索引的最左前缀原则(重点)

复合索引 (a, b, c) 实际上相当于创建了三个索引:(a)(a, b)(a, b, c)。查询时只有从索引的最左列开始匹配才能使用索引。

能用索引的情况:

  • WHERE a = 1
  • WHERE a = 1 AND b = 2
  • WHERE a = 1 AND b = 2 AND c = 3
  • WHERE a = 1 AND c = 3(只用到 a,c 无法使用,但 a 可过滤一部分)

不能用索引的情况:

  • WHERE b = 2(没有最左列 a)
  • WHERE b = 2 AND c = 3

范围查询的影响:

  • WHERE a = 1 AND b > 2 AND c = 3:a 和 b 能用到索引,c 用不到(因为 b 是范围查询,后面的列停止匹配)。

设计建议:将区分度高的列放在复合索引左侧,等值查询的列优先于范围查询的列。


五、索引失效的常见场景

场景 示例 原因
对索引列使用函数 WHERE YEAR(create_time) = 2024 无法使用索引,应改为范围查询
隐式类型转换 WHERE phone = 13800138000(phone 是 varchar) 类型不匹配,索引失效
LIKE 以通配符开头 WHERE name LIKE '%张三' 无法使用索引
OR 前后未全索引 WHERE a = 1 OR b = 2(只有 a 有索引) 需要全表扫描
使用 !=<> WHERE status != 0 非等值查询一般不用索引
使用 IS NULLIS NOT NULL 某些情况下失效,取决于版本和数据分布 -

六、如何评估索引是否有效?

使用 EXPLAIN 命令查看执行计划:

sql 复制代码
EXPLAIN SELECT * FROM user WHERE name = '张三';

关键列:

  • typeconst > ref > range > index > ALL(好到差)
  • possible_keys:可能使用的索引
  • key:实际使用的索引
  • rows:预估扫描行数
  • ExtraUsing index 表示覆盖索引(不回表),Using where 表示需要过滤

七、常见面试追问

Q1:主键索引和唯一索引的区别?

  • 主键索引不允许 NULL,唯一索引允许 NULL(多个 NULL)。
  • 一个表只能有一个主键,可以有多个唯一索引。
  • 主键通常是聚簇索引(InnoDB),唯一索引是辅助索引。

Q2:为什么推荐使用自增整数做主键?

  • 插入时顺序写入,B+Tree 页分裂少,性能高。
  • UUID 或随机字符串作为主键会导致随机插入,页分裂频繁,且占用空间大。

Q3:什么是覆盖索引?

如果一个索引包含了查询所需的所有列(即 SELECT 的列都在索引中),那么不需要回表查询数据行,称为覆盖索引。例如:

sql 复制代码
CREATE INDEX idx_name ON user(name);
SELECT name FROM user WHERE name = '张三';  -- 覆盖索引,不回表

Q4:索引下推(Index Condition Pushdown)是什么?

MySQL 5.6 引入的优化:在索引遍历过程中,对索引中包含的字段先做条件过滤,减少回表次数。例如 INDEX(a, b),查询 WHERE a = 1 AND b = 2,没有 ICP 时会先根据 a=1 回表再过滤 b;有 ICP 时直接在索引中判断 b=2,只回表符合的数据。

Q5:联合索引中,字段顺序如何设计?

  • 区分度高的列放在左侧。
  • 等值查询的列放在左侧,范围查询的列放在右侧。
  • 经常用于排序的列可以考虑加入索引(ORDER BY 也能利用索引顺序)。

八、总结

索引类型 特点 适用场景
主键索引 唯一、非空、聚簇 每张表必备,作为行标识
唯一索引 值唯一,可 NULL 保证字段唯一性(如邮箱、手机号)
普通索引 无约束 加速查询,最常用
复合索引 多列组合,最左前缀 多条件查询、排序
全文索引 关键词匹配 大文本搜索(如文章、评论)

一句话记住索引设计等值左前缀,范围右靠后;覆盖索引少回表,函数运算全失效

索引是把双刃剑,合理的索引能让查询飞起来,滥用索引会让写入慢如牛。理解索引类型和原理,是 MySQL 优化的第一步。

希望这篇文章能帮你彻底掌握 MySQL 索引的相关知识,从容应对面试和实际调优,欢迎继续讨论。

我的个人简介最后有一段内容,感兴趣的朋友可以去找找看。那里有我日常分享的技术深度 解析和职场避坑指南,期待与您继续交流。

相关推荐
helx822 小时前
spring-ai 下载不了依赖spring-ai-openai-spring-boot-starter
java
SimonKing2 小时前
轻量级富文本编辑器Quill,保姆级教程,5分钟快速上手
java·后端·程序员
iNgs IMAC2 小时前
MySQL无法连接到本地localhost的解决办法2024.11.8
数据库·mysql·adb
tIzE TERV2 小时前
mysql数据被误删的恢复方案
数据库·mysql
ID_180079054732 小时前
京东商品详情 API 数据分析业务场景 + JSON 返回参考
java·开发语言
eRTE XFUN2 小时前
mysql用户名怎么看
数据库·mysql
xyyaihxl2 小时前
springboot系列--自动配置原理
java·spring boot·后端
weyyhdke2 小时前
Java进阶-在Ubuntu上部署SpringBoot应用
java·spring boot·ubuntu
前端摸鱼匠2 小时前
【AI大模型春招面试题24】什么是“注意力分数”?如何计算?其大小反映了什么?
人工智能·算法·ai·面试·大模型·求职招聘