MySQL索引原理:聚簇与非聚簇索引解析
一、先统一两个关键前提我们只讲MySQL InnoDBMyISAM 结构完全不同现在基本不用所有表的数据本质上就是一棵 B树数据不是散乱存在磁盘上的而是按索引组织好的。二、什么是聚簇索引Clustered Index1. 定义聚簇索引 索引结构 真实数据放在一起叶子节点直接存整行完整数据。2. InnoDB 里的规则一张表有且仅有一个聚簇索引默认就是主键索引没有主键时InnoDB 会自动选一个唯一非空索引还没有就内部生成一个隐藏列ROW_ID当聚簇索引3. 结构长这样非叶子节点主键 指针 叶子节点id1,name张三,age20,... 完整一行数据4. 查询过程以主键查询为例select*fromuserwhereid100;走聚簇索引 B树找到叶子节点直接拿到整行数据结束不需要再查别的地方三、什么是非聚簇索引Secondary Index 二级索引1. 定义非聚簇索引只存索引列 主键叶子节点不存完整数据只存你建索引的字段值对应的主键2. 结构长这样比如给age建索引非叶子节点age 指针 叶子节点age20 → 主键id100 age21 → 主键id1053. 查询过程关键回表select*fromuserwhereage20;先走 age 索引树找到叶子节点得到主键 id100再拿主键去聚簇索引查一遍完整数据这一步就叫回表你说的完全正确非聚簇索引一定会导致回表除非是索引覆盖。四、两者最核心区别一张表看懂对比项聚簇索引非聚簇索引二级索引叶子节点存什么整行完整数据索引字段 主键数量一张表只能一个可以建多个查询是否回表不回表直接拿数据绝大多数情况需要回表物理存储顺序数据按主键物理有序索引有序数据无序查询速度最快比主键查询慢多一次回表IO一句话总结聚簇索引是“数据本身”二级索引是“数据的目录门牌号”。五、重点深度理解为什么不推荐 select * 你这句话非常关键我帮你彻底讲透-- 用二级索引查询还 select *select*fromuserwhereage20;为什么慢必须回表回表是随机IO非常慢如果匹配1000条就要回表1000次那怎么优化—— 索引覆盖只查索引里有的字段就不需要回表-- 只查age和id都在二级索引树上selectage,idfromuserwhereage20;这叫索引覆盖查询速度接近主键查询。所以结论用非主键索引时尽量**不要 select ***只查需要的字段避免大量回表这是 MySQL 性能优化最基础也最重要的一条。六、再深入一层为什么 InnoDB 必须这么设计1. 节省空间如果每个二级索引都存完整数据会极度冗余。比如一张表有5个索引数据就要存5份。2. 保证数据一致性数据只在聚簇索引存一份修改数据时只需要改一次二级索引只需要维护索引列和主键成本极低3. 支持高效范围查询聚簇索引叶子节点是链表范围查询极快。七、初学者最容易混淆的点误区1主键索引 聚簇索引在 InnoDB 里是的完全等价。误区2回表一定很慢少量数据回表还好大量数据回表会爆炸所以分页、大结果集严禁用非聚簇索引 select *误区3索引建越多越好二级索引会降低写入速度INSERT/UPDATE 要维护多棵树而且查询优化器可能选错索引。八、最精炼的记忆口诀适合背诵聚簇索引存数据二级索引存主键一张表一个聚簇默认就是主键二级索引必回表除非索引能覆盖*非主键查不要 select回表多了性能崩九、延伸小知识帮你拔高MyISAM 都是非聚簇索引数据和索引完全分开InnoDB 没有真正的“表数据文件”表就是聚簇索引回表次数 慢查询的第一大元凶联合索引本质也是二级索引只是索引项更大