mysql默认不支持hash索引作为主索引,因innodb和myisam不原生支持;仅memory和ndb引擎支持,但不适合事务型核心表;hash索引不支持范围查询、排序、前缀匹配,且存在哈希冲突风险。

MySQL 默认不支持 Hash 索引作为主索引
因为 InnoDB 和 MyISAM 这两个最常用的存储引擎,压根不原生支持 Hash 索引类型。你执行 CREATE INDEX idx ON t(col) USING HASH,MySQL 不会报错,但 SHOW CREATE TABLE t 里看到的仍是 BTREE —— 实际创建的还是 B+ 树索引。只有 MEMORY 和 NDB 引擎才真正实现 Hash 索引,而它们都不适合做主库或事务型核心表。
Hash 索引无法用于范围查询(、<code>>、BETWEEN)
Hash 索引本质是把键值哈希后映射到固定槽位,哈希值之间没有大小关系。比如 'apple' 和 'banana' 哈希后可能是 1289 和 37,完全无法推断原始字符串顺序。所以当你写 WHERE id > 100 或 WHERE created_at BETWEEN '2025-01-01' AND '2025-12-31',Hash 索引直接失效,只能全表扫描。
- 哪怕你建了
(a,b,c)的复合 Hash 索引,只要查询中出现a > 1,后续b和c就全用不上 -
ORDER BY a也绕不开:Hash 索引不保序,数据库没法跳过排序阶段 - 连
LIKE 'abc%'这种前缀匹配都做不到——Hash 是对完整值计算,切不出“前缀”
B+ 树天然支持范围与排序,且兼顾等值查询
InnoDB 用 B+ 树做聚簇索引,所有数据行按主键物理排序存储在叶子节点,叶子节点还用双向链表连起来。这就意味着:
- 等值查询:从根节点逐层向下查,最多树高次 I/O(通常 3–4 层),和 Hash 的 O(1) 理论差距不大,实际差别常被缓存掩盖
- 范围查询:定位到起始键后,顺着叶子链表往后读,连续 I/O 效率极高
- 排序:如果
ORDER BY字段是索引最左前缀,直接按叶子节点顺序返回,免排序 - 覆盖索引:只查索引列时,根本不用回表,B+ 树节点里就存着这些值
相比之下,Hash 索引除了单点等值极快,其他场景全是硬伤,没法当通用索引用。
自定义伪 Hash 索引要自己兜底冲突和维护
真想用 Hash 加速等值查询(比如超长 URL 查找),得手动加一列 url_hash,再给它建 B+ 树索引。但必须注意:
- 查询时不能只靠
WHERE url_hash = CRC32('xxx'),必须补上AND url = 'xxx'防止哈希冲突误判 - CRC32 返回 32 位整数,碰撞概率随数据量上升明显;用
SHA2(url, 224)太长,B+ 树索引效率反而下降 - 每次
INSERT/UPDATE url,都要同步更新url_hash,应用或触发器得写牢,漏一次就查不到 - 这个方案本质还是 B+ 树在干活,Hash 只是辅助过滤——别误以为“用了 Hash 就变快了”
真正容易被忽略的点是:Hash 冲突不是小概率事件,而是随数据规模指数级增长的确定性问题;一旦线上查出脏数据或漏数据,排查成本远高于一开始选对 B+ 树索引。











