11.索引
提纲
- 索引的概念
- 顺序索引
- 稀疏和密集索引
- 多级索引
- 主索引和辅助索引
- 散列索引
- 索引评估
- B+ 树和动态索引
- 多搜索键的情况
索引概念
想象一个数据库,保存着 1000 万名居民的记录
- 每个居民包含属性 ID,address,telephone 等等
人们可以通过其 ID 检索居民信息
如果我们不通过计算机构建数据库的话:
- 我们可以将所有记录打印在一个目录中
- 假设每页能容纳 10 个记录,那么这个目录将长达 \(10^6\) 页
如何排列目录中的记录?
- 目标:最大限度地减少查找记录的工作量
- 评估:成本定义为在最坏情况下找到记录之前必须“打开”的页数
方案一:无规则排列记录
- 此时我们不能根据规则检索,只能暴力搜索
- cost = \(10^6\) page
方案二:根据 ID 排好序
- 使用二分查找,cost =
![image]()
- \(10^7\) 个记录顺序排列在 \(10^6\) 个 page,只需跟每个 page 首个记录比较,所以是log2\(10^6\)
- 数据存储在磁盘上,读写以 page 为单位
- 每次读取时都会将整个页面带入主内存
- 成本仅计算 page 读取次数,因为磁盘操作比 cpu 操作昂贵得多
保留已排序的文件并额外创建一个索引
-
每个索引条目是一个小的记录 < ID, Page No >
- 包含 ID 以及可在其中找到 ID 的页面
- 例如: < 5634569, 259 >的意思是 5634569 在页 259 上存储
-
ID称为索引的搜索键 search key
-
索引条目比记录小得多!
-
与原来直接检索记录相比,我们只需要检索 index entry,只要找到该 id 的 index entry,我们就能根据其附有的地址找到完整记录
-
我们是否要为这 \(10^7\) 条居民记录中的每一条记录添加一个条目?
- NO !我们只要求每个 page 的第一条记录有一个条目
- 给定索引中两个连续的连续条目 < 5634569, 259 >, < 5700000, 260 >,可以知道 5634569 和 5700000 之间的每个 ID 都必须在页 259 上
- NO !我们只要求每个 page 的第一条记录有一个条目
-
鉴于每页可以容纳 100 个条目,并且我们有 1,000,000 个条目,因此索引为 10,000 页
-
如果使用索引来加快记录搜索速度?
- 对索引使用二分查找来寻找其中小于等于 ID 的最大 ID 值,cost =
![image]()
- 然后,沿着该条目的指针读取目标记录所在的页面, cost = 1
- 总的 cost = 14 + 1 = 15
![image]()
- 对索引使用二分查找来寻找其中小于等于 ID 的最大 ID 值,cost =
-
可以进一步降低成本吗?
- 进一步创建一个二级索引,用于索引 100 页中的 \(10^4\) 个条目。同样的,我们只需要索引一级索引中每页的第一个记录
- 使用二分搜索:cost =
![image]()
- 然后,沿着两层索引找到目标记录页面,cost = 2
- 总 cost = 7 + 2 = 9
- 同上,可以进一步建立新索引......
![image]()
索引的基础概念
- 索引机制可加快对所需数据的访问
- 例如,菜鸟驿站用的快递架跟快递编号
- 搜索键:即寻址的根据、编号的根据
- 索引文件由以下格式的记录(称为索引条目)组成:
![image]()
- 两种基础的索引
- 按搜索键值顺序索引
- 使用散列函数将搜索键均匀地分布在“桶”中,无序存储
顺序索引
我们构建的索引是有序的 - 也称为树索引
- 记录的索引节点位置是按 search key 排序的
- 还有其他类型的索引
查找记录时,从根节点开始,沿着某一路径到达包含记录搜索键值的叶节点
获取一个记录所需的 page 访问次数为:树高 + 1

主索引 vs. 辅助索引
- 主索引(也叫聚合索引):文件的实际存放也是按 search key 排序的
![image]()
- 辅助索引:文件的实际存放不按 search key 排序
![image]()
稀疏索引 vs. 密集索引
- 稀疏索引:仅包含某些 search key 的索引
- 仅适用于主索引
- 譬如:仅检索每个 page 的第一个 record
- 更少的存储空间,插入删除时更少的 overhead 额外成本
- 仅适用于主索引
- 密集索引:包含所有 search key 的索引
![image]()
多级索引
- 如果主索引太大装不进内存,则需要用到 disk,索引过程的时间成本会变高很多(涉及到磁盘读写)
- 将保存在磁盘上的主索引条目视为排序的文件,并在其上构造稀疏索引,用于检索主索引条目
- 外部:主索引的稀疏索引
- 内部:主索引文件
- 如果外部索引太大而无法放入主内存,则可以创建另一级索引,以此类推
- 每次更新(插入删除)会由内到外引起 indexes 的连锁反应更新
![image]()
二级密集索引的例子
如果查询条件不是跟 search key 有关的怎么办?
- 例子 1:如果账户数据库是按照账户号码顺序存储的,我们可能想要找到某个特定分行的所有账户。
- 例子 2:同上,但我们想要找到所有具有特定余额或一定余额范围的账户。
- 对非排序属性( account-number、balance )额外建立索引,生成二级索引
![image]()
- 当检索许多记录时(例如,范围检索),辅助索引可能非常昂贵。因为在磁盘不连续地寻址耗时更长
哈希索引
- 哈希索引不仅可以用来组织文件存储,也可以用来构建文件索引
- 哈希索引组织搜索键及其关联的记录指针
- 严格来说,哈希索引始终是二级索引
![image]()
索引评价指标
- 能高效支持不同查询
- 例如,哈希在范围检索表现很差
- 辅助索引在检索多个记录时表现也很差,因为磁盘经常需要跨区寻址
- 更新时间成本
- 当文件被修改时,其索引页必须更新
- 额外存储成本,即 index 本身大小
- 索引通常应该比数据文件小得多
数据更新:删除
- 若删除的记录的 search key 在 file 中是唯一的,则该 key 也要在 index 里删除,如下表的 Brighton
- Single-level index deletion
- 密集索引:
- 稀疏索引:假设该删除记录的 search key 在 index 里有对应的 entry,则将该 entry 替换为该删除记录后面记录的 search key
- 密集索引:
数据更新:插入
- 单机索引插入
- 使用插入记录的搜索键值执行查找
- 如果搜索键值没有出现在索引中,则将其插入
- 如果该索引为文件的每个 page 维护有一个索引条目,则不需要对索引进行任何更改。除非创建新 page,当有新的 block( page )创建的话,将该 block 的第一个 search key 加入 index
















浙公网安备 33010602011771号