Mysql

关注公众号 jb51net

关闭
首页 > 数据库 > Mysql > MySQL聚簇索引

MySQL聚簇索引深入讲解(含例子)

作者:南寻(新人笔记)

聚簇索引作为关系型数据库的核心特性,其概念和实践在传统单机数据库中已发展成熟,随着分布式数据库的兴起,聚簇索引的实现和优化面临着新的挑战与机遇,这篇文章主要介绍了MySQL聚簇索引的相关资料,需要的朋友可以参考下

一、聚簇索引定义

InnoDB只有聚簇索引,表数据本身就是一棵 B + 树:

二、B + 树对比 B 树,为什么 InnoDB 选 B + 树(深挖题)

表格

维度

B 树

B + 树(InnoDB 选用)

数据存储

所有节点存完整数据

仅叶子存完整数据,非叶子只存主键

IO 次数

树更高,查询 IO 更多

树更矮,IO 次数少(磁盘慢,减少 IO = 提速)

范围查询

需遍历多分支

叶子节点双向链表,范围扫描只顺链表走,极快

缓存效率

非叶子占大量空间,缓存命中率低

非叶子节点体积小,可全部载入内存

三、主键选择三大铁律(面试官高频追问)

4. 页分裂 / 页合并(深挖原理 + 调优场景)

四、辅助索引(二级索引 / 普通索引)深度深挖

1. 辅助索引存储结构(面试灵魂提问:二级索引叶子存什么?)

辅助索引也是独立 B + 树:

2. 回表(书签查找)核心流程(必考)

CREATE INDEX idx_name ON user(name);
SELECT * FROM user WHERE name='张三';

3. 覆盖索引(避免回表,面试最优解)

如果查询字段全部包含在辅助索引内,无需回表,称为覆盖索引,执行计划Extra显示Using index。

-- 覆盖索引,无需回表
SELECT id,name FROM user WHERE name='张三';
-- 无覆盖索引,必须回表查age
SELECT id,name,age FROM user WHERE name='张三';

优化方案:建立联合索引 idx_name_age(name,age),将查询字段放进索引叶子。

4. 联合索引(复合索引)+ 最左匹配原则(深挖边界坑)

(1)底层存储

联合索引叶子存储:(索引列1,索引列2,...,主键),排序规则严格按左到右依次比较。

(2)最左匹配完整规则(面试官最爱挖坑)

索引 idx(a,b,c)

(3)联合索引排序优化

排序字段遵循最左前缀,避免Using filesort:索引idx(a,b)

5. 唯一索引 / 普通索引 差异深挖

6. 前缀索引(字符串索引优化,边界坑)

长字符串直接建索引占用空间极大,用前缀索引截取前 N 位:CREATE INDEX idx_name ON user(name(10));致命缺陷:无法做覆盖索引,因为索引只存前 10 位,回表不可避免;无法使用排序、分组。

五、MVCC 与索引联动(大厂高并发面试难点)

1. 可见性依托聚簇索引隐藏列

聚簇索引叶子行自带DB_TRX_ID、DB_ROLL_PTR:

2. 当前读(加锁读)索引锁机制(锁 + 索引连环面试题)

经典面试题:update user set name='a' where id>10 为什么并发插入 id=12 会阻塞?答:聚簇索引范围查询触发临键锁,锁定 (10,+∞) 间隙,阻止新数据插入,解决幻读。

六、索引失效全场景总结(手写执行计划高频题)

七、索引优化实战(业务场景面试题)

1. 建索引黄金规范

2. 慢 SQL 索引排查命令

-- 查看执行计划,判断是否走索引、是否回表、是否文件排序
explain select ...;
-- 统计索引使用情况,长期不用的索引可删除
sys.schema_unused_indexes;
-- 查看页分裂、索引IO性能
show engine innodb status;

八、大厂高频深挖面试连环题(问答版)

Q1:聚簇索引和 MyISAM 索引有什么本质区别?

A:

Q2:为什么不推荐 UUID 当主键?

A:UUID 无序,随机值插入会频繁触发页分裂,大量磁盘碎片;UUID 长度 36 字符,非叶子节点存储量大,树高度增加,IO 次数暴涨;无法自增,无顺序追加优化。

Q3:覆盖索引为什么快?

A:辅助索引 B + 树叶子已经包含所有查询字段,不需要二次访问聚簇索引,省去一次 B + 树磁盘 IO,是查询最优方案。

Q4:什么是索引下推 ICP?作用?

A:MySQL5.6 + 优化;在辅助索引扫描时,把 where 条件里的索引列过滤下推到存储引擎层,不用回表到 server 层过滤,减少回表次数,大幅降低 IO。例:idx(a,b) where a=1 and b>10,引擎层直接过滤 b,不回表。

Q5:联合索引 (a,b),where b=? order by a 能走索引排序吗?

A:不能,违背最左前缀,索引按 a 先排序,跳过 a 直接查 b,索引有序性失效,会触发 Using filesort。

Q6:一张表多个索引,MySQL 怎么选择用哪个?

A:优化器计算各索引扫描代价(需要读取的数据页数量),选择代价最小的;如果索引扫描页数超过全表 30%,直接放弃索引走全表扫描。可以用force index(索引名)强制指定。

Q7:delete 大量数据后,索引空间会自动释放吗?

A:不会。delete 仅标记记录删除,页面空间不会归还磁盘,只是标记空闲复用;大量删除产生碎片,需执行OPTIMIZE TABLE重建索引整理空间。

Q8:行锁依赖索引,如果 SQL 没走索引会锁全表,底层原理是什么?

A:SQL 无法定位精确数据行,InnoDB 只能对聚簇索引所有数据页加临键锁,锁定整张表所有记录,并发写入全部阻塞,线上极易死锁、性能雪崩。

Q9:自增主键为什么能避免页分裂?

A:主键持续递增,新增行永远写入当前最后一个数据页,页面填满后才新建下一页,不会往已有页面中间插入数据,几乎无页分裂,磁盘顺序写入,性能极高。

Q10:辅助索引存储主键,主键越大对索引有什么影响?

A:二级索引叶子每条记录都存储主键,主键越长,单页能存放的索引行数越少,B + 树高度增加,查询时磁盘 IO 次数变多,索引占用磁盘空间成倍上涨。

九、高阶拓展(P6/P7 面试官追加提问)

到此这篇关于MySQL聚簇索引的文章就介绍到这了,更多相关MySQL聚簇索引内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文