MySQL InnoDB&MyISAM 支持Hash么
我们在使用MySQL的时候,关于索引的数据类型,使用的最多的就是HASH和BTREE. 很多开发人员很有经验的会在创建某些字段的索引的时候告诉MySQL的存储引擎:使用HASH !. 我一段时间也是这样胸有成竹的按照这个理论选择索引类型的: 如果是精确的equals比较查询,那么就使用HASH,如果使用范围查询和大小比较查询那么最好使用BTREE.
由于以前的开发经历就是功能开发为主,对具体的细节不是很在意,一般MySQL也能满足需求,所以我天真的以为既然建表语句可以指定HASH而且没有报警告和错误,那么这个索引的底层数据结构肯定是HASH,然后我就放心的使用equals精确查询数据了.直到有一天我看到MySQL的官方文档,才对这个产生深刻的反思.
原文如下:
Most MySQL indexes (PRIMARY KEY, UNIQUE, INDEX, and FULLTEXT) are stored in B-trees. Exceptions: Indexes on spatial data types use R-trees; MEMORY tables also support hash indexes; InnoDB uses inverted lists for FULLTEXT indexes.
什么? 绝大多少MySQL index是BTREE?除了空间位置数据使用了RTREE以及MEMORY TABLE以及使用倒排列表的FULLTEXT indexes?
InnoDB 官方解读
然后我马上检查了InnoDB的文档:
发现InnoDB其实是不支持HASH索引的,但是它可以使用称为Adaptive Hash
的技术来在表象上支持HASH. 这也就是我为什么以前使用InnoDB引擎并指定index类型为HASH的来建表并执行SQL的时候,功能依然看起来正常的本质原因.
MyISAM 官方解读
我继续检查了MyISAM的文档:
那么很遗憾,MyISAM也是不支持Hash的.而且MyISAM也不支持类似InnoDB的Adaptive Hash
的技术来在表象上支持HASH.
所以我们得出结论:
- MyISAM和InnoDB 不支持HASH
- InnoDB可以使用
Adaptive Hash
来间接支持HASH - MEMOEY才能同时支持HASH和BTREE
我们在建表时给某些字段添加hash索引,或者后期为某表添加hash索引时,如果他们的存储引擎为InnoDB或MyISAM,则sql脚本本身是不会报错的,但是我们会发现,该hash索引字段的index_type仍然为BTREE.这其实是MySQL为了照顾使用习惯而做到一些特殊处理,其实底层会忽略你指定索引为HASH的逻辑,依然使用BTREE
实际验证
本次我使用MySQL8作为测试环境,通过实际的代码操作做实际的论证.
InnDB验证
CREATE TABLE index_type_test (
`id` INT NOT NULL AUTO_INCREMENT,
`name` VARCHAR(32) NULL,
PRIMARY KEY (`id`),
UNIQUE INDEX `name_UNIQUE` using hash(name)
) ENGINE = InnoDB;
然后我们查询这个表的索引类型:
mysql> show index from index_type_test;
所以实际测试表明InnoDB会忽略你指定的HASH类型,依然使用BTREE
有关自适应HASH的内容请看: MySQL InnoDB中的Adaptive Hash
MyISAM验证
CREATE TABLE index_type_test (
`id` INT NOT NULL AUTO_INCREMENT,
`name` VARCHAR(32) NULL,
PRIMARY KEY (`id`),
UNIQUE INDEX `name_UNIQUE` using hash(name)
) ENGINE = MyISAM;
然后我们查询这个表的索引类型:
所以实际测试表明MyISAM会忽略你指定的HASH类型,依然使用BTREE.
本文原创链接:
参考链接: