数据库索引
数据库索引关键知识笔记(学习+面试版)
核心定位:索引是数据库优化的核心,也是面试高频考点(必考!),笔记聚焦「基础概念+核心原理+面试易错点+实战准则」,兼顾学习理解和面试背诵,适配MySQL、PostgreSQL等主流关系型数据库。
一、索引基础(必背,面试开篇基础题)
1.1 索引的定义
索引(Index)是数据库中用于快速查询、筛选数据的数据结构(本质是“排好序的快速查找数据结构”),相当于书籍的目录——通过目录快速定位到目标章节,无需逐页翻阅,核心作用是「减少磁盘I/O,提升查询性能」。
面试提示:不要只说“提升查询速度”,要补充“减少磁盘I/O”(索引的底层逻辑),体现专业性。
1.2 索引的核心作用(正反两面,面试常问)
- 正向作用(核心):① 加速查询(where筛选、join关联、order by排序、group by分组);② 减少全表扫描,降低磁盘I/O开销;③ 保证数据唯一性(唯一索引)。
- 反向代价(易错点):① 占用磁盘空间(索引是独立的数据结构,不是免费的);② 降低写入性能(增/删/改操作时,需同步维护索引树,增加额外开销)—— 索引本质是“以写换读”。
面试考点:“为什么不给所有字段加索引?” → 答:索引会占用磁盘空间,且写入时需维护索引,过度索引会导致写入性能暴跌。
1.3 索引的核心原则(底层判断依据)
索引的价值取决于「字段区分度(基数)」,公式:区分度 = 字段唯一值数量 / 表总行数
- 高区分度(≈1):适合建索引(如id、手机号、订单号),能快速筛选少量数据;
- 低区分度(<0.01):谨慎建索引(如状态字段、逻辑删除字段),筛选数据过多时,索引会失效。
二、索引分类(核心重点,面试高频区分题)
按「功能+结构」分类,重点掌握前4类,其余了解即可,面试常考“聚簇vs非聚簇”“唯一vs普通”的区别。
2.1 按功能分类(实战常用,必背)
| 索引类型 | 核心特点 | 适用场景 | 面试提示 |
|---|---|---|---|
| 主键索引(PRIMARY KEY) | ① 唯一且非空;② 一张表只能有1个;③ 默认是聚簇索引(MySQL) | 所有业务表(唯一标识一行数据) | 必考:“主键索引和普通索引的区别?” |
| 唯一索引(UNIQUE KEY) | ① 唯一,允许NULL(多个NULL不冲突);② 可建多个 | 手机号、邮箱、订单号等需唯一的字段 | 易错:唯一索引≠主键索引,可多个,允许NULL |
| 普通索引(INDEX) | ① 不唯一、允许NULL;② 可建多个;③ 最常用 | 高频查询的非唯一字段(如商品分类、用户名模糊查询) | 注意:低区分度字段(如status)不建议建单列普通索引 |
| 组合索引(联合索引) | ① 多个字段组合建立的索引;② 遵循“最左前缀原则” | 多字段联合查询(如where status=1 and create_time>’2026-01-01’) | 面试必考:最左前缀原则、组合索引的设计顺序 |
| 覆盖索引 | 非独立索引类型,索引包含查询所需所有字段,无需回表 | 高频简单查询(如select id,status from order where status=0) | 核心:减少回表开销,提升查询性能 |
2.2 按结构分类(底层原理,面试必问)
✅ 聚簇索引(Clustered Index)
- 核心:索引结构和数据本身存储在一起,索引的叶子节点就是数据行(MySQL中,主键索引默认是聚簇索引)。
- 优势:查询速度极快,无需回表(找到索引就是找到数据);
- 劣势:① 一张表只能有1个聚簇索引;② 插入/删除时,需移动数据,维护成本高;③ 主键无序(如UUID)会导致索引碎片。
✅ 非聚簇索引(Non-Clustered Index)
- 核心:索引结构和数据分开存储,索引的叶子节点存储的是「主键值」,需通过主键值回表查询具体数据(又称“二级索引”)。
- 优势:① 可建多个;② 插入/删除维护成本低,不影响数据本身;
- 劣势:查询时可能需要回表(除非是覆盖索引),性能略低于聚簇索引。
面试高频题:聚簇索引和非聚簇索引的区别?(直接背以下3点)
- 存储方式:聚簇索引“索引+数据”共存,非聚簇索引“索引和数据分离”;
- 数量限制:聚簇索引最多1个,非聚簇索引可多个;
- 查询性能:聚簇索引无需回表(更快),非聚簇索引需回表(除非覆盖索引)。
2.3 其他索引(了解即可,面试偶尔问)
- 哈希索引:基于哈希表,查询速度极快(O(1)),但不支持排序、范围查询,MySQL的Memory引擎支持;
- 全文索引:用于文本模糊查询(如文章内容搜索),MySQL5.6+支持,性能不如Elasticsearch,仅适用于简单文本查询;
- 空间索引:用于地理空间数据查询(如地图坐标),实际开发中极少用。
三、索引底层数据结构(面试核心难点,必理解+背诵)
主流数据库(MySQL、PostgreSQL)的索引底层都是「B+树」,面试必问“为什么用B+树,不用B树、哈希表?”,重点理解B+树的优势。
3.1 核心数据结构:B+树(重点)
B+树的结构特点(简化理解,无需记复杂节点细节)
- 是「平衡多路查找树」,避免树的高度过高(减少磁盘I/O次数);
- 叶子节点:按顺序排列,存储数据(聚簇索引)或主键值(非聚簇索引),叶子节点之间用指针连接(支持范围查询);
- 非叶子节点:仅存储索引关键字,不存储数据,用于快速定位叶子节点。
B+树的核心优势(面试必背,4点)
- 「高度低,I/O少」:多路查找树,树的高度通常是3-4层(百万级数据,3层即可覆盖),每次查询只需3-4次磁盘I/O,速度极快;
- 「支持范围查询」:叶子节点有序且用指针连接,无需回溯,范围查询(如between、>、<)效率极高;
- 「查询稳定」:所有查询最终都要落到叶子节点,查询时间固定,不会出现极端慢查询;
- 「存储效率高」:非叶子节点不存储数据,仅存索引关键字,单个节点能存储更多关键字,进一步降低树的高度。
3.2 对比其他结构(面试必问,突出B+树的优势)
| 数据结构 | 优势 | 劣势 | 为什么不用? |
|---|---|---|---|
| B树 | 平衡多路查找树,I/O较少 | ① 非叶子节点存储数据,存储效率低,树高更高;② 叶子节点无序,不支持范围查询;③ 查询不稳定(可能在非叶子节点找到数据) | 范围查询差,存储效率低,不如B+树适配数据库场景 |
| 哈希表 | 单值查询极快(O(1)) | ① 不支持范围查询、排序;② 哈希冲突需处理;③ 大量数据时,性能下降明显 | 数据库高频场景(范围查询、排序)不支持,实用性低 |
| 红黑树 | 平衡二叉树,查询、插入、删除效率高 | 二叉树,树高过高(百万级数据,树高约20层),磁盘I/O次数过多 | 树高过高,I/O开销大,不适合大数据量场景 |
面试话术:“MySQL索引底层用B+树,核心原因是B+树高度低、I/O少,支持范围查询和排序,查询稳定,能完美适配数据库的高频查询场景(单值、范围、排序),而B树、哈希表、红黑树都存在明显劣势,无法满足数据库的性能需求。”
四、索引设计准则(实战+面试,必背,避坑重点)
索引设计的核心:「精准匹配业务查询,拒绝过度索引」,按优先级设计,遵循以下准则,能避免95%的索引失效和性能问题。
4.1 索引创建优先级(面试必背,口诀记牢)
口诀:主键必建第一流,唯一索引排前头;组合索引是核心,单列索引兜底用;覆盖索引做优化,过度索引不可留。
- 第一优先级:主键索引(所有表必须有,优先用bigint自增ID,避免UUID);
- 第二优先级:唯一索引(业务唯一字段,如手机号、订单号,兼顾唯一性和查询性能);
- 第三优先级:组合索引(高频多字段联合查询,解决低区分度字段索引失效问题);
- 第四优先级:单列普通索引(仅单一字段高频查询,无组合条件时用);
- 第五优先级:覆盖索引(基于已有索引优化,无需新建,减少回表)。
4.2 状态字段索引设计(高频场景,面试延伸题)
状态字段(status、del_flag等)是低区分度字段,设计索引时需注意:
- ✅ 必加索引的场景:高频查询、筛选后返回少量数据(如where status=0,筛选出1%数据);
- ❌ 不加索引的场景:低频查询、筛选后返回70%以上数据(如del_flag=0占99.9%);
- ⚠️ 核心优化:状态字段不建议建单列索引,优先和其他字段建组合索引(如idx_del_flag_status(del_flag, status))。
4.3 索引设计避坑准则(易错点,面试常考)
- ❌ 不给低区分度+高频筛选+数据分布极端的字段建单列索引(如del_flag,99.9%是0);
- ❌ 不建过度索引(单表索引≤5个,最多不超过8个);
- ❌ 不给更新频率远大于查询频率的字段建索引(如实时更新的支付状态,写入多、查询少);
- ✅ 组合索引设计:高频筛选字段放左边,区分度高的字段放左边(如idx_status_createtime(status, create_time));
- ✅ 优先用数值类型建索引(如status用tinyint,不用varchar),避免隐式类型转换;
- ✅ 避免用NULL值(NULL会导致索引失效,可设置默认值,如status默认0)。
五、索引失效场景(面试重中之重,必背+举例)
索引失效是面试高频题,常考“以下SQL为什么不走索引?”,核心记住:「只要破坏索引的查询逻辑,就会失效」,重点场景如下(带SQL示例,方便理解)。
5.1 核心失效场景(必背,8个)
- 对索引字段做函数运算(最常见) 示例:
select * from user where date(create_time) = '2026-01-01'原因:函数运算会破坏索引的有序性,数据库无法走索引,需优化为:select * from user where create_time between '2026-01-01 00:00:00' and '2026-01-01 23:59:59' - 索引字段发生隐式类型转换 示例:
select * from user where status = '1'(status是tinyint类型,传入字符串) 原因:数据库会自动转换类型,等价于cast(status as char) = '1',破坏索引有序性。 - 使用不等于(!=、<>)、not in、is not null 示例:
select * from user where status != 1原因:这类查询会筛选出大部分数据,数据库认为走索引开销大于全表扫描,直接放弃索引。 - 模糊查询以%开头 示例:
select * from user where name like '%张三'原因:%开头无法利用索引的有序性,无法快速定位,若必须模糊查询,可用覆盖索引或全文索引。 ✅ 有效写法:select * from user where name like '张三%'(%结尾,可走索引) - 违反组合索引的最左前缀原则 示例:组合索引
idx_a_b_c(a,b,c),查询select * from user where b=2 and c=3原因:最左前缀原则要求“从左到右匹配索引字段”,缺少a字段,索引完全失效。 - or连接非索引字段 示例:
select * from user where status=1 or age=20(age无索引) 原因:or连接的字段中,有一个无索引,数据库会放弃所有索引,走全表扫描。 - 索引字段数据分布极端(低区分度+大部分数据符合条件) 示例:
select * from user where del_flag=0(del_flag=0占99.9%) 原因:走索引的开销>全表扫描,数据库自动选择全表扫描。 - 使用order by非索引字段 示例:
select * from user where status=1 order by age(age无索引) 原因:非索引字段排序,需进行文件排序(filesort),效率极低,且会导致索引失效。
5.2 索引失效排查技巧(面试延伸,体现实战能力)
实际开发中,用MySQL的explain命令排查索引是否生效:
- 看
type字段:all(全表扫描,索引失效)、ref/range/eq_ref(索引生效); - 看
key字段:显示NULL,说明索引失效;显示具体索引名,说明走了对应索引; - 看
Extra字段:出现Using filesort(排序失效)、Using where; Using filesort(索引失效+排序失效)。
六、面试高频真题(直接背诵,适配面试场景)
以下真题是大厂面试高频题,整理好标准答案,直接背诵,避免面试卡顿。
真题1:什么是索引?索引的作用和代价分别是什么?
答:索引是数据库中用于快速查询、筛选数据的数据结构,本质是排好序的快速查找结构,相当于书籍目录。 作用:① 加速查询,减少磁盘I/O;② 保证数据唯一性(唯一索引)。 代价:① 占用磁盘空间;② 降低写入性能(增删改需维护索引树),索引是“以写换读”。
真题2:聚簇索引和非聚簇索引的区别?MySQL中默认是什么索引?
答:区别有3点:① 存储方式:聚簇索引“索引+数据”共存,非聚簇索引分离;② 数量限制:聚簇索引最多1个,非聚簇索引可多个;③ 查询性能:聚簇索引无需回表,非聚簇索引需回表(除非覆盖索引)。 MySQL中,主键索引默认是聚簇索引,若无主键,会选择唯一非空索引作为聚簇索引,若都没有,会自动生成隐藏聚簇索引。
真题3:MySQL索引底层为什么用B+树,不用B树、哈希表?
答:核心原因是B+树能完美适配数据库的高频查询场景,优势如下:① 高度低,I/O少,3-4层即可覆盖百万级数据,查询速度快;② 叶子节点有序且连表,支持范围查询和排序;③ 查询稳定,所有查询都落到叶子节点;④ 非叶子节点不存数据,存储效率高。 不用B树:B树非叶子节点存数据,存储效率低,不支持范围查询; 不用哈希表:哈希表不支持范围查询、排序,哈希冲突需处理,大数据量性能下降。
真题4:什么情况下索引会失效?举3个常见例子。
答:破坏索引查询逻辑,就会导致索引失效,常见例子:① 对索引字段做函数运算(如date(create_time)=’2026-01-01’);② 模糊查询以%开头(如name like ‘%张三’);③ 违反组合索引最左前缀原则(如组合索引idx_a_b,查询where b=2);④ 索引字段隐式类型转换(如status=’1’,status是tinyint)。
真题5:如何设计高效的索引?状态字段(如status)如何建索引?
答:高效索引设计遵循优先级:主键索引→唯一索引→组合索引→单列普通索引,核心准则是“精准匹配业务查询,拒绝过度索引”,还要注意:① 高频查询字段优先建索引;② 组合索引高频字段、高区分度字段放左边;③ 避免过度索引(单表≤5个);④ 数值类型优先建索引。 状态字段(低区分度):不建议建单列索引,若高频查询,优先和其他字段建组合索引(如idx_status_createtime(status, create_time));若筛选后返回大部分数据,不建索引。
真题6:唯一索引和主键索引的区别?
答:① 唯一性:两者都保证唯一,但主键索引非空,唯一索引允许NULL;② 数量限制:主键索引只能有1个,唯一索引可建多个;③ 存储方式:主键索引默认是聚簇索引,唯一索引是非聚簇索引(除非无主键,唯一非空索引成为聚簇索引)。
七、总结(核心背诵口诀,快速回顾)
核心口诀(面试前快速过一遍)
- 索引本质:排好序的目录,以写换读,减少I/O;
- 分类口诀:主键唯一组合列,聚簇非聚分清楚;覆盖索引提性能,哈希全文了解足;
- 底层口诀:B+树是核心,高度低、支持范围,查询稳定效率高;
- 设计口诀:主键必建,唯一优先,组合核心,单列兜底,过度不行;
- 失效口诀:函数转换不等,%前or非索引,最左前缀别违反,数据极端也失效。
面试提示
索引面试重点:底层B+树、聚簇vs非聚簇、索引失效、设计准则,这4个部分占90%的考点,优先背诵;其他知识点(如哈希索引、空间索引)了解即可,无需深入。回答问题时,结合SQL示例,体现实战能力,会更加分。

