这是我参与8月更文挑战的第6天,活动详情查看:8月更文挑战
1. Optimization
Prefix compression
同一个叶子节点中的key可能有相同的前缀,可以提取公共前缀,然后各自记录除公共前缀外不同的部分。
Suffix truncation
truncation截断;由于树的中间节点(inner node)只用来做路径搜索,所以不需要存储完整key,只需要能够用于正确的进行路由就可以了。
Bulk insert
构建一个b+树的最快方法是首先将key的序列进行排序,然后自底向上的构建索引。
Pointer swizzling
一般在索引中,节点都是使用page id 来引用其他的node。如果某个page已经写入内存中,可以直接存储对应内存位置的raw pointers。
2. Duplicate keys
对于非唯一的key,有两种处理方法:
- Append record id 每条数据的record id是唯一的(page id 和slot id组成)
- Overflow leaf nodes 维护和修改更复杂
3. Additional index usage
Implicit indexes
DBMS一般会自动在主键和unique的属性上创建索引。但是在外键不会。
Partial indexes
在整张表的的一个子集上建立索引(只选择部分数据)。这可以用于,例如按照时间日期进行分区建表建索引。
Covering indexes
如果一个查询所需要的全部属性都在一个索引上,那么DBMS就不需要再去访问完整的tuple。这减少了对buffer pool的资源占用。
Index include columns
在索引上额外存储某个列,来尽可能的让index能够cover query。注意,显然地,这个额外的列并不属于search key。
Functional/expression indexes
Other indexes
Trie index
前缀树,逐个检查key的字符,而非直接比较完整的key。
复杂度和key的长度有关。O(k)。
树的结构只依赖于key的分布和长度,与插入顺序无关;不需要rebalancing操作。
Radix tree
基数树,前缀树的一个变种。不像前缀树那样将每个字符都拆开,而是只拆开公共的部分。
Inverted index
以上讨论的树形索引结构都适用于某个值或某个区间的值的查询,但不适用于是否存在的检索(contains)。
使用倒排索引来维护word-record的映射关系。记录了每个word和在目标属性中包含这个word的所有记录的列表。
4. Design decisions
关于索引的一些决策问题:
- What to store:索引中需要记录至少一个属性;也可以记录word出现的频率、位置或者其他元数据;
- When to update:可以使用辅助的数据结构来记录更新,然后批量进行索引更新
5. 总结
首先补充了一下上一节没有写完的,关于索引的一些优化策略。首先从空间的代价去考虑,索引中的key都是有序存储的,所以可以用提取公共前缀的思想来减少叶子节点中的数据占用的空间。另外,由于b+树的性质,内部节点只用来进行路径检索,所以可以只保留能够用于路由的前缀即可,冗余的后缀可以截断;
然后考虑时间的代价。首先b+树是一种搜索树,所以提取将数据排序再构建树结构会提高效率;然后,对于树结构中节点的检索,如果某个节点对应的page已经存在于内存中,那么指向这个节点的指针就可以直接指向内存中的位置。