面试官:MySQL 索引是什么?这道题答全的人真不多

面试被问到 MySQL 索引,多数人的回答停留在"加快查询"四个字。

这话对,但没用。

索引真正要讲清楚的,是一份排好序的目录:

索引可以理解成一份排好序的目录,它通过维护特定的数据结构,让数据库能够更快定位目标数据,而不必每次都扫描整张表。

代价也实打实------写数据时要顺手维护它,空间上多占一份。

用写入和空间换查询速度,这层账得算明白。

索引到底是什么

拿查字典说最清楚。

没有目录,找一个字得从第一页翻到最后一页,数据库管这叫全表扫描。

有了拼音目录,先定位到那一页再细看,这就是索引查找。

MySQL 的索引就是这张目录。

它是存储引擎层建的辅助数据结构, 以 InnoDB 的 B+ 树索引为例,它会按照索引列的值组织数据,使查询能够沿着索引结构快速定位目标记录。

说白了,索引在存储引擎层,不在 Server 层。

不同存储引擎的索引实现走的不是一条路,InnoDB 和 MyISAM 就是两套完全不同的方案,后面细说。

底层为什么是 B+ 树

面试官八成会追问:

凭什么用 B+ 树,不用 B 树?

官方文档写的是 "B-tree",但面试和平时交流里一定说 B+ 树。

它两个特征最关键:

非叶子节点只存索引键和指针,不存数据,所以同一层能塞下更多键,树更矮;

所有叶子节点用链表串起来,天然有序,范围查询和排序顺着链表走就行。

树矮的意义在 IO。

B+ 树的高度通常比较低,一次索引查找只需要经过少量层级;

如果相关索引页不在 Buffer Pool 中,才需要从磁盘读取,因此能够显著减少磁盘 IO。

树的高度越低,查找需要访问的节点越少,通常也意味着更少的 IO 开销。

二叉树太高、哈希表不支持范围查询和排序,都不如 B+ 树全面。

聚簇、非聚簇,还有回表

这块最容易答偏。

InnoDB 里索引分两类。

聚簇索引的叶子直接存整行,一张表只有一个,通常就是主键。

二级索引的叶子存的是主键值,不是整行。

问题就出在二级索引上。

你写 where name = '张三',引擎先在 name 索引里找到张三对应的主键,再拿主键去聚簇索引把整行捞出来。这多走的一步叫回表。

MyISAM 是另一条路:

它的索引叶子存行号,拿到行号去数据文件按位置读。

所以 MyISAM 没有聚簇的概念,索引全是二级的。

索引不只是加快查询

检索提速、降 IO 是本职。

一张千万级的订单表跑 where order_id = 16815,没索引只能全表扫描把每页读一遍,IO 开销极大;

建了 order_id 索引,可以沿着 B+ 树快速定位目标记录,大幅减少需要扫描的数据页和 IO 开销。

ORDER BYGROUP BY 在满足索引顺序等条件时,可以利用索引本身的有序性减少排序开销,而不一定需要额外的排序操作。

具体是否使用索引,要结合执行计划判断。

看执行计划 Extra 列,本来会显示 Using filesort,用了索引有序性这一项就消失。

唯一索引还能保数据完整。

主键和唯一索引靠唯一约束挡脏数据,比如用户表给 phone 建唯一索引,重复手机号直接写不进去。这比在 Java 代码里判重可靠,数据库层约束是硬性的,并发下也不会漏。

作用 说明
检索提速 大幅减少需要扫描的数据页和 IO 开销
排序 / 分组 利用索引有序性,减少额外排序开销
数据完整 唯一 / 主键索引挡住重复脏数据

但索引不是免费的。

每次写入,索引都得跟着更新。

B+ 树插入可能引发页分裂,删除可能触发页合并,都是实打实的额外开销。

所以写多读少的表,索引越多写入越慢,反而成了一种负担。

索引本身也会占用额外存储空间,表上索引越多,占用的空间和维护成本通常也越高,不是越多越好。索引多了,优化器选择执行计划的成本也可能增加。

还有一些常见场景会让普通索引难以有效利用,比如 LIKE '%张' 这种左模糊查询、对索引列进行函数计算,以及部分隐式类型转换。

遇到这类情况不要凭感觉判断,最好结合 EXPLAIN 查看实际执行计划。

必要时再考虑其他优化方案,而不是直接依赖 FORCE INDEX

索引难以有效利用的常见场景 原因
like '%张' 左模糊 前缀不确定,B+ 树有序性用不上
字段套函数 where year(createtime)=2024 索引列被计算,无法命中
类型不匹配 where phone = 13800000000(phone 是字符串) 隐式转换导致索引失效

所以这道题别只说"加快查询"。

从 B+ 树结构、InnoDB 的回表、到作用和优缺点体系化讲一遍,面试官才信你是真懂。

相关推荐
特立独行的猫a3 小时前
我用 Rust + Tauri 2 复刻了 N_m3u8DL-CLI:一个 m3u8 多线程下载器
开发语言·后端·rust·m3u8·视频下载器·m3u8dl-cli
月光有害3 小时前
理解 Spring 依赖注入:从构造器注入到集合与条件 Bean
java·后端·spring
对象存储与RustFS3 小时前
大文件传到 48 GiB 就断:S3 分片上传的参数怎么算,以及那些没人清的残片
后端·rust·开源
foggyprojects3 小时前
客户说“销售额”,系统怎样落到订单含税金额或开票含税销售额?
后端
念何架构之路3 小时前
路由注册:RouterGroup(routergroup.go)
开发语言·后端·golang
小当家.1053 小时前
LLM服务缓存与连接池管理:三层缓存架构与ChatClient池化
java·后端·spring·缓存·llm·agent
人间凡尔赛4 小时前
当 AI Agent 攻陷网关:Istio agentgateway 与 Gateway API Inference Extension 实战解析
后端·云原生·架构
wwwzhouzy4 小时前
SpringBoot 响应式编程
java·spring boot·后端·响应式编程
Python私教4 小时前
请求超时不等于失败:把写操作恢复设计成事实回读
后端·python