本文转载于SMTH的SET版,由大牛pennyliang所作。觉着写得真的挺好,就厚颜无耻的拿过来了。
我们首先从数据库的角度看,我们知道mysql的基本结构一般是B+树,为什么常用的不是HASH呢?从几个方面来看。
一般我们存储数据的方法可以抽象为。
primay key, candiate key1,candidate key2,...->value{field1,field2,...}
如果我们支持的仅仅是
select field1 from table where primay key=XXX
那么完全可以用HASH来做,而且可能更好。
但如果是这样的查询呢?
select field1 from table where primay key>XX and key <YY
显然用普通的HASH,就很难处理了,需要枚举出XX到YY全部的key,一个个的去尝试。
在比如两个表相交的场合,用HASH来做也会很伤,很多不必要的计算。
因此就引出了一个问题,需要保序(order preserved),可以将哈希函数做到完美哈希函数来实现保序,这个在即将出版的MG一书中有精彩论述,而且做出一个完美哈希函数代价极大,只能对静态集合,长期使用的场合使用,比如静态字典。
B+树很好的解决了这个问题,value都在叶子节点上,而且是保序的,因此很容易处理这种查询,但B+树需要有非叶节点的开销,插入,删除都会有一定代价。
对于索引一次创建,没有插入和删除的需求的话,最朴素的方法,莫过于直接排序,即我们可以把此前的结构转化为。
primary key value
key1 v1
key2 v2
key3 v3
... ...
keyn vn
每个key都是排好序的,这一点很重要,其余的candidate key也是类似处理。每个索引用一个索引文件来表示。
如果value特别巨大,这里可以存放的是value在硬盘的偏移(linux的话还可以直接写设备,直接用设备的偏移来表示数据的位置)
排序为优化创造了很好的条件,比如我们需要进行一个这样的查询:
select table1_key,table2_key,table1_value from table1,table2
where table1_key=table2_key
由于这两个表都是按照key排序的,这样两个有序的索引求交可以非常快速,只需要O(min(length(table1),length(table2))的时间复杂度。
排序的方法在处理duplicate key也非常有利,仅仅是相同key的位置放在了一起,而哈希还需要特别处理这种情况(注意这种不是冲突,比如用学生姓名做candidate index,可能会有同名的情况)。
另外排序的方法是最节省的了,几乎没有浪费,性价比高。