MIT6.830实现关系型数据库simpleDB

本篇博客详述了数据库管理系统SimpleDB的实现,包括数据存储、操作符、查询优化、事务处理和索引等内容。在数据管理方面,实现了BufferPool、HeapFile和B+树索引,优化了查询性能。在查询优化中,涉及了操作符如Filter、Join的实现,以及基于代价的查询计划。事务处理涵盖了两阶段封锁协议、死锁检测和回滚恢复。此外,还介绍了B+树的索引结构和其在提高查询效率中的作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

lab1 实现数据管理

主要需要实现存储、访问与管理物理层面的数据(二进制文件),以及将其映射为逻辑层面的数据(关系表)。在这一课题的最后,还要求实现SimpleDB中最基本的操作——SeqScan,因此完成这一章后,就可以扫描全表了。本节内容相对简单。

exercise1

主要是实现Tuple与TupleDesc这两个类的构造器和主要方法,较为简单。

Tuple:包含td,rid,fields三个属性,一条记录最基本的信息,其它的就是一些构造器,getter方法和迭代器等,看着注释实现就可以了。

TupleDesc:TupleDesc主要是需要实现一个TDItem内部类来表示一个字段的描述信息,包括字段类型,字段名;TupleDesc中用一个TDItem数组来表示多个字段的描述信息,有了这个,后面做起来就简单很多了。

exercise2

主要是实现Catalog.java这个类,这里的关键是在Catalog里实现一个Table类,来存放一张表格的信息;然后一个CataLog有多张表格,在Catalog里我们可以用map来存储tableid与table的映射关系;为了方便操作,我还多创建了一个存放table name与 table id映射关系的map

exercise3

无需实现淘汰策略,主要是实现getPage方法。根据PageId来查找BufferPool中有无该数据页,如果有直接返回,如果没有就从磁盘中获取,存入BufferPool中。其中BufferPool的容器是用map来存Page的,以pid的hashcode与Page建立映射关系。

exercise4

主要是实现以下三个类:

HeapPageId.java RecordId.java HeapPage.java
关键是HeapPage的实现,HeapPage中的核心是数据是怎样HeapPage中组织的,这里主要是由header和tuples两个部分组成。其中,一条tuple在HeapPage中表示为一个slot,而header以bitmap的形式来表示第i个slot是否被占用,最低位表示第一个slot是否被占用。由于header是一个byte类型数据,所以最后一个字节并不一定都表示一个slot,也可能无意义

exercise5

主要是实现heapfile,HeapFile是DbFile的实现,是对磁盘文件操作的入口

HeapFile要求我们实现一个readPage方法,根据PageId去从磁盘中读取数据。这里主要的难点是计算偏移量然后读取数据,这里需要先计算出offset,然后用seek移动指针,然后再开始读取.

exercise6

注意是做一个全表扫描,主要验证上一个exercise实现的迭代器的正确性,实现SeqScan即可,其中SeqScan给扫描的表支持别名,然后getTupleDesc需要去修改每个字段的名字,加上别名如a.table

lab2:实现操作符

这一部分主要是实现一系列操作符,包括insert、delete、select、join、group by、order by等。其中,join的高效率实现是一个难点(学习一下常见的算法即可,文末有推荐文章),其他操作符都比较简单。而且group by与order by功能被简化了,也省去了一部分工作量。而在课题最后,则要实现课题一未完成的一个功能——缓存管理。在这里,将要学习并实现缓存机制,包括缓存替换策略(LRU等)。

  1. Nested-Loop Join Algorithms_高爽的博客-CSDN博客
    这是Join算法的优化,建议在第2个课题实现到join操作时看

exercise1

要求我们完成Filter和Join两种操作符

Filter是SQL语句中where的基础,如select * from students where id > 2.Filter起到条件过滤的作用。我们进行条件过滤,使用的是迭代器FIlter的next去获取所有过滤后的记录,比如上述SQL语句的结果,相当于List<Tuple> list;即一个含有多条tuple的集合,而忽略其中的实现细节Filter就相当于list.iterator()返回的一个跌打器,我们通过it.next()去获取一条一条符合过滤条件的Tuple。

Filter是继承于Operator的,而Operator继承于抽象类OpIterator,是一个迭代器.

Join算法我选择的是BlockNestedLoopJoin

* 传统的BlockNestedLoopJoin只是对左表做缓存,使用Block来减少对左表的访问带来的磁盘IO次数(每一个Page都要带来一次IO访问)
* DoubleBlockNestedJoin是对右表也做缓存处理,后来发现效果并不明显,
* 我一开始认为还是IO瓶颈,所以给HeapFile加了对多个Pages的缓存
* 然而除了对于(左部)大表Join(右部)小表有了一些不明显的效率提高之外,对于大表Join大表仍然效率极低
* 最后发现此时性能瓶颈在于对两个缓存区Block做Join操作,Block虽然比一个大表小,
* 但实际上也不小(测试案例中两个Block是长度为16384和963的数组)
* 在查阅了MergeJoin算法之后,觉得先排序再Join的思想挺好,就将两个Block的Join换成了先排序再Join的版本,得到了bnlSortedJoin

exerciese2

要求我们实现各种聚合运算如count、sum、avg、min、max等,并且聚合器需要拥有分组聚合的功能。讲义告诉我们,我们只需实现根据一个字段去分组和聚合,也就是只有一个分组字段和一个聚合字段。

exercise3

需要我们实现HeapPage、HeapFile、BufferPool的插入元组和删除元组的方法。

在HeapPage中插入和删除元组
我们要在HeapPage中插入元组,要做的第一件事就是找空槽位然后进行插入,再处理相关细节;我们要在HeapPage删除tuple,首先需要找到tuple在哪个slot,再进行删除即可。

插入元组的思路:找到一个空的slot,然后进行插入,并标记slot已经被使用

在BufferPool中插入和删除元组
以插入元组为例,BufferPool与HeapFile的调用关系:

1.BufferPool插入元组,会先调用Database.getCatalog().getDatabaseFile(tableId)获取HeapFile即表文件;

2.执行HeapFile.insertTuple(),插入元组并返回插入成功的页面;

3.使用HeapPage的markDirty方法,将返回的页面标记为脏页,并放入缓存池中

Exercise4:Insertion and deletion

exercise4要求我们实现Insertion and deletion两个操作符,实际上就是两个迭代器,实现方式与exercise1相似,将传入的数据源进行处理,并返回处理结果,而处理并返回结果一般都是写在fetchNext中。这里的处理结果元组,只有一个字段,那就是插入或删除影响的行数,与MySQL相似。具体实现插入和删除,需要调用我们exercise3实现的插入删除元组相关方法。

批量记录是怎样被插入的?
写完exercise4,我们可以开始思考这个问题了,以便将整个过程连贯起来。
0.客户端发起请求,请求消息的有效内容是上述的sql语句(假如我们有客户端和服务端);

1.SQL解析器解析上述语句,并获取要插入的表,记录信息;

2.根据表获取表的id,并将记录信息封装成数据源child(实质是一个迭代器);

3.生成本次批量插入操作的事务id;

4.把tid、tableId、child传入Insert操作符的构造器中,生成Insert对象;

5.调用Insert的hasNext方法,判断是否有结果,因为是第一次调用,hasNext会调用我们写的fetchNext方法,去执行插入操作并获取结果;

6.在fetchNext执行操作的具体步骤是:调用Database.getBufferPool().insertTuple(tid, tuple)方法进行插入,BufferPool的insertTuple会根据tableId从获取数据库文件HeapFile,并调用HeapFile的insertTuple方法;而HeapFile的insertTuple方法会调用BufferPool.getPage()方法从缓冲池取出页面HeapPage(如果缓冲池没有才会从磁盘中取并放入缓冲池);获取HeapPage后,调用HeapPage.insertTuple()方法,去插入元组;插入完成后,HeapFile会返回从BufferPool中获取并插入了元组的页面,在BufferPool的insertTuple中把它标记为脏页并写回缓冲池;

7.整个过程下来,插入的元组并不是真正插入到了磁盘,而是在缓冲池中取出页面插入元组标记脏页并写回缓冲池。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值