MEMORY引擎的HASH索引仅支持单列完整值等值匹配,不支持范围查询、LIKE、ORDER BY及复合索引;AHI是InnoDB自动构建的内存哈希优化,不可手动控制,仅加速高频等值访问的二级索引。

Memory引擎的HASH索引只能建在单列上,且该列必须是完整值匹配
MySQL MEMORY 引擎支持 HASH 和 BTREE 两种索引类型,但 HASH 索引只适用于等值查询(= 或 ),不支持范围、前缀、LIKE 或 ORDER BY。它底层用哈希表实现,查找是 O(1),但前提是:你查的必须是整列的完整值。
常见错误现象:SELECT * FROM t WHERE col LIKE 'abc%' 即使 col 上建了 HASH 索引也完全用不上;WHERE col > 100 同样失效;复合索引如 (a,b) 无法建 HASH 类型——MEMORY 不允许。
- 建表时显式指定:
CREATE TABLE t (id INT, name VARCHAR(32), INDEX USING HASH(name)) ENGINE=MEMORY; - 如果列有
NULL,HASH索引仍可用,但所有NULL会被映射到同一个哈希桶,可能引发冲突和性能抖动 - 字符串列建议用固定长度(
CHAR)或短变长(VARCHAR(32)),过长的VARCHAR会增加哈希计算开销和桶冲突概率
自适应哈希索引AHI是InnoDB自动行为,不能开关,也不能指定字段
AHI(Adaptive Hash Index)是 InnoDB 在运行时根据访问模式“偷偷”构建的内存哈希索引,只为加速重复出现的等值查询。它不是你 CREATE 出来的,也不出现在 SHOW CREATE TABLE 里,更不能用 ALTER TABLE 开关——innodb_adaptive_hash_index 这个配置项只控制是否启用整个 AHI 机制,不提供字段级控制。
使用场景有限:只有当某二级索引页被频繁以相同方式访问(比如反复查 idx_name 上的 name = 'tom'),且满足“连续访问同一索引页 + 相同搜索条件”的模式,InnoDB 才可能为这个组合生成哈希条目。
- AHI 只基于现有二级索引构建,不会为没有索引的列生成哈希加速
- 哈希键是“索引字段值 + 索引页地址”,所以它本质上是对索引的缓存优化,不是独立索引结构
- 高并发写入时,AHI 的维护锁(
hash_lock)可能成为争用点,SHOW ENGINE INNODB STATUS里看到大量hash_lock等待就是信号
Hash索引 vs AHI:一个是你手动选的存储结构,一个是InnoDB动态加的加速补丁
别把 MEMORY 的 HASH 索引和 InnoDB 的 AHI 混成一类东西。前者是表定义的一部分,决定数据怎么存、怎么查;后者是纯内存里的运行时优化,随时可被驱逐,重启即消失,且只对特定访问模式生效。
性能影响差异明显:MEMORY + HASH 查等值极快,但不支持任何非等值操作,且数据全在内存,断电就丢;AHI 对查询是“锦上添花”,没它也能跑,有它可能快一倍,但不会改变语义或执行计划是否走索引。
- 看执行计划时,
type: ref或eq_ref表示走了二级索引,AHI 是否起效你看不到——它发生在索引查找之后的内存层 -
MEMORY表的HASH索引会在EXPLAIN中显示type: const或eq_ref(如果是主键或唯一键),但这是因为它直接定位到行,不是因为用了哈希 - 想确认 AHI 是否活跃?查
SHOW ENGINE INNODB STATUS,在INSERT BUFFER AND ADAPTIVE HASH INDEX段看Hash table size和used cells
什么时候真该用HASH索引?别为了“哈希”而哈希
除非你明确需要毫秒级等值响应、数据量不大、能接受不支持范围查询、且业务天然适合内存表(比如会话缓存、临时聚合中间表),否则别硬上 MEMORY + HASH。多数人其实是想加速查询,结果掉进“以为建了 HASH 就万能”的坑里。
容易踩的坑:把大文本列(VARCHAR(500))、JSON 字段、或者经常要 GROUP BY/ORDER BY 的列配 HASH 索引,最后发现除了浪费内存,啥也没换来。
- 优先考虑
BTREE:它兼容所有查询类型,现代 SSD 下范围扫描也不慢 - 如果真要哈希语义,应用层自己做(比如 Redis 缓存 key → id 映射),比依赖
MEMORY表更可控 - InnoDB 表想加速等值?先确保二级索引存在、选择性够高,AHI 会自己跟上——你不用做任何事
AHI 的触发逻辑藏得深,HASH 索引的限制又很死,这两者都不是调优第一选项。真正该花时间的,是看慢查日志里到底卡在哪——90% 的时候,问题出在没索引、索引没覆盖、或者统计信息过期,而不是哈希不够快。










