我正在读一篇关于哈希索引的文章,似乎它类似于PHP的md5
函数,因为它们都接受一个字符串值并返回一个表示该字符串的整数,这个表示形式是是一致的。这种相似性真的存在吗,还是我错过了什么?还有谁知道MySQL采用基于散列的索引结构的散列算法?
答案 0 :(得分:2)
我不是假装对MySQL算法做出完整的描述,但有一些事情可能会被猜到。
首先,Hash table wiki是必读的。然后我们收到MySQL documentation的通知:
- 它们仅用于使用=或< =>的等式比较。运营商(但速度很快)。它们不用于比较
运营商如<找到一系列的价值观。依赖的系统 这种类型的单值查找称为“键值存储”;到
将MySQL用于此类应用程序,尽可能使用哈希索引。- 优化器无法使用哈希索引来加速ORDER BY操作。 (此类索引不能用于搜索下一个 按顺序进入。)
- MySQL无法确定两个值之间大约有多少行(范围优化器使用它来决定) 使用哪个索引)。如果您更改a,这可能会影响某些查询 MyISAM表到哈希索引的MEMORY表。
- 只有整个键可用于搜索行。 (使用B树索引,密钥的任何最左前缀都可用于查找行。)
这指向以下(相当常见)属性:
MySQL哈希函数在固定长度的“全键”记录上运行(它 但问题是如何处理varchars,例如它们可能用零填充到最大长度)
在猜测哈希函数的上行数时,引擎可能会使用max_heap_table_size
个全局值和MAX_ROWS
参数。
MySQL allows非唯一键,但警告比例减速。至少这可能告诉我们没有第二个哈希函数,而只是一个在冲突解决中使用的链表。
至于所使用的实际功能,我认为没什么可说的。 MySQL甚至可以根据一些关键启发法使用不同的函数(例如,一个用于主要是顺序数据,例如ID,而另一个用于CHAR),当然其输出根据估计的行数而改变。但是,当BTREE无法为您提供足够好的性能或者您从未使用过任何优势时,您应该只考虑哈希索引,我认为这是一种罕见的情况。
<强>更新强>
进入源代码:/storage/heap/hp_hash.c
包含一些哈希函数的实现。至少它是一个正确的假设,他们对不同类型使用不同的技术,因为它涉及TEXT和VARCHAR:
/*
* Fowler/Noll/Vo hash
*
* The basis of the hash algorithm was taken from an idea sent by email to the
* IEEE Posix P1003.2 mailing list from Phong Vo (kpv@research.att.com) and
* Glenn Fowler (gsf@research.att.com). Landon Curt Noll (chongo@toad.com)
* later improved on their algorithm.
*
* The magic is in the interesting relationship between the special prime
* 16777619 (2^24 + 403) and 2^32 and 2^8.
*
* This hash produces the fewest collisions of any function that we've seen so
* far, and works well on both numbers and strings.
*/
我会试着给出一个简单的解释。
ulong nr= 1, nr2= 4;
for (seg=keydef->seg,endseg=seg+keydef->keysegs ; seg < endseg ; seg++)
单独处理复合密钥的每个部分,结果累积在nr
。
if (seg->null_bit)
{
if (rec[seg->null_pos] & seg->null_bit)
{
nr^= (nr << 1) | 1;
continue;
}
}
单独处理NULL值。
if (seg->type == HA_KEYTYPE_TEXT)
{
uint char_length= seg->length; /* TODO: fix to use my_charpos() */
seg->charset->coll->hash_sort(seg->charset, pos, char_length,
&nr, &nr2);
}
else if (seg->type == HA_KEYTYPE_VARTEXT1) /* Any VARCHAR segments */
{
uint pack_length= seg->bit_start;
uint length= (pack_length == 1 ? (uint) *(uchar*) pos : uint2korr(pos));
seg->charset->coll->hash_sort(seg->charset, pos+pack_length,
length, &nr, &nr2);
}
TEXT和VARCHAR也是如此。 hash_sort
可能是考虑整理的其他功能。 VARCHAR具有前缀1或2字节长度。
else
{
uchar *end= pos+seg->length;
for ( ; pos < end ; pos++)
{
nr *=16777619;
nr ^=(uint) *pos;
}
}
所有其他类型都使用mutiplication和xor
进行逐字节处理。