前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >在MySQL中建立自己的哈希索引(书摘备查)

在MySQL中建立自己的哈希索引(书摘备查)

作者头像
用户1148526
发布2019-05-25 19:41:38
2.2K0
发布2019-05-25 19:41:38
举报
文章被收录于专栏:Hadoop数据仓库

在MySQL中,只有Memory存储引擎支持显式的哈希索引,但是可以按照InnoDB使用的方式模拟自己的哈希索引。这会让你得到某些哈希索引的特性,例如很大的键也只有很小的索引。 想法非常简单:在标准B-Tree索引上创建一个伪哈希索引。它和真正的哈希索引不是一回事,因为它还是使用B-Tree索引进行查找。然而,它将会使用键的哈希值进行查找,而不是键自身。你所要做的事情就是在where子句中手动地定义哈希函数。 一个不错的例子就是URL查找。URL通常会导至B-Tree索引变大,因为它们非常长。通常会按照下面的方式来查找URL表:

代码语言:javascript
复制
select id from url where url='http://www.mysql.com';

但是,如果移除url列上的索引并给表添加一个被索引的url_crc列,就可以按照下面的方式进行查询:

代码语言:javascript
复制
select id from url where url='http://www.mysql.com' and url_crc=crc32('http://www.mysql.com');

这种方式很不错,因为MysSQL查询优化器注意到url_crc列上有很小的、选择性很高的索引,并且它会使用里面的值进行索引查找。即使有几行相同的url_crc值,也很容易进行精确地对比来确定需要的行。替代方案是把完整的URL索引为字符串,它要慢得多。 这个办法的一个缺点是要维护哈希值。你可以手工进行维护,在MySQL 5.0及以上版本中,可以使用触发器来进行维护。下面的例子显示了触发器如何在插入和更新值的时候维护url_crc列。首先,创建一个表:

代码语言:javascript
复制
create table pseudohash (
    id int unsigned not null auto_increment,
    url varchar(255) not null,
    url_crc int unsigned not null default 0,
    primary key (id),
    key (url_crc)
);

接下来创建触发器:

代码语言:javascript
复制
delimiter |

create trigger pseudohash_crc_ins before insert on pseudohash
for each row begin
    set new.url_crc=crc32(new.url);
end;
|

create trigger pseudohash_crc_upd before update on pseudohash
for each row begin
    set new.url_crc=crc32(new.url);
end;
|

delimiter ;

剩下的工作就是验证触发器自动维护了哈希值:

代码语言:javascript
复制
insert into pseudohash (url) values ('http://www.mysql.com');
select * from pseudohash;

update pseudohash set url='http://www.,ysql.com/' where id=1;
select * from pseudohash;

使用这种方式,就不应该使用sha1()和md5()这些哈希函数。它们返回很长的字符串,会浪费大量的存储空间并且减慢比较速度。它们是强加密函数,被设计为不产生任何冲突。这并不是我们的目标。简单的哈希函数能在有较好性能的同时保证可接受的冲突率。 如果表有很多行并且crc32()产生了很多冲突,就要实现自己的64位哈希函数。要确保自己的函数返回整数,而不是字符串。一种实现64位哈希函数的方法是利用MD5返回的部分值:

代码语言:javascript
复制
select conv(right(md5('http://www.mysql.com/'),16),16,10) as hash64;

处理哈希碰撞 当通过哈希值搜索值的时候,必须在where子句中包含一个常量值(literal value):

代码语言:javascript
复制
select id from url where url_crc=crc32('http://www.mysql.com') and url='http://www.mysql.com';

下面的查询不能正常工作,因为可能返回多行:

代码语言:javascript
复制
select id from url where url_crc=crc32('http://www.mysql.com');

哈希碰撞几率的增长比想象的要快。crc32()返回一个32位的整数值,因此至少需要93000个值才会出现碰撞(k*(k-1)/2n=1,其中n=2^32,则k=92682)。 为了避免碰撞问题,必须在where子句中定义两个条件。如果碰撞不是问题,不如进行统计并且不需要精确的结果,就可以通过在where子句中使用crc32()值简化查询,并得到效率提升。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2016年12月28日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
云数据库 SQL Server
腾讯云数据库 SQL Server (TencentDB for SQL Server)是业界最常用的商用数据库之一,对基于 Windows 架构的应用程序具有完美的支持。TencentDB for SQL Server 拥有微软正版授权,可持续为用户提供最新的功能,避免未授权使用软件的风险。具有即开即用、稳定可靠、安全运行、弹性扩缩等特点。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档