You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
在公布了今年的赛题后,首先有80分的题目我们已经做了:basic、select-meta、drop-table、update、date、select-tables、insert、order-by,虽然有些需要做修改,还有一个改动略大,但起码大体上没啥问题。对于这80分的题目我们基本上是把对应的提交直接 rebase 到了今年的开发分支上,然后做修改提测
base on: 6d7e170
比赛开始之前
找一些文档看,还有官方的赛前培训
可以做去年的题目,我们开始之前把2021年的题目做了80分
初赛
准备
首先要为后续的开发、测试、版本管理构建一些基础模块,比如说编译安装以及测试的 shell 脚本、代码格式化(clang-format)、代码静态检查(clang-tidy)、Gitee 和 Github 的 Issue 和 PR 模板、Github 的 workflow 等等
涉及到的几个提交如下:
clang-format/tidy
clang-format 和 clang-tidy 模块源自bustub/build_support at master · cmu-db/bustub,我们在此基础上禁用了一些 check,并且限制了被检查的目录
这两个工具除了规范编程以外,也有很实际的好处:
使用 clang 编译
e35aeb5 (这个其实没啥用)
版本管理
主要就三个原则:
rebase 主要是为了让提交历史更清晰,尽可能地线性化
这是我们 main 分支最后的一部分提交记录
![image](https://user-images.githubusercontent.com/46896167/200178667-ac14ddc1-19af-4afd-8fd0-c439dbc3f704.png)
赛题分析
在公布了今年的赛题后,首先有80分的题目我们已经做了:basic、select-meta、drop-table、update、date、select-tables、insert、order-by,虽然有些需要做修改,还有一个改动略大,但起码大体上没啥问题。对于这80分的题目我们基本上是把对应的提交直接 rebase 到了今年的开发分支上,然后做修改提测
然后我们发现对于 update、insert、show-index、multi-index、unique、clog 这几个赛题是一条线上的,这条线交给成林 @Zhang-X0 来做,我只了解一部分,一起调了调 bug,这几个赛题后面就不说了
剩下的由我和琨琨 @yang-jun-kun 做,这部分赛题思路我都熟,以下都会提到
具体的实现可以找对应的 PR 看
赛题思路
drop-table
先看 create table 和 create index 的流程,在 drop table 的时候要处理好各种资源
有一个要注意的地方是 disk buffer pool 的析构,会在 close file 的时候把自己释放掉,但是 buffer pool manager 中还有信息未删除,会导致问题
typecast
先把类型转换的函数单独实现,存一个函数指针的二维数组 cast_to
然后考虑要在哪里用这个模块就行
另外,在 do_predicate 的时候比较的规则是:
总结来说就是不考虑 date,先处理 null,其他情况都先转成 float
like
select-tables && join-tables
Tuple 是算子执行阶段中非常好的一层抽象:
miniob-2022/src/observer/sql/expr/tuple.h
Lines 75 to 96 in 6d7e170
利用好 Tuple 这个抽象,构造一个 CompoundTuple(一开始叫 JoinedTuple)
最初的实现:
后来因为在实现 OrderBy 的时候必须缓存表数据,所以把这里也改成了缓存右表数据:
并且考虑到 JoinOperator 的孩子可能是其他类型的算子(尤其是考虑到 ProjectOperator 这种特殊类型,必须用 ProjectTuple 才能得到正确的信息,虽然今年的赛题里没有这种情况):
实现 InnerJoinOn 的时候,一开始
偷懒做的方案是把 on filter 作为 where filter,等所有的表笛卡尔连接后再统一做 filter,结果超时了最后的方案是在构造 JoinOperator 的时候尽可能地把 filter 推下去,给 JoinOperator 集成了过滤功能
最终,JoinOperator 的 next 流程为:
text
发现了官方的彩蛋(
或者说卡了一个 bug)直接看 commit msg: 8abfe5a
分隔
到这里为止,第一页的基本都做完了,分析后面的赛题的时候发现存在一个 null 测例,其前后的一些测例都要把 null 考虑进去
另外还发现 aggr-func 赛题排在很前面,group-by 赛题排在很后面,但是我觉得这两个应该一起做,仔细考虑之后,重排了一下做题顺序,具体安排见 #14
order-by
expression
在语法分析阶段根据优先级构造成树的形式,resolve 阶段保留树的结构,执行阶段后序遍历执行
在语法阶段增加了 UnaryExpr、BinaryExpr、Expr,在 resolve 阶段给 Expression 扩充了 BinaryExpression,具体的运算则是对 TupleCell 做扩展
function
对表达式的扩充,语法阶段增加了 FuncExpr,对应到 resolve 后的 FuncExpression
group-by && aggrfunc
重排做题顺序主要是为了把这两一起实现 #14
这块新增了 GroupByUnit GroupByStmt GroupByOperator GroupByTuple,以及 AggrFuncExpr(esssion)
实现的关键在于 GroupByTuple,也是利用了 Tuple 这个抽象
其他的几个点:
具体实现看 #15
过了两周才写这里,忘了不少,但最关键的部分已经写了null
关键思路:在 Record 中给每个 nullable 的字段加一个 null 标志
实现上,为了简单,给所有字段都加这个标记,具体来说有两种方案:
我们选择了第二种做法,这样也方便了索引对 null 的支持,把 bitmap 作为 key 的一部分,然后扩展 key compactor 就行
simple-sub-query && complex-sub-query
子查询首先要考虑如何区分父子查询的 where 谓词条件、join 谓词条件、投影列、order-by 表达式、group-by 表达式、having 谓词条件等,我们的方案是用涉及到的这些归约节点存一个 length 信息
像这样
miniob-2022/src/observer/sql/parser/yacc_sql.y
Lines 921 to 936 in 54b4154
对于 In 和 Exists 子查询其实也是给表达式做扩充,增加了 ListExpr(ession) 和 SubQueryExpr(ession)
do predicate 的时候:
对于父子查询表关联,我们给每个 Operator 增加了一个 parent tuple,do predicate 的时候把 parent tuple 和子算子的 tuple 拼成一个 CompoundTuple 传下去
最后对于复杂子查询留了一个 and 和 or 条件支持:
alias
给每个表达式存一个别名就行
update-select
有了前面子查询的基础,这里语法阶段只需要把 updates 中原来的 values 拓展成 exprs 即可,在 resolve 阶段生成对应的 Expression,执行阶段(UpdateOperator Open)先 get_value 拿到 TupleCell,根据 TupleCell 构造 Value,以适配 table update_record 的接口
非功能性 fail
basic 挂了:钉钉群里问的镜水老师,说是重启失败了,我们在本地也复现了
本地能过测例,提交后因为段错误 core 了:
此外还可以利用评测系统二分找 bug:
可以看看 alias-debug 和 unique-debug 这两个分支的最后几次提交
TODO
编码上主要是内存管理没太做好,第一周还注意着,第二周就不太行了
项目管理上还有不少问题:
Last
在满分之前没好好做文档和问题记录,想着之后补起来,但由于时间原因又隔了一个礼拜,等初赛结束的时候才勉强把这篇总结写完。当时的一些细节好多已经忘了,初赛过程中一些零散的记录也不愿再整理了,之后会和这个总结一起放到 wiki 里保存。就先这样吧
The text was updated successfully, but these errors were encountered: