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

作者:该用户快成仙了 时间:2024-01-21 17:23:55 

除了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" 是为了防止哈希碰撞时数据不准确。

来源:https://blog.csdn.net/weixin_60707895/article/details/121014425

标签:MySQL,设置Hash索引,面试题
0
投稿

猜你喜欢

  • css中absolute与relative的区别

    2007-11-17 08:04:00
  • python实现简单的超市商品销售管理系统

    2021-08-24 00:07:32
  • Python画图工具Matplotlib库常用命令简述

    2021-10-11 07:28:07
  • 从mysql读写分离着手提升服务器性能

    2024-01-22 06:56:10
  • python beautifulsoup4 模块详情

    2021-12-30 07:50:03
  • python re模块匹配贪婪和非贪婪模式详解

    2023-04-19 01:44:16
  • python求质数的3种方法

    2023-02-12 04:07:54
  • 公网远程访问局域网SQL Server数据库

    2024-01-22 01:38:21
  • JavaScript中你不知道的Object.entries用法

    2024-04-19 11:01:40
  • 微信昵称带符号导致插入MySQL数据库时出错的解决方案

    2024-01-20 23:40:20
  • WIn10+Anaconda环境下安装PyTorch(避坑指南)

    2023-06-20 03:24:04
  • python排序算法之选择排序

    2023-03-15 11:56:56
  • 当设计师遇上前端开发

    2009-05-04 14:05:00
  • Mysql使用存储过程快速添加百万数据的示例代码

    2024-01-19 21:51:26
  • 请问能否在ASP中调用DLL

    2009-06-07 18:24:00
  • 单页面vue引入百度统计的使用方法示例详解

    2024-05-11 09:14:23
  • 不同分辨率下的自适用宽度

    2008-11-24 12:58:00
  • Facebook:产品设计评价体系解密

    2011-05-24 17:13:00
  • python 安装教程之Pycharm安装及配置字体主题,换行,自动更新

    2021-01-02 06:34:20
  • SQL Server 数据库基础编程详解

    2024-01-17 03:29:37
  • asp之家 网络编程 m.aspxhome.com