MySQL中的哈希索引算法

时间:2012-08-28 10:10:16

标签: mysql sql hash indexing

我正在读一篇关于哈希索引的文章,似乎它类似于PHP的md5函数,因为它们都接受一个字符串值并返回一个表示该字符串的整数,这个表示形式是是一致的。这种相似性真的存在吗,还是我错过了什么?还有谁知道MySQL采用基于散列的索引结构的散列算法?

1 个答案:

答案 0 :(得分:2)

我不是假装对MySQL算法做出完整的描述,但有一些事情可能会被猜到。

首先,Hash table wiki是必读的。然后我们收到MySQL documentation的通知:

  
      
  • 它们仅用于使用=或< =>的等式比较。运营商(但速度很快)。它们不用于比较
      运营商如<找到一系列的价值观。依赖的系统   这种类型的单值查找称为“键值存储”;到
      将MySQL用于此类应用程序,尽可能使用哈希索引。
  •   
  • 优化器无法使用哈希索引来加速ORDER BY操作。 (此类索引不能用于搜索下一个   按顺序进入。)
  •   
  • MySQL无法确定两个值之间大约有多少行(范围优化器使用它来决定)   使用哪个索引)。如果您更改a,这可能会影响某些查询   MyISAM表到哈希索引的MEMORY表。
  •   
  • 只有整个键可用于搜索行。 (使用B树索引,密钥的任何最左前缀都可用于查找行。)
  •   

这指向以下(相当常见)属性:

  1. MySQL哈希函数在固定长度的“全键”记录上运行(它 但问题是如何处理varchars,例如它们可能用零填充到最大长度)

  2. 在猜测哈希函数的上行数时,引擎可能会使用max_heap_table_size个全局值和MAX_ROWS参数。

  3. MySQL allows非唯一键,但警告比例减速。至少这可能告诉我们没有第二个哈希函数,而只是一个在冲突解决中使用的链表。

  4. 至于所使用的实际功能,我认为没什么可说的。 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进行逐字节处理。