mysql主键索引必须是b+树而非哈希,因innodb要求主键有序以支持范围查询、order by及最左匹配,且依赖主键顺序组织数据页;哈希仅支持等值查询且无序,innodb中指定hash会静默转为b+树。

为什么 MySQL 的主键索引一定是 B+ 树,而不是哈希?
因为 InnoDB 存储引擎强制要求主键索引(聚簇索引)必须是有序结构,而 B+ 树天然支持范围查询、ORDER BY 和联合索引的最左匹配;哈希索引只支持等值查询,且无法保证数据物理顺序——InnoDB 依赖主键顺序组织磁盘页和行记录,哈希做不到这点。
常见错误现象:CREATE TABLE t (id INT, KEY USING HASH(id)); 在 InnoDB 中会静默转为 B+ 树,只有 MEMORY 引擎才真正支持哈希索引。
- InnoDB 不接受
USING HASH指定主键或普通索引 - 哈希索引仅适用于 MEMORY 表,且无法使用
ORDER BY、>、BETWEEN等操作 - B+ 树的叶子节点形成双向链表,这是范围扫描和排序能力的物理基础
覆盖索引到底“覆盖”了什么?
覆盖索引不是一种独立索引类型,而是指一个索引包含了查询所需的所有字段(包括 SELECT 列和 WHERE 条件列),从而避免回表——即不需要再根据主键去聚簇索引中二次查找整行数据。
典型场景:SELECT user_id, status FROM orders WHERE user_id = 123 AND status = 'paid'; 如果存在联合索引 INDEX idx_user_status (user_id, status),这个查询就完全走索引,不访问聚簇索引。
- 注意:
SELECT *几乎不可能被覆盖,除非你建了一个包含所有列的索引(不现实且低效) - 如果 WHERE 中用了
status,但索引是(user_id)单列,那status还得回表读取,不算覆盖 - EXPLAIN 结果中
Extra字段出现Using index才表示命中覆盖索引
什么时候该用哈希索引?
只在明确知道查询模式全是等值、且表极小、并发低、不需排序/分页时,才考虑 MEMORY 引擎 + 哈希索引。现实中极少用到。
例如缓存类临时表:CREATE TABLE cache_map (k VARCHAR(32), v TEXT, PRIMARY KEY(k)) ENGINE=MEMORY; 默认就是哈希主键,查 SELECT v FROM cache_map WHERE k = 'token_abc'; 极快。
- 哈希冲突会导致链表退化,大量重复 key 会让性能骤降
- 哈希索引不支持
LIKE 'abc%'或IS NULL查询 - MySQL 8.0+ 的自适应哈希索引(AHI)是 InnoDB 自动构建的,用户不可控,也不建议关闭
B+ 树索引的“最左前缀”到底怎么失效?
失效不是指索引不用,而是指从某个字段开始,后续字段无法用于索引查找(但仍可能参与过滤或覆盖)。
比如索引 INDEX idx_a_b_c (a, b, c):
-
WHERE a = 1 AND b > 10 AND c = 5→a和b可用于查找,c只能过滤(range 后的等值不走索引查找) -
WHERE b = 2→ 整个索引无法用于查找,只能全索引扫描(index scan) -
WHERE a = 1 AND c = 5→a可用,c被跳过,无法利用索引快速定位c值
容易忽略的一点:如果 WHERE 中有函数或表达式作用于索引列(如 WHERE YEAR(create_time) = 2024),哪怕是最左列也会导致索引失效——B+ 树存的是原始值,不是计算结果。










