哈希索引是什么
哈希索引用哈希表把键映射到行的位置,等值查找接近常数时间;代价是哈希打乱了键的原有顺序,范围查询、排序、前缀与模糊匹配全部用不上。它只适合「按某个值精确命中」的访问模式,条件一旦变成区间,索引就直接失效、退化成全表扫描。能显式创建哈希索引的引擎并不多。
基本信息
| 支持条件 | 等值比较,包括 = 与 IN 这类等值集合 |
|---|---|
| 不支持 | 范围条件、排序、前缀与模糊匹配、组合键的最左前缀 |
| MySQL | 只有 MEMORY 引擎可显式建哈希索引,InnoDB 无对应语法 |
| InnoDB 自适应哈希 | 引擎按访问模式内部维护,无法手动创建或删除,可用参数开关 |
| PostgreSQL | CREATE INDEX ... USING hash (col),10 起写入 WAL,可持久安全使用 |
支持与不支持
| 查询形式 | 能否使用哈希索引 | 原因 |
|---|---|---|
| col = 常量 | 可用,等值命中效率高 | 哈希值直接定位到桶 |
| col IN (…) | 可用,按等值集合逐项处理 | 可拆成若干次等值比较 |
| col BETWEEN a AND b | 不可用 | 哈希不保序,无法做区间遍历 |
| ORDER BY col | 不可用 | 索引里没有可用的顺序 |
| col LIKE 'pre%' | 不可用 | 前缀匹配依赖有序结构 |
| 多列组合 | 只能整键等值,无最左前缀能力 | 哈希作用于整个键值 |
典型使用场景
- 会话表精确查找:按 session_id、token 逐条命中,从不做范围扫描
- 内存键值结构:MEMORY 表承担临时查找,键唯一且查询形式固定
- 长键等值命中:键变长后 B 树比较代价上升,哈希只比较定长哈希值
- 索引选型验证:对比同一条等值查询在哈希索引与 B 树下的计划差异
- 排查全表扫描:确认语句里是否混入了范围或排序条件让哈希索引失效
- 临时去重结构:会话级中间表做等值探测与去重
两种数据库的写法
两种数据库的写法
-- MySQL:MEMORY 引擎支持显式哈希索引
CREATE TABLE session_kv (
k VARCHAR(64) NOT NULL, # 会话标识,只有等值命中
v VARCHAR(255),
KEY USING HASH (k)
) ENGINE = MEMORY; # 数据全放内存,实例重启即消失
-- PostgreSQL:哈希索引,只支持等值
CREATE INDEX idx_kv_k ON session_kv USING hash (k);
EXPLAIN (ANALYZE) SELECT v FROM session_kv WHERE k = 'abc'; # 计划中应出现哈希索引扫描
EXPLAIN (ANALYZE) SELECT v FROM session_kv WHERE k > 'abc'; # 范围条件用不上哈希索引InnoDB 的自适应哈希索引由引擎按访问模式自动建立,命中情况可在 SHOW ENGINE INNODB STATUS 的哈希索引统计段观察。它在高并发场景下也可能成为闩锁争用来源,怀疑有影响时关闭该特性再压测对比,比凭感觉判断可靠。
选型思路很简单:查询只有等值条件、且键的区分度很高时,哈希索引才有意义;只要查询里存在范围、排序、前缀匹配中的任意一项,就应该用 B 树。多数业务表用 B 树一种索引类型就够了。
MEMORY 引擎的表只把数据放在内存:实例重启后表结构还在,数据全部丢失,只能当可重建的缓存使用。另外单表大小受 max_heap_table_size 限制,超限写入会直接报错。