看到红薯帖了个4中HASHMAP的方法。我也参乎一下,发表下我对HASH的看法。
HASH表,维基上有很好的说明。英文中文都有。中文已经说的不错了。我就不重复了。简单说说我的理解。
HASH表有很多用途,比如加密等。但也有个重要用途是在查表。例如曾经听说魔兽游戏里,有些数据就是用HASH表来查找的。
本质上说。HASH就是映射。那么为什么要映射,是因为传统的比较法查找,较慢所导致的。为什么会较慢,因为比较的信息量和带比较的对象的数量并不对等。简单举例:
我们的身份证有18位,假设都是0到9.那么这等于有10^18的数量。而总人口只有10个亿的规模,也就是10^9的规模。如果我们一一去查18 位,显然有很多信息冗余的地方。如果我们能做个表,根据18位的数字串,直接查到一个索引(当然这个索引表也有10的9次方的规模),然后根据这个索引作 为数据库存储的位置(或简单点说数组的偏移量),就会更快些。
另一个例子,如果年级里,总共就256个人。假设人名不同,理想的构造一个HASH映射表。就一个8bit数即可有效的区别每个不同的人的信息存放 位置。无论你的姓名如何,通过这个表,就可以直接获得一个索引,而且值就是在 0到 255(包含)之间。这显然比按照姓名一个字一个字的比较,再获取索引要快。因为最快的比较也要 log2N次,且不谈每次还要比较字符串。
以上是正面说。下面是反着说:
1、假设我们要查找的数据 空间是N,但是确实已经存在了N个数据,或接近。此时查HASH表已经没有意义了。例如如果身份证 ,18位,任意一个具体数值都对应一个确定存在的人。那么我们只要将数据库每个人的信息,按照身份证的号码存储好。这个身份证本身就是数组的下标。查表只 是画蛇添足。当然这种情况发生概率比较小。
2、除非我们能够知道HASH映射的所有输入数据和从数据量,否则我们连构造理想HASH的机会都没有。就是说。理论上,如果输入数据的空间大于输 出数据的空间(如果固定)则一定会有碰撞。这其实也是废话。因为不可能一一对应。必然出现 多个不同的输入数据,经过hash表的一次迭代算出来相同值。
因此,从上面的分析,可以看出。HASH表在数据库中利用时,有效的使用环境是,实际存储的内容和理论支持存储的内容的数量存在巨大差异的场合。例 如,你有个1Tbytes的硬盘。假设每个文件至少4Kbytes。则理论上,你可以在上面存放256M个文件。但通常很多文件远大于4Kbytes。也 就是说实际真正现实存储,很难发生256M个文件。甚至可能只有不到1M的文件数量。
那么此时,你将路径映射到一个较小的索引表中,该索引表只有1M的数据,当你小于1M的文件时,理论上,用HASH的映射函数,和这个表就可以两步法找到这个文件。而不是一个路径一个路径的查找比较。
这里说的是文件,实际就是在等同数据库里的数据。
最后想说明以下几点:
1、理论值和现实状态差距很大。工程和理论的最大区别,就我的观点,在于概率和误差。好的工程设计,在于大概率下的性能的提升。而不是做个统计,兼 顾了各种情况的平均性能。因此,虽然有些东西。例如上面的举例,理论上,增加HASH并不能保证所有情况下的性能提升。但是大概率的情况下,确实可以提 升,这就是好的产品。
2、HASH表的性能和系统规模有关系。当系统规模小时,较大的输出表并不有效,系统规模大时,早期有效的表,因为碰撞概率的迅速增加,会拖累系 统。因此,要么动态的重新规划HASH表,这个动静很大,一般除非系统升级才会折腾。要么,考虑分层或分布的计算实现,这是通常的做法。
额外喷一句:说道系统可扩建的重构,有些人,看mysql这个不顺眼,那个不顺眼。但mysql相对短小精干,而且开源,在后期分布集群的发展方向 不可小视。反观orcale和 sql server 却未必灵活。我相信后两者公司的技术人员的牛度,但我很难相信他们会为中国的公司,低价的服务。