索引的出现其实就是为了提高数据查询的效率,就像书的目录一样。常见的索引类型有:哈希表、有序数组、搜索树
哈希表
哈希表是一种以键 - 值(key-value)存储数据的结构,我们只要输入待查找的值即 key,就可以找到其对应的值即 Value。哈希的思路很简单,把值放在数组里,用一个哈希函数把 key 换算成一个确定的位置,然后把 value 放在数组的这个位置。
不可避免地,多个 key 值经过哈希函数的换算,会出现同一个值的情况。处理这种情况的一种方法是,拉出一个链表,即链表法。
哈希表在等值查询时是很快的,但在区间查询时效率却非常慢。由于哈希存储时的数据并不是递增的,在区间查询时就必须全表扫描了。
应用于 Memcached 及其他一些 NoSQL 引擎
有序数组
有序数组在等值查询和区间查询时的性能都非常优秀。由于数组中的元素都是递增的,所以在查询时可以采用二分法查找,这个时间复杂度为O(log(N))。
在范围查询时也是一样,只要找到大于区间的左边,然后向右遍历找到区间的右边。这样的效率也是很快的。
但有序数组也有个缺点是更新插入时效率很差,原因在于新插入一个数据时,数组需维护有序状态,所以会将插入位置后面的数据往后挪,这样所花的成本太高。
所以,有序数组索引只适用于静态存储引擎,比如你要保存的是 2018 年某个城市的所有人口信息,这类不会再修改的数据。
搜索树
先说下二叉搜索树。我们知道,二叉搜索树有个特点是,每个节点的左儿子小于父节点,父节点又小于右节点。所以在搜索时其效率可达O(log(N))。
如果是以二叉搜索树为索引结构的话,其效率不一定高。原因在于当数据量大时,即节点数非常多,其树的高度也会很高。这将导致每一次遍历的时候都需要遍历每一层的数据(一层的数据为一个数据块),读取数据块的操作是非常慢的。可见数据块越多对数据搜索效率就越差。
为了让一个查询尽量少读磁盘,就必须让查询过程访问尽量少的数据块。故我们不应该使用二叉树,而是采用N叉树,这N由数据大小决定。
N 叉树由于在读写上的性能优点,以及适配磁盘的访问模式,已经被广泛应用在数据库引擎中了。
Tips:
数据库底层存储的核心就是基于这些数据模型的。每碰到一个新数据库,我们需要先关注它的数据模型,这样才能从理论上分析出这个数据库的适用场景。