MySQL面试题讲解之如何设置Hash索引


Posted in MySQL onNovember 01, 2021

除了B-Tree 索引,MySQL还提供了如下索引:

  • Hash索引

只有Memory引擎支持,场景简单

  • R-Tree索引

MyISAM的一个特殊索引类型,主要用于地理空间数据类型

  • Full-text

MyISAM的一个特殊索引,主要用于全文索引,从MySQL 5.6开始InnoDB支持全文索引

索引 / 存储引擎MyISAMInnoDBMemoryB-Tree索引支持支持支持HASH索引不支持不支持支持R-Tree索引支持支持不支持Full-text索引支持支持不支持

最常用的索引也就是B-tree索引和Hash索引,且只有Memory, NDB两种引擎支持Hash索引。 Hash索引适于key-value查询,通过Hash索引比B-tree索引查询更加迅速。但Hash索引不支持范围查找例如<><==,>==等。 Memory只有在"="的条件下才会使用hash索引

MySQL在 8.0才支持函数索引,在此之前只能对列的前面某一部分进行索引,例如标题title字段,可以只取title的前10个字符索引,这样的特性大大缩小了索引文件的大小,但前缀索引也有缺点,在order by和group by操作时失效。

create index idx_title on film(title(10));

1 特点

只存在数组,用一个hash函数把key转换成一个确定的内存位置,然后把value放在数组的该位置。使用 hash 自然会有哈希冲突可能,MySQL 采取拉链法解决。

Hash索引基于Hash表实现,只有查询条件精确匹配Hash索引中的列时,才能够使用到hash索引。对于Hash索引中的所有列,存储引擎会为每行计算一个hashcode,Hash索引中存储的就是hashcode。

  • 例如一个维护了身份证号和姓名的表,根据身份证号查找对应名字,其hash索引如下:

MySQL面试题讲解之如何设置Hash索引

比如我们想查ID_card_n4对应username:

  • 将ID_card_n4通过hash函数算出A
  • 按顺序遍历,找到User4

四个ID_card_n值并不一定递增,这样即使增加新的User,速度也快,只需在后追加。 当然缺点也很明显,不是有序,所以hash索引做区间查询速度很慢。比如要找身份证号在[ID_card_X, ID_card_Y]区间的所有用户,就须全表扫描。

2 Hash索引的缺陷

  • 必须二次查找
  • 不支持部分索引查找、范围查找
  • 哈希码可能存在哈希冲突,如果hash 算法设计不好,碰撞过多,性能也会变差
  • 索引存放的是hash值,所以仅支持 < = > 以及 IN
  • 无法通过操作索引来排序,因为存放的时候会经过hash计算,但是计算的hash值和存放的不一定相等,所以无法排序
  • 不能避免全表扫描,只是由于在memory表里支持非唯一值hash索引,即不同的索引键,可能存在相同hash值
  • 因为哈希表是一种根据关键字直接访问内存存储位置的数据结构 ,所以利用其原理的hash 索引,也就需要将所有数据文件添加到内存,这就很耗内存
  • 如果所有的查询都是等值查询,那么hash确实快,但实际上范围查找数据更多
  • 智能处理键值得全值匹配
  • 查询Hash函数决定着索引键的大小

要使InnoDB或MyISAM支持哈希索引,可以通过伪哈希索引来实现,叫自适应哈希索引。

可通过增加一个字段,存储hash值,将hash值建立索引,在插入和更新的时候,建立触发器,自动添加计算后的hash到表里。

哈希表这种结构适用于只有等值查询的场景,比如Memcached。

3 案例应用

假如有一个非常非常大的表,比如用户登录时需要通过email检索出用户,如果直接在email列建索引,除了索引区间匹配,还要进行字符串匹配比对,email短还好,如果长的话这个查询代价就比较大。 若此时,在email建立哈希索引,查询以int查询,性能就比字符串比对查询快多了。

Hash 算法

建立哈希索引,首先就要选定哈希算法,《高性能MySQL》说到的CRC32算法。

INSERT UPDATE SELECT 操作

在表中添加hash值的字段:

ALTER TABLE `User` ADD COLUMN email_hash int unsigned NOT NULL DEFAULT 0;

接下来就是在UPDATE和INSERT时,自动更新 email_hash 字段,通过触发器实现:

DELIMITER |
CREATE TRIGGER user_hash_insert BEFORE INSERT ON `User` FOR EACH ROW BEGIN
SET NEW.email_hash=crc32(NEW.email);
END;
|
CREATE TRIGGER user_hash_update BEFORE UPDATE ON `User` FOR EACH ROW BEGIN
SET NEW.email_hash=crc32(NEW.email);
END;
|
DELIMITER ;

这样SELECT请求就会变成:

SELECT `email`, `email_hash` FROM `User` WHERE 
	email_hash = CRC32(“xxoo@gmail.com”) 
			AND `email`= “xxoo@gmail.com”;

+----------------------------+------------+
| email                    |  email_hash  |
+----------------------------+------------+
| xxoo@gmail.com | 2765311122 |
+----------------------------+------------+

AND email = "xxoo@gmail.com" 是为了防止哈希碰撞时数据不准确。

到此这篇关于MySQL面试题讲解之如何设置Hash索引的文章就介绍到这了,更多相关MySQL 设置Hash索引内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!


Tags in this post...

MySQL 相关文章推荐
MySQL表的增删改查基础教程
Apr 07 MySQL
详解MySQL主从复制及读写分离
May 07 MySQL
如何用Navicat操作MySQL
May 12 MySQL
MySQL中使用or、in与union all在查询命令下的效率对比
May 26 MySQL
MySQL如何使用使用Xtrabackup进行备份和恢复
Jun 21 MySQL
MySQL系列之十五 MySQL常用配置和性能压力测试
Jul 02 MySQL
MySQL 四种连接和多表查询详解
Jul 16 MySQL
mysql分组后合并显示一个字段的多条数据方式
Jan 22 MySQL
MySQL的存储函数与存储过程的区别解析
Apr 08 MySQL
mysql如何查询连续记录
May 11 MySQL
MySQL解决Navicat设置默认字符串时的报错问题
Jun 16 MySQL
SQL语句中EXISTS的详细用法大全
Jun 25 MySQL
MySQL对数据表已有表进行分区表的实现
Nov 01 #MySQL
mysql分表之后如何平滑上线详解
Nov 01 #MySQL
MySQL8.0升级的踩坑历险记
Nov 01 #MySQL
详细聊聊关于Mysql联合查询的那些事儿
Oct 24 #MySQL
mysql事务对效率的影响分析总结
Oct 24 #MySQL
mysql事务隔离级别详情
mysql主从复制的实现步骤
You might like
用PHP+java实现自动新闻滚动窗口
2006/10/09 PHP
PHP调用MsSQL Server 2012存储过程获取多结果集(包含output参数)的详解
2013/07/03 PHP
php 判断网页是否是utf8编码的方法
2014/06/06 PHP
php过滤html标记属性类用法实例
2014/09/23 PHP
PHP中array_slice函数用法实例详解
2014/11/25 PHP
利用PHP获取访客IP、地区位置、浏览器及来源页面等信息
2017/06/27 PHP
jQuery 中关于CSS操作部分使用说明
2007/06/10 Javascript
url参数中有+、空格、=、%、&amp;、#等特殊符号的问题解决
2013/05/15 Javascript
JS中完美兼容各大浏览器的scrolltop方法
2015/04/17 Javascript
深入浅析JavaScript中的3DES
2016/08/24 Javascript
JavaScript使用正则表达式获取全部分组内容的方法示例
2017/01/17 Javascript
Angular2实现自定义双向绑定属性
2017/03/22 Javascript
使用react-router4.0实现重定向和404功能的方法
2017/08/28 Javascript
js实现跟随鼠标移动的小球
2019/08/26 Javascript
JS原型对象操作实例分析
2020/06/06 Javascript
浅析 Vue 3.0 的组装式 API(一)
2020/08/31 Javascript
[40:04]Secret vs Infamous 2019国际邀请赛淘汰赛 败者组 BO3 第二场 8.23
2019/09/05 DOTA
使用Python内置的模块与函数进行不同进制的数的转换
2016/03/12 Python
python利用matplotlib库绘制饼图的方法示例
2016/12/18 Python
Python内置函数reversed()用法分析
2018/03/20 Python
利用Pandas读取文件路径或文件名称包含中文的csv文件方法
2018/07/04 Python
利用Python将每日一句定时推送至微信的实现方法
2018/08/13 Python
Python文件循环写入行时防止覆盖的解决方法
2018/11/09 Python
python爬虫利器之requests库的用法(超全面的爬取网页案例)
2020/12/17 Python
Numpy中的数组搜索中np.where方法详细介绍
2021/01/08 Python
介绍一下Java中标识符的命名规则
2014/02/03 面试题
解释下列WebService名词:WSDL、SOAP、UDDI
2012/06/22 面试题
实习医生自我评价
2013/09/22 职场文书
历史学专业推荐信
2013/11/06 职场文书
市场营销管理制度
2014/01/29 职场文书
优秀党务工作者先进事迹材料
2014/12/25 职场文书
我是特种兵观后感
2015/06/11 职场文书
2016幼儿园毕业感言
2015/12/08 职场文书
一小时迅速入门Mybatis之bind与多数据源支持 Java API
2021/09/15 Javascript
Go语言读取txt文档的操作方法
2022/01/22 Golang
java获取一个文本文件的编码(格式)信息
2022/09/23 Java/Android