自己动手写数据库:实现基于静态哈希的索引

本文讨论了数据库设计中的查询优化难点,特别是如何通过索引结构(如哈希索引和B+树)提高查询速度。文章介绍了如何在不改变表结构的前提下,利用索引文件记录数据分布,以及哈希索引的工作原理和B+树在处理数据删除和修改时的作用。通过实例展示了索引管理器的创建过程和查询优化的实际应用。
摘要由CSDN通过智能技术生成

数据库设计中有一项至关重要的技术难点,那就是给定特定条件进行查询时,我们需要保证速度尽可能快。假设我们有一个 STUDENT 表,表中包含学生名字,年龄,专业等字段,当我们要查询给定年龄数值的记录,如果我们能把所有记录以年龄字段排序,那么通过二分查找,我们就能快速定位满足条件的记录。如果表中包含N=1,000,000 条记录,通过二分查找就能通过大概 logN = 20 次即可,但是要遍历所有记录来找,就得查询一百万次。

但根据某个字段来排序记录,当查询以另外字段查询时就无法得到相应加速。因此如何通过合适算法,让数据进行相应组织,使得查询根据不同字段进行时都能得到相应加速是数据库设计的核心难题。

在不改变表结构的情况下,要能根据不同字段加快查询速度,就需要索引制度。索引本质是一个文件,其中的数据是对给定表的记录分布进行描述和说明。索引文件中的数据以一条条记录的方式存在,一条记录包含两个字段,一个字段叫 datarid,它是一个指针,指向某条特定数据所在的位置,另一个字段叫 dataval,它可以是建立索引的字段的值,如果我们要想针对两个字段 age, name 进行索引,那么索引文件钟就包含两种记录,一种记录的 dataval 对应 age 的值,另一种记录的 dataval 存储 name 的值,然后记录根据 dataval 的值排序,于是我们要根据 age 查询时,我们先通过折半查找在第一种记录钟查询到 VALUE 为给定查询值的记录,然后通过 datarid 字段获取给定记录在硬盘的位置,另外需要注意的是,索引信息也是存储在文件中,获取索引信息也需要访问磁盘,因此我们需要使用好的所有算法尽可能减少在查询索引信息时对磁盘区块的读取。

使用索引文件创建索引数据来记录每条记录的位置还有一个问题,那就是记录会删除和修改,一旦相关记录删除和修改后,索引中的数据就需要进行相应变动,这里我们就需要 B 树,B+树等相关算法的支持。

还需要注意的是,一旦能快速定位所需记录的位置,我们就能定位记录所在的区块从而大大减少对硬盘的访问次数。但也有例外的情况,当建立索引的字段取值重复性很小时,索引的效率就好,如果索引字段取值的重复性很高,那么效率反而有可能会降低。

我们把索引建立的基本流程展示如下:
1c1005c2cbed4000d16f68959b976873.png
1,当解释执行索引建立的 SQL 语句时,例如 create majoridIDX on student (majorid),
create nameIDX on student (name), 启动索引建立流程
2,索引流程首先创建专门存储索引信息的表 idxcat,其字段为 indexname, tablename, fildname,这些字段分别用于存储索引的名称,建立索引的表名和字段名称。
3,选择索引算法,这里我们先使用前面说的哈希索引。我们使用一个哈希函数hash,假设他能将输入的数据哈希到 0-1000 这范围内的整数值, 假设字段 majorid 的取值 20和 100 经过该函数后输出结果相同为 39,那么代码将创建一个名为 majoroid#39 的记录表来存储这两条记录的访问信息(blockid 和 offset),上图,该表的字段为 dataval,block, id 分别用于存储记录对应索引字段的值,记录所在的 blockid 和 offset 也就是偏移。

在上面例子中由于 majorid 为 20 和 100 的记录都哈希到数值 39,因此他们这两条记录的存储信息都存储在表 majorid#39 这个表中,记录中字段为 name=”jim”的记录,由于”jim”哈希的结果为 69,因此该记录的存储信息放置在表 name#69 中。

哈希索引的效率取决于所寻求哈希函数的取值范围,假设函数哈希结果取值范围为 0-N,那么对于一个包含 M 条记录的的表,他对应记录的存储信息将放置在 M/N 个哈希记录表中。哈希索引法在理论上能将记录的查询时间从 M 优化到 M/N。
4,在执行 select 语句进行记录查询时,首先在索引表 idxcat 中查询给定表和对应字段是否已经建立了索引,如果建立了,那么直接从对应的查询记录表中获得记录的存储信息,然后直接从硬盘读取记录数据。

我们看对应代码实现,索引管理器的实现依然放在 metadata_manager 路径下,创建一个名为index_manager.go 的文件,增加代码如下:

package metadata_manager

//索引管理器需要使用到后面才讲到的SQL查询和索引算法知识,所以先放一放
import (
    "query"
    rm "record_manager"
    "tx"
)

type IndexManager struct {
    layout  *rm.Layout
    tblMgr  *TableManager
    statMgr *StatManager
}

func NewIndexManager(isNew bool, tblMgr *TableManager, statMgr *StatManager, tx *tx.Transation) *IndexManager {
    if isNew {
        //索引元数据表包含三个字段,索引名,对应的表名,被索引的字段名
        sch := rm.NewSchema()
       
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值