MySQL中用户可显式创建的哈希索引仅支持MEMORY引擎,InnoDB等引擎不支持USING HASH语法;其仅适用于等值查询,范围查询、排序等均失效;典型场景为内存中高频小数据量的临时映射表。

哈希索引只在 MEMORY 表上显式可用
MySQL 中能由用户主动创建并控制的哈希索引,仅限于 ENGINE=MEMORY 表。InnoDB 的“自适应哈希索引”是内部机制,SHOW INDEXES 看不到,也不能 CREATE INDEX ... USING HASH,它只是 B+Tree 访问热点的自动加速缓存,不构成独立索引对象。
所以如果你看到文档说“MySQL 支持哈希索引”,实际指的是:只有 MEMORY 引擎允许你写 USING HASH;其他引擎不接受该语法,会报错 ERROR 1064 或 ERROR 1178。
-
CREATETABLE t (id INT, PRIMARY KEY(id) USING HASH) ENGINE=MEMORY;✅ 合法 -
ALTERTABLE t ADD INDEX idx_name (name) USING HASH;✅ 仅当 t 是 MEMORY 表时合法 -
CREATETABLE t_innodb (...) ENGINE=InnoDB; ALTER TABLE t_innodb ADD INDEX ... USING HASH;❌ 报错:Unknown storage engine 'InnoDB' or syntax error
等值查询快,但范围查询直接失效
哈希索引底层是哈希表,查 = 或 IN 时平均时间复杂度 O(1),比 B+Tree 的 O(log n) 更快;但它完全不维护顺序,因此任何涉及大小比较的操作都会跳过索引:
-
WHERE id = 123→ 走哈希索引 ✅ -
WHERE id IN (100, 200, 300)→ 走哈希索引 ✅(多个 hash 查找) -
WHERE id > 100→ 全表扫描 ❌ -
WHERE id BETWEEN 100 AND 200→ 全表扫描 ❌ -
ORDER BY id→ 无法利用索引排序 ❌
执行 EXPLAIN 会发现 type 是 ALL 或 index,而不是 ref / eq_ref,说明没用上哈希索引。
MEMORY 表 + 哈希索引的典型适用场景
结合 MEMORY 引擎“纯内存、无持久化、重启丢数据”的特性,哈希索引只适合那些高频等值查找 + 临时性 + 小数据量的用途:
- 会话 ID 映射表:
session_id VARCHAR(64) PRIMARY KEY USING HASH,用于快速查用户登录状态 - 短链跳转表:
short_code CHAR(6) UNIQUE USING HASH,根据短码查原始 URL - 配置项缓存表:
config_key VARCHAR(50) PRIMARY KEY USING HASH,避免重复读取配置文件 - 中间计算结果暂存:
job_id BIGINT PRIMARY KEY USING HASH,配合定时清理脚本使用
注意:MEMORY 表默认最大大小受 max_heap_table_size 限制(默认 16MB),超限插入会失败;且所有数据常驻内存,不适合存 GB 级数据或长期运行的业务主表。
哈希冲突和负载因子影响实际性能
MEMORY 引擎的哈希索引采用链地址法处理冲突,但它的哈希桶数量是静态分配的,由表定义时的 MAX_ROWS 和 AVG_ROW_LENGTH 推算得出,后续无法调整。如果预估行数严重偏低:
- 桶太少 → 冲突链变长 → 查询退化为链表遍历,O(1) 变成 O(k),k 是平均链长
- 桶太多 → 内存浪费,且可能触发
max_heap_table_size提前告警
建表时建议显式指定:MAX_ROWS=100000 AVG_ROW_LENGTH=100,让 MySQL 算出合理桶数;也可通过 SHOW TABLE STATUS LIKE 't' 查看 Rows 和 Avg_row_length,反推当前负载是否健康。
真正容易被忽略的是:哈希索引对 NULL 值的处理——MEMORY 引擎中,NULL 不参与哈希计算,所有 NULL 值会被归入同一个桶,若字段允许 NULL 且 NULL 值较多,这个桶就会成为性能瓶颈。


















