为什么 MySQL 的 InnoDB 默认用 B+ 树,而不是哈希索引?
因为
InnoDB存储引擎本身不支持显式创建哈希索引(
HASH索引),它只支持
B+ 树索引。你执行
CREATE INDEX ... USING HASH会报错;只有
MEMORY引擎才原生支持哈希索引。InnoDB 内部确实有自适应哈希索引(
adaptive hash index),但它完全由引擎自动管理,不可配置、不可干预,仅对“热点”的
B+ 树查找路径做缓存加速,不是用户可定义的索引类型。
B+ 树索引能做什么,哈希索引做不到?
B+ 树支持范围查询、排序、最左前缀匹配、部分列匹配(如联合索引前缀);
HASH索引只支持等值查询(
=或
IN),且必须提供**全部索引列**才能命中——哪怕你建的是
(a, b)联合哈希索引,查
WHERE a = 1也用不上。
B+ 树:支持
WHERE age > 25、
ORDER BY created_at、
WHERE user_id = 123 AND status = 'active'(联合索引前缀匹配)
HASH:只响应
WHERE id = 1001这类完整键等值查找;
WHERE id IN (1001, 1002, 1003)可能走,但效率未必优于 B+ 树
HASH不存储有序数据,无法用于
MIN()/
MAX()优化或索引覆盖排序
哈希索引真比 B+ 树快吗?
单次等值查询理论上是 O(1),但实际受制于哈希冲突、内存分布和引擎实现。在
MEMORY表中,哈希索引确实比 B+ 树快——前提是数据量不大、无严重哈希碰撞、且查询模式高度集中于等值。但一旦出现哈希桶溢出(overflow chain),性能会急剧下降;而
B+ 树的磁盘 I/O 和缓存友好性更可控,尤其在大数据量、混合查询(等值 + 范围)场景下优势明显。
MEMORY引擎的哈希索引要求所有查询列都参与哈希计算,不支持
NULL值作为索引列
B+ 树在
InnoDB中天然支持聚簇索引(主键即数据存储顺序),减少回表;哈希索引只能是非聚簇的,必然要回查数据行 哈希索引无法利用
key_len判断实际匹配长度,执行计划中常显示为
ALL或不准,调试困难
什么时候该考虑哈希索引?
几乎只有一种现实场景:
MEMORY表 + 极高并发、纯等值查询、数据量稳定且可预估(避免哈希桶分裂)、对延迟极度敏感(微秒级)。例如缓存用户 session ID 到 user_id 的映射表:
CREATE TABLE session_lookup ( session_id CHAR(32) NOT NULL, user_id INT NOT NULL, PRIMARY KEY (session_id) ) ENGINE=MEMORY DEFAULT CHARSET=utf8mb4 AVG_ROW_LENGTH=64 MAX_ROWS=1000000;
此时你可以显式指定哈希索引:
CREATE INDEX idx_session_hash ON session_lookup (session_id) USING HASH;别在
InnoDB表上尝试
USING HASH—— 语法报错:
ERROR 1064 (42000): Syntax error不要指望哈希索引解决慢查询:如果
EXPLAIN显示没走索引,换哈希索引大概率也没用,先检查是否满足等值、是否含
NULL、是否用了函数包裹列(如
WHERE MD5(id) = ?) 哈希索引不支持
LIKE 'abc%',也不支持索引下推(ICP),这些都得靠 B+ 树
真正需要纠结选型的地方,往往不是“B+ 树 vs 哈希”,而是“要不要加索引”“索引列顺序怎么排”“是否该用覆盖索引”——这些才是日常调优里更常踩坑的位置。
