
PRIMARY KEY 索引不是“带唯一约束的普通索引”,它是聚簇索引,直接决定整张表数据的物理存放顺序;所有二级索引(INDEX、UNIQUE INDEX、FULLTEXT)都只是“查主键的跳板”,必须回表。
主键索引 = 聚簇索引:数据就长在叶子节点里
InnoDB 中,PRIMARY KEY 索引的 B+ 树叶子节点存的是**整行记录**,不是指针、不是 ID、不是偏移量——就是 SELECT * FROM t 返回的那条数据原样。这意味着:
-
SELECT * FROM user WHERE id = 123只需一次 B+ 树搜索,拿到叶子页就完事,不涉及额外 IO - 如果没有显式定义
PRIMARY KEY,InnoDB 会找NOT NULL UNIQUE列顶上;都找不到,就用隐藏的 6 字节row_id—— 这会导致ORDER BY或SELECT *结果不可预测 - 主键越短越好:
BIGINT比VARCHAR(36)做主键,B+ 树层级更少,范围扫描更快,且二级索引叶子节点里存的主键值也更小,省空间
二级索引叶子节点只存「字段值 + 主键值」
比如你在 name 上建了普通索引:CREATE INDEX idx_name ON user(name),它的 B+ 树叶子节点内容是类似 ('Alice', 105) 这样的二元组,其中 105 是对应行的主键值。
-
SELECT name FROM user WHERE name = 'Alice'→ 覆盖索引,不用回表,直接从二级索引里取值 -
SELECT email FROM user WHERE name = 'Alice'→ 必须拿着105去主键索引再查一遍,这就是“回表”,IO 成本翻倍 - 联合索引
INDEX (a, b, c)的最左前缀生效规则严格:WHERE b = 2不走索引;WHERE a = 1 AND b = 2 ORDER BY c才可能避免文件排序
为什么 EXPLAIN 显示 type=const 却还带 Using where
这不是优化器“没尽力”,而是你误用了非主键字段做等值查询,或者字段类型隐式转换导致索引失效。例如:
-
id是BIGINT,但查询写成WHERE id = '123'→ 字符串转数字触发隐式转换,PRIMARY KEY索引可能失效 - 用
CHAR字段做索引,但查询值带空格或长度超限,也会让匹配失败 -
EXPLAIN中key字段为空,Extra出现Using where; Using filesort,基本可以断定没走对索引,优先检查字段类型和是否加了函数(如WHERE UPPER(name) = 'ALICE')
写多读少时,二级索引数量要克制
每次 INSERT / UPDATE / DELETE,InnoDB 不仅要改主键 B+ 树,还要同步更新所有相关二级索引树。尤其当目标页不在内存中时:
- 普通索引可走
change buffer延迟写入,减少磁盘 IO - 唯一索引不行——必须立刻把页读进内存校验唯一性,否则可能破坏约束
- 所以,高频写入表上堆 5 个以上二级索引,性能下降会非常明显,尤其是高并发
INSERT场景
真正容易被忽略的是:二级索引本身不存数据,但它放大了主键设计的缺陷。比如用 UUID 做主键,每个二级索引叶子节点都要存一个 36 字符的字符串,不仅索引体积暴涨,回表时按随机地址去磁盘捞数据,缓存命中率也极低。这比“少建一个索引”影响更底层。











