索引结构
顺序文件上的索引
顺序文件:记录按查找键排序
密集索引
- 规则:每个记录都有一个索引项,索引项按照查找键排序,密集索引一般常驻内存
- 优点:查找键值为K的记录不需要访问磁盘数据块
- 缺点:索引占据太多空间
稀疏索引
- 规则:仅部分记录有索引项,为每个数据块的第一个记录建立索引
- 优点:节省索引空间
- 缺点:需要访问磁盘数据块
多级索引
- 优点:一级索引可能太大不能常驻内存,二级索引更小,可以常驻内存;减少磁盘IO
- 关于减少磁盘IO
在这个例子中,我们需要注意,只有一级索引查找需要全部在磁盘中进行,因此需要14次IO;
但是对于多级索引,二级索引本身就在内存中,因此不需要IO,二级索引定位之后会将部分一级索引读入内存,因此只需要一次IO,之后的操作均在内存中进行,最后读一次数据块,因此一共有2次IO
辅助索引
主索引:顺序文件上的索引,记录按索引属性值有序,根据索引值可以确定记录的位置
辅助索引:数据文件不需要按查找键有序,根据索引值不嗯呢该确定记录在文件中的顺序
辅助索引概念
- 辅助索引只能是密集索引
很显然,辅助索引没有顺序,因此稀疏索引无助于索引
- 可以在密集索引的基础上建立二级稀疏索引
- 间接桶:(处理重复键值)
倒排索引
- 思想:为每个检索词建立间接桶,桶的指针指向检索词出现的文档
B+树
结点性质
所有结点格式相同,均为n个值,n+1个指针
-
叶结点:至少有⌊(n+1)/2⌋个指针指向键值(还有1个指针指向下一个叶结点)
-
中间结点: 至少有 ⌈ ( n + 1 ) / 2 ⌉ \lceil (n+1)/2 \rceil ⌈(n+1)/2⌉个指针指向子树
-
根节点:至少有两个指针
插入删除
效率
- IO代价
通常情况下根节点常驻内存,因此IO代价为h-1 - 索引大小
对于块大小8KB,键2B,指针2B,则一个块可以放2048个索引项
1)一层:只有根节点记录信息,占据一个块,共2047个键值,2048个指针
2)两层:占据1+2048个块,每个块仍旧是2047个键值,约 2 2 2 2^22 222个索引
3)三层:占据 1 + 2 1 1 + 2 2 2 1+2^11+2^22 1+211+222个块,约 2 3 3 2^33 233个索引
散列表
普通散列表
- 结构:每个桶可能有多个块,则IO次数取决于块数量
- 插入:桶内若有空间则直接插入,否则创建一个溢出块
- 删除:可能需要处理溢出块
为处理溢出块过多的情况,这里提出动态散列表
可拓展散列表
成倍增加桶数目
- 散列函数h(k)是一个b位二进制序列,前i位表示桶的数目
- 从i=1开始分配桶数量(2个),若桶数量不够时,则会增加i并重新分配桶内元素(可能会有冲突块)
- 优点:大部分情况不存在溢出块,因此查找记录时,只需查找一个存储块
- 缺点:桶增长速度过快
线性散列表
线性增加
- 结构:散列函数h(k)仍是二进制位序列,使用右边i位区分桶,桶数n
- 规则:若h(k)的右i位=m<n,则记录位于第m个桶;若m>n,则记录位于 m − 2 i − 1 m-2^{i-1} m−2i−1
- n动态变化:当前记录总数r与n保持一个固定的比例之内
注意这里增加桶也是按照大小增加了01
这里注意还是会用到溢出块!
若桶容纳,则取消溢出块
对比
- 空间效率:线性散列表更优
- 查找性能:可拓展散列表更优
- 综合性能:线性散列表更好
R-Tree
R-tree结构
R-tree的插入
- 规则:从根节点开始插入,直到最适应的叶结点(最适应是指选择只需要最小增量的方框)
- 如果最合适的叶结点有空间,则直接插入;否则需要将L分隔为L1和L2(因为每个L所能容纳的结点数量是一定的)
R+树
R+树中的所有MBR互不重叠,因此一个空间数据可能存在于多个MBR中(因为有分割)
例如上图中的G
网格文件
网格文件特点
-
不同维的网格线数目可以不同
-
相邻网格线之间可以有不同的间距
-
适合多键值查询(还有范围查询)
-
需要优化的网格划分算法:每个网格中的记录均匀分布
网格文件的物理组织
- 分维聚簇组织:
网格文件考虑
- 适合分布比较均匀的多维数据
- 一般适合2维数据:维数增加将导致网格指数级增长,易出现过多的空桶
分段散列函数
散列函数对多个属性进行散列,产生一个二进制序列,其中每个属性各使用若干位
分段散列函数还支持部分匹配查询,也就是只查询单个属性
分段散列与网格文件
- 分段散列可以支持高于2维的多维数据
- 分段散列函数可以将数据均匀地散列到桶中,空间利用率更高
- 都适合部分匹配查询
- 网格文件适合NN查询和范围查询(1<x<3中),分段散列函数不太适合
- 都是将数据划分到桶中的方法——类散列方法