mysql的哈希索引是基于哈希表实现的索引结构,通过哈希函数将索引键映射到哈希表的对应位置,能够快速定位到数据行,在等值查询场景下性能表现远优于B树索引,不过它不支持范围查询和排序操作。

哈希索引的基本原理
哈希索引的核心逻辑是,当对索引列执行插入、查询操作时,mysql会先对索引键执行哈希函数计算,得到对应的哈希值,再根据哈希值找到哈希表中存储的数据行指针,从而快速定位到目标数据。需要注意的是,不同索引键可能计算出相同的哈希值,这种情况称为哈希冲突,mysql会通过链表的方式存储冲突的索引项。
不同存储引擎下创建哈希索引的方法
Memory存储引擎创建哈希索引
Memory存储引擎默认使用哈希索引,创建表时可以直接指定索引类型为哈希索引,也可以通过后续语句添加哈希索引。
创建表时直接定义哈希索引的示例:
-- 创建memory引擎的表,同时创建哈希索引
CREATE TABLE user_hash (
id INT PRIMARY KEY,
username VARCHAR(50),
INDEX idx_username (username) USING HASH
) ENGINE=MEMORY;
给已存在的Memory表添加哈希索引的示例:
-- 给user_hash表的username列添加哈希索引 ALTER TABLE user_hash ADD INDEX idx_username_hash (username) USING HASH;
InnoDB存储引擎创建哈希索引
InnoDB存储引擎本身不支持用户手动创建哈希索引,但是InnoDB有自适应哈希索引功能,当mysql发现某些索引值被频繁使用等值查询时,会自动在内存中基于B树索引构建哈希索引,提升查询效率。用户可以通过参数开启或关闭这个功能:
-- 查看自适应哈希索引是否开启,ON为开启,OFF为关闭 SHOW VARIABLES LIKE 'innodb_adaptive_hash_index'; -- 开启自适应哈希索引 SET GLOBAL innodb_adaptive_hash_index=ON; -- 关闭自适应哈希索引 SET GLOBAL innodb_adaptive_hash_index=OFF;
如果需要InnoDB表使用哈希索引的效果,也可以通过创建虚拟的哈希列,再给这个哈希列创建B树索引来模拟,示例代码如下:
-- 创建InnoDB表,添加哈希列
CREATE TABLE user_innodb (
id INT PRIMARY KEY,
username VARCHAR(50),
-- 存储username的哈希值,使用CRC32函数计算
username_hash INT GENERATED ALWAYS AS (CRC32(username)) VIRTUAL
);
-- 给哈希列创建B树索引,模拟哈希索引效果
CREATE INDEX idx_username_hash ON user_innodb (username_hash);
查询时同时匹配哈希列和原列,减少哈希冲突的影响:
-- 查询时同时匹配哈希值和原字段,避免哈希冲突导致结果错误
SELECT * FROM user_innodb WHERE username_hash = CRC32('test_user') AND username = 'test_user';
创建哈希索引的注意事项
- 哈希索引仅支持等值查询,不支持
>、<、BETWEEN等范围查询,也不支持ORDER BY排序操作。 - 哈希索引无法利用索引列的前缀匹配,比如对
VARCHAR(100)列创建哈希索引,查询时不能用LIKE 'abc%'的形式使用索引。 - 哈希冲突会影响查询性能,如果索引列的重复值较多,哈希冲突概率高,哈希索引的性能优势会明显下降。
- Memory存储引擎的表数据存储在内存中,重启mysql后数据会丢失,哈希索引也会随之失效,适合存储临时数据。
哈希索引和B树索引的差异对比
| 对比维度 | 哈希索引 | B树索引 |
|---|---|---|
| 适用查询类型 | 仅支持等值查询 | 支持等值查询、范围查询、排序 |
| 查询时间复杂度 | 理想情况O(1),冲突多时接近O(n) | O(log n) |
| 存储引擎支持 | Memory默认支持,InnoDB需模拟 | 主流存储引擎都支持 |
| 是否支持前缀匹配 | 不支持 | 支持 |
总结
如果业务场景以等值查询为主,且数据重复度低,可以选择Memory存储引擎直接创建哈希索引,或者给InnoDB表添加哈希列模拟哈希索引。如果业务包含范围查询、排序等需求,还是优先选择B树索引。开发者需要根据实际业务场景选择合适的索引类型,才能最大化提升数据库查询性能。