请注意:本仓库仅供学习参考使用,由于 2022 OceanBase 数据库大赛正在进行,与去年的题目有所重叠,提醒查看过本仓库的各位选手切勿妄图抄袭代码,违者将受到蚂蚁集团大赛委员会和法律的制裁。本仓库受开源许可证 “木兰宽松许可证”和 GNU General Public License v3.0 保护,这意味着若您使用本仓库的代码,您必须将您的代码开源(这意味着您无法在以闭源方式提交代码的所有比赛中使用)。
ATTENTION PLEASE: This repository is for study and reference only. Since the 2022 OceanBase Database Competition is ongoing, it overlaps with last year's problems. All contestants who have viewed this repository are reminded NOT TO COPY the code in vain. Violators will be subject to the competition committee of Ant Group and the legal sanctions. This repository is protected by the open source license Mulan Permissive License and GNU General Public License v3.0, which means that if you use the code of this repository, you must make your code open source (which means you cannot use closed source code way to submit code for use in all contests).
该仓库由偏远小渔村传统弱校队维护,维护人员由 @ligen131 @Bunnycxk @QuartZ-Z 组成,最终成绩:220 + 10 (除表达式外,其他题目均通过测试)。
- 若为Linux系统清略过此步骤,若为Windows系统请从官网下载
git
并安装: https://git-scm.com/downloads 默认选项安装即可。 - 单击仓库右上角的
fork
按钮建立本仓库在本人账号下的分支,请特别注意在你本人的账号下该仓库必须为Private状态。 - 通过
git clone https://github.com/[Your_User_Name]/miniob.git
将本仓库克隆到本地。 - 在本地修改、编译(请见下面How to build,需要Linux系统)、运行代码。
- 修改完代码之后通过
git push origin master
上传到dev
分支。在本地第一次上传详见下面Useful Link中的GIthub基本操作。 - 在github页面
pull request
拉取请求等待合并代码,请注意不要申请合并到master分支,请申请合并到dev分支。
Lastest Update: 2021-11-13 19:16
v0.6.0-v0.7.0 2021-11-13 19:16
@ligen 完成order-by,@Bunnycxk 完成insert。用例测试如下:
create table t(id int,name char(4),da date); insert into t values(1,'lige','2021-10-30'),(11,'lige','2021-10-31'),(2,'aset','2000-2-29'); insert into t values(4,'deft','1976-2-29'),(5,'ghit','2035-1-1'),(6,'jklt','2021-6-30'),(233,'nowt','2021-10-31'); create table s(id int,name char(4),da date); insert into s values(7,'lige','2021-10-30'),(8,'lige','2021-10-31'),(9,'aset','2000-2-29'); insert into s values(10,'deft','1976-2-29'),(11,'ghit','2035-1-1'),(12,'jklt','2021-6-30'); insert into s values(233,'nowt','2021-10-31'); insert into s values(100,'fail','2021-11-13'),(100,'FAIL','2021-11-31'); select * from t; select * from s; select * from t order by id; select * from s,t where t.name=s.name order by t.da,s.da desc; select * from s,t order by t.da desc,s.id desc; drop table t; drop table s; exit;输出:
miniob > SUCCESS miniob > SUCCESS miniob > SUCCESS miniob > SUCCESS miniob > SUCCESS miniob > SUCCESS miniob > SUCCESS miniob > FAILURE miniob > id | name | da 1 | lige | 2021-10-30 11 | lige | 2021-10-31 2 | aset | 2000-02-29 4 | deft | 1976-02-29 5 | ghit | 2035-01-01 6 | jklt | 2021-06-30 233 | nowt | 2021-10-31 miniob > id | name | da 7 | lige | 2021-10-30 8 | lige | 2021-10-31 9 | aset | 2000-02-29 10 | deft | 1976-02-29 11 | ghit | 2035-01-01 12 | jklt | 2021-06-30 233 | nowt | 2021-10-31 miniob > id | name | da 1 | lige | 2021-10-30 2 | aset | 2000-02-29 4 | deft | 1976-02-29 5 | ghit | 2035-01-01 6 | jklt | 2021-06-30 11 | lige | 2021-10-31 233 | nowt | 2021-10-31 miniob > s.id | s.name | s.da | t.id | t.name | t.da 10 | deft | 1976-02-29 | 4 | deft | 1976-02-29 9 | aset | 2000-02-29 | 2 | aset | 2000-02-29 12 | jklt | 2021-06-30 | 6 | jklt | 2021-06-30 8 | lige | 2021-10-31 | 1 | lige | 2021-10-30 7 | lige | 2021-10-30 | 1 | lige | 2021-10-30 8 | lige | 2021-10-31 | 11 | lige | 2021-10-31 233 | nowt | 2021-10-31 | 233 | nowt | 2021-10-31 7 | lige | 2021-10-30 | 11 | lige | 2021-10-31 11 | ghit | 2035-01-01 | 5 | ghit | 2035-01-01 miniob > s.id | s.name | s.da | t.id | t.name | t.da 233 | nowt | 2021-10-31 | 5 | ghit | 2035-01-01 12 | jklt | 2021-06-30 | 5 | ghit | 2035-01-01 11 | ghit | 2035-01-01 | 5 | ghit | 2035-01-01 10 | deft | 1976-02-29 | 5 | ghit | 2035-01-01 9 | aset | 2000-02-29 | 5 | ghit | 2035-01-01 8 | lige | 2021-10-31 | 5 | ghit | 2035-01-01 7 | lige | 2021-10-30 | 5 | ghit | 2035-01-01 233 | nowt | 2021-10-31 | 233 | nowt | 2021-10-31 233 | nowt | 2021-10-31 | 11 | lige | 2021-10-31 12 | jklt | 2021-06-30 | 11 | lige | 2021-10-31 12 | jklt | 2021-06-30 | 233 | nowt | 2021-10-31 11 | ghit | 2035-01-01 | 233 | nowt | 2021-10-31 11 | ghit | 2035-01-01 | 11 | lige | 2021-10-31 10 | deft | 1976-02-29 | 233 | nowt | 2021-10-31 10 | deft | 1976-02-29 | 11 | lige | 2021-10-31 9 | aset | 2000-02-29 | 11 | lige | 2021-10-31 9 | aset | 2000-02-29 | 233 | nowt | 2021-10-31 8 | lige | 2021-10-31 | 11 | lige | 2021-10-31 8 | lige | 2021-10-31 | 233 | nowt | 2021-10-31 7 | lige | 2021-10-30 | 11 | lige | 2021-10-31 7 | lige | 2021-10-30 | 233 | nowt | 2021-10-31 233 | nowt | 2021-10-31 | 1 | lige | 2021-10-30 12 | jklt | 2021-06-30 | 1 | lige | 2021-10-30 11 | ghit | 2035-01-01 | 1 | lige | 2021-10-30 10 | deft | 1976-02-29 | 1 | lige | 2021-10-30 9 | aset | 2000-02-29 | 1 | lige | 2021-10-30 8 | lige | 2021-10-31 | 1 | lige | 2021-10-30 7 | lige | 2021-10-30 | 1 | lige | 2021-10-30 233 | nowt | 2021-10-31 | 6 | jklt | 2021-06-30 12 | jklt | 2021-06-30 | 6 | jklt | 2021-06-30 11 | ghit | 2035-01-01 | 6 | jklt | 2021-06-30 10 | deft | 1976-02-29 | 6 | jklt | 2021-06-30 9 | aset | 2000-02-29 | 6 | jklt | 2021-06-30 8 | lige | 2021-10-31 | 6 | jklt | 2021-06-30 7 | lige | 2021-10-30 | 6 | jklt | 2021-06-30 233 | nowt | 2021-10-31 | 2 | aset | 2000-02-29 12 | jklt | 2021-06-30 | 2 | aset | 2000-02-29 11 | ghit | 2035-01-01 | 2 | aset | 2000-02-29 10 | deft | 1976-02-29 | 2 | aset | 2000-02-29 9 | aset | 2000-02-29 | 2 | aset | 2000-02-29 8 | lige | 2021-10-31 | 2 | aset | 2000-02-29 7 | lige | 2021-10-30 | 2 | aset | 2000-02-29 233 | nowt | 2021-10-31 | 4 | deft | 1976-02-29 12 | jklt | 2021-06-30 | 4 | deft | 1976-02-29 11 | ghit | 2035-01-01 | 4 | deft | 1976-02-29 10 | deft | 1976-02-29 | 4 | deft | 1976-02-29 9 | aset | 2000-02-29 | 4 | deft | 1976-02-29 8 | lige | 2021-10-31 | 4 | deft | 1976-02-29 7 | lige | 2021-10-30 | 4 | deft | 1976-02-29 miniob > SUCCESS miniob > SUCCESS
*期望得分:90
*第一次多人合作提交代码。
v0.5.0 2021-11-7 16:27
完成aggregation-func。用例测试如下:
create table t(id int,name char(4),da date); insert into t values(1,'lige','2021-10-30'); insert into t values(11,'lige','2021-10-31'); insert into t values(2,'aset','2000-2-29'); insert into t values(4,'deft','1976-2-29'); insert into t values(5,'ghit','2035-1-1'); insert into t values(6,'jklt','2021-6-30'); insert into t values(233,'nowt','2021-10-31'); select count(1),avg(id) from t; select count(id,name) from t; select count(*),max(id),min(da),avg(id) from t where t.id<233; select max(id),min(da),avg(id) from t where t.id<233; select count(1),count(2),count(id),count(*),max(da),min(da) from t; select count() from t; select count(id,name) from t; select count(hh) from t; select count(*),count(hh) from t; select max(id),count(id,name) from t; drop table t; exit;输出:
miniob > SUCCESS miniob > SUCCESS miniob > SUCCESS miniob > SUCCESS miniob > SUCCESS miniob > SUCCESS miniob > SUCCESS miniob > SUCCESS miniob > count(1) | avg(id) 7 | 37.4286 miniob > FAILURE miniob > count(*) | max(id) | min(da) | avg(id) 6 | 11 | 1976-02-29 | 4.83333 miniob > max(id) | min(da) | avg(id) 11 | 1976-02-29 | 4.83333 miniob > count(1) | count(2) | count(id) | count(*) | max(da) | min(da) 7 | 7 | 7 | 7 | 2035-01-01 | 1976-02-29 miniob > FAILURE miniob > FAILURE miniob > FAILURE miniob > FAILURE miniob > FAILURE miniob > SUCCESS
*期望得分:70
*因为有些非法情况题目并没有约束输出,故可能会不过。*UPD: 17:04非法输入需要全部返回FAILURE,已解决。
v0.4.0-v4.0.1 2021-11-05 16:21-16:52
妈的,经历了改了许多写法,终于他妈的完成了select-tables。用例测试如下:
create table t(id int,name char(4),da date); insert into t values(1,'lige','2021-10-30'); insert into t values(11,'lige','2021-10-31'); insert into t values(2,'aset','2000-2-29'); insert into t values(4,'deft','1976-2-29'); insert into t values(5,'ghit','2035-1-1'); insert into t values(6,'jklt','2021-6-30'); insert into t values(233,'nowt','2021-10-31'); create table s(id int,name char(4),da date); insert into s values(7,'lige','2021-10-30'); insert into s values(8,'lige','2021-10-31'); insert into s values(9,'aset','2000-2-29'); insert into s values(10,'deft','1976-2-29'); insert into s values(11,'ghit','2035-1-1'); insert into s values(12,'jklt','2021-6-30'); insert into s values(233,'nowt','2021-10-31'); select s.name from s,t where s.name=t.name; select * from s,t where s.name=t.name; select s.name,t.id,t.name from s,t where s.id=t.id; select * from s,t where s.id=t.id and s.da>'2021-10-30' and t.da<'2021-10-31' and t.id>1; select * from s,t where s.id=t.id; select * from s,t where s.id=t.id and t.da>'2021-10-30'; drop table t; drop table s; exit;输出:
miniob > SUCCESS miniob > SUCCESS miniob > SUCCESS miniob > SUCCESS miniob > SUCCESS miniob > SUCCESS miniob > SUCCESS miniob > SUCCESS miniob > SUCCESS miniob > SUCCESS miniob > SUCCESS miniob > SUCCESS miniob > SUCCESS miniob > SUCCESS miniob > SUCCESS miniob > SUCCESS miniob > s.name lige lige lige lige aset deft ghit jklt nowt miniob > s.id | s.name | s.da | t.id | t.name | t.da 7 | lige | 2021-10-30 | 1 | lige | 2021-10-30 7 | lige | 2021-10-30 | 11 | lige | 2021-10-31 8 | lige | 2021-10-31 | 1 | lige | 2021-10-30 8 | lige | 2021-10-31 | 11 | lige | 2021-10-31 9 | aset | 2000-02-29 | 2 | aset | 2000-02-29 10 | deft | 1976-02-29 | 4 | deft | 1976-02-29 11 | ghit | 2035-01-01 | 5 | ghit | 2035-01-01 12 | jklt | 2021-06-30 | 6 | jklt | 2021-06-30 233 | nowt | 2021-10-31 | 233 | nowt | 2021-10-31 miniob > s.name | t.id | t.name ghit | 11 | lige nowt | 233 | nowt miniob > s.id | s.name | s.da | t.id | t.name | t.da miniob > s.id | s.name | s.da | t.id | t.name | t.da 11 | ghit | 2035-01-01 | 11 | lige | 2021-10-31 233 | nowt | 2021-10-31 | 233 | nowt | 2021-10-31 miniob > s.id | s.name | s.da | t.id | t.name | t.da 11 | ghit | 2035-01-01 | 11 | lige | 2021-10-31 233 | nowt | 2021-10-31 | 233 | nowt | 2021-10-31 miniob > SUCCESS miniob > SUCCESS*距离上次提交已经三天,这题真的很难受qwq。经历了莫名其妙的各种段错误qwq,最终发现是自己写错了。问了各路大神,改了几种写法,还被一个大一队超了qwq。行吧,能过就行qwq。
*期望得分:60 。
*cxk也逐渐步入正轨,希望能挺进初赛吧。前面竞争已经很激烈了。
v0.3.0 2021-11-02 18:53
艰难地完成了Update。用例测试如下:
create table t(id int,name char,da date); create index da_t on t(da); insert into t values(1,'ligen','2021-10-30'); insert into t values(11,'ligen','2021-10-31'); insert into t values(2,'aset','2000-2-29'); insert into t values(4,'deft','1976-2-29'); insert into t values(5,'ghit','2035-1-1'); insert into t values(6,'jklt','2021-6-30'); insert into t values(233,'nowt','2021-10-31'); select * from t; update t set name='aaa' where da='2021-10-31'; select * from t; update t set name='bbb' where da='2021-10-32'; select * from t; update t set name='ccc' where id=9; select * from t; update t set name="OK" where da>='1976-2-29'; select * from t; exit;输出:
miniob > SUCCESS miniob > SUCCESS miniob > SUCCESS miniob > SUCCESS miniob > SUCCESS miniob > SUCCESS miniob > SUCCESS miniob > SUCCESS miniob > SUCCESS miniob > id | name | da 1 | lige | 2021-10-30 11 | lige | 2021-10-31 2 | aset | 2000-02-29 4 | deft | 1976-02-29 5 | ghit | 2035-01-01 6 | jklt | 2021-06-30 233 | nowt | 2021-10-31 miniob > SUCCESS miniob > id | name | da 1 | lige | 2021-10-30 11 | aaa | 2021-10-31 2 | aset | 2000-02-29 4 | deft | 1976-02-29 5 | ghit | 2035-01-01 6 | jklt | 2021-06-30 233 | aaa | 2021-10-31 miniob > FAILURE miniob > id | name | da 1 | lige | 2021-10-30 11 | aaa | 2021-10-31 2 | aset | 2000-02-29 4 | deft | 1976-02-29 5 | ghit | 2035-01-01 6 | jklt | 2021-06-30 233 | aaa | 2021-10-31 miniob > SUCCESS miniob > id | name | da 1 | lige | 2021-10-30 11 | aaa | 2021-10-31 2 | aset | 2000-02-29 4 | deft | 1976-02-29 5 | ghit | 2035-01-01 6 | jklt | 2021-06-30 233 | aaa | 2021-10-31 miniob > SUCCESS miniob > id | name | da 1 | OK | 2021-10-30 11 | OK | 2021-10-31 2 | OK | 2000-02-29 4 | OK | 1976-02-29 5 | OK | 2035-01-01 6 | OK | 2021-06-30
*看了两天,仿照了
Insert/delete/select
的写法,一开始看的真的晕,寻求大佬帮助之后有点思路,希望能过吧qwq。*期望得分:50
*如果能过目前就能进前50了。
v0.2.0 2021-10-31 22:06
完成date。顺便修复了一下原代码中两个char类型相接select和where时会出错的情况(如果未来有错误请到
tuple.cpp
的add_record
中的case CHARS
和condition_filter.cpp
的filter
函数中修改,具体是用到strncpy
函数那几行)。用例测试如下:create table t(id int,name char,da date); insert into t values(1,'ligen','2021-10-30'); insert into t values(11,'ligen','2021-10-31'); insert into t values(2,'aset','2000-2-29'); insert into t values(3,'fail','2000-100-29'); insert into t values(4,'deft','1976-2-29'); insert into t values(5,'ghit','2035-1-1'); insert into t values(6,'jklt','2021-6-30'); insert into t values(7,'FAIL','2021-4-31'); insert into t values(8,'FAI2','2021-2-29'); insert into t values(233,'nowt','2021-10-31'); select * from t where da='2021-10-30'; select * from t where da='2021-11-31'; select * from t where da>='2021-10-30'; select * from t where da>'2021-10-30'; select id,da from t where name='aset'; select name,da from t where name='fail'; create index da_t on t(da); select * from t; drop table t; exit;输出:
miniob > SUCCESS miniob > SUCCESS miniob > SUCCESS miniob > SUCCESS miniob > FAILURE miniob > SUCCESS miniob > SUCCESS miniob > SUCCESS miniob > FAILURE miniob > FAILURE miniob > SUCCESS miniob > id | name | da 1 | lige | 2021-10-30 miniob > FAILURE miniob > id | name | da 1 | lige | 2021-10-30 11 | lige | 2021-10-31 5 | ghit | 2035-01-01 233 | nowt | 2021-10-31 miniob > id | name | da 11 | lige | 2021-10-31 5 | ghit | 2035-01-01 233 | nowt | 2021-10-31 miniob > miniob > miniob > miniob > id | da 2 | 2000-02-29 miniob > name | da miniob > SUCCESS miniob > id | name | da 1 | lige | 2021-10-30 11 | lige | 2021-10-31 2 | aset | 2000-02-29 4 | deft | 1976-02-29 5 | ghit | 2035-01-01 6 | jklt | 2021-06-30 233 | nowt | 2021-10-31 miniob > SUCCESS
*其实date应该很快就写完了的,拖这么久没写别的实是不应该。
*期望得分:40
*如果测试中有update的数据那这10分是拿不到了。接下来写update。
*Upload by ligen131
v0.1.1 2021-10-29 14:49 && v0.1.0 2021-10-28 23:50
完成drop-table && select-meta。用例测试如下:
help; show tables; create table t(id int,name char(255)); insert into t values(233,'aaa'); insert into t values(131,'bbb'); insert into t values(233,'ccc'); insert into t values(114,'aaa'); insert into t values(555,'ddd'); select * from t; select not_exists_col from not_exists_table where not_exists_col2="aaa"; select not_exists_col from t where not_exists_col2="aaa"; select not_exists_col from t where name="aaa"; select id from t where name="aaa"; select id from not_exists_table; select id from t where aaa="aaa"; select num from t; create index t_id on t(id); create index t_name on t(name); select * from t; delete from t where name='aaa'; select * from t; show tables; drop table t; show tables; select * from t; create table t(id int,num int,name char(255)); insert into t values(666,777,"eee"); create index t_id on t(id); create index t_num on t(num); select * from t; drop table t; exit;输出:
miniob > show tables; desc `table name`; create table `table name` (`column name` `column type`, ...); drop table `table name`; create index `index name` on `table` (`column`); insert into `table` values(`value1`,`value2`); update `table` set column=value [where `column`=`value`]; delete from `table` [where `column`=`value`]; select [ * | `columns` ] from `table`; miniob > No table miniob > SUCCESS miniob > SUCCESS miniob > SUCCESS miniob > SUCCESS miniob > SUCCESS miniob > SUCCESS miniob > id | name 233 | aaa 131 | bbb 233 | ccc 114 | aaa 555 | ddd miniob > FAILURE miniob > FAILURE miniob > FAILURE miniob > id 233 114 miniob > FAILURE miniob > FAILURE miniob > FAILURE miniob > SUCCESS miniob > SUCCESS miniob > id | name 233 | aaa 131 | bbb 233 | ccc 114 | aaa 555 | ddd miniob > SUCCESS miniob > id | name 131 | bbb 233 | ccc 555 | ddd miniob > t miniob > SUCCESS miniob > No table miniob > FAILURE miniob > SUCCESS miniob > SUCCESS miniob > SUCCESS miniob > SUCCESS miniob > id | num | name 666 | 777 | eee miniob > SUCCESS
10-29: 修改元数据未校验输出No data问题,现在会返回FAILURE。
*看工程代码真的好难qwq
*drop table基本实现就是删除.table/.data/.index文件,index因为有多个所以要vector枚举,还要把Buffer Pool中的缓存清理干净(研究了好久qwq)。
*Upload By ligen131
*期望得分:30
v0.0.2 2021-10-20 13:51
编译完成,上传依赖库文件。
v0.0.1 2021-10-15 23:46
比赛开始,提交初始代码,创建
dev
分支。
(重要!必读!)OceanBase大赛miniob代码架构框架设计和说明
- install cmake
- build libevent
git submodule add https://github.com/libevent/libevent deps/libevent
cd deps
cd libevent
git checkout release-2.1.12-stable
mkdir build
cd build
cmake .. -DEVENT__DISABLE_OPENSSL=ON
make
sudo make install
- build google test
git submodule add https://github.com/google/googletest deps/googletest
cd deps
cd googletest
mkdir build
cd build
cmake ..
make
sudo make install
- build jsoncpp
git submodule add https://github.com/open-source-parsers/jsoncpp.git deps/jsoncpp
cd deps
cd jsoncpp
mkdir build
cd build
cmake -DJSONCPP_WITH_TESTS=OFF -DJSONCPP_WITH_POST_BUILD_UNITTEST=OFF ..
make
sudo make install
- build miniob
cd `project home`
mkdir build
cd build
cmake ..
make
名称 | 分值 | 描述 | 测试用例示例 |
---|---|---|---|
优化buffer pool | 10 | 必做。实现LRU淘汰算法或其它淘汰算法 | |
查询元数据校验 | 10 | 必做。查询语句中存在不存在的列名、表名等,需要返回失败。需要检查代码,判断是否需要返回错误的地方都返回错误了。 | create table t(id int, age int); select * from t where name=’a’; select address from t where id=1; select * from t_1000; select * from t where not_exists_col=1; |
drop table | 10 | 必做。删除表。清除表相关的资源。 | create table t(id int, age int); create table t(id int, name char); drop table t; create table t(id int, name char); |
实现update功能 | 10 | 必做。update单个字段即可。 | update t set age =100 where id=2; update set age=20 where id>100; |
增加date字段 | 10 | 必做。date测试不会超过2038年2月,不会小于1970年1月1号。注意处理非法的date输入,需要返回FAILURE。 | create table t(id int, birthday date); insert into t values(1, ‘2020-09-10’); insert into t values(2, ‘2021-1-2’); select * from t; |
多表查询 | 10 | 必做。支持多张表的笛卡尔积关联查询。需要实现select * from t1,t2; select t1.,t2. from t1,t2;以及select t1.id,t2.id from t1,t2;查询可能会带条件。查询结果展示格式参考单表查询。每一列必须带有表信息,比如: t1.id | t2.id 1 | 1 | select * from t1,t2; select * from t1,t2 where t1.id=t2.id and t1.age > 10; select * from t1,t2,t3; |
聚合运算 | 10 | 需要实现max/min/count/avg. 包含聚合字段时,只会出现聚合字段。聚合函数中的参数不会是表达式,比如age +1 | select max(age) from t1; select count(*) from t1; select count(1) from t1; select count(id) from t1; |
名称 | 分值 | 描述 | 测试用例示例 |
---|---|---|---|
多表join操作 | 20 | INNER JOIN。需要支持join多张表。需要考虑大表问题,不要直接使用笛卡尔积再过滤 | select * from t1 inner join t2 on t1.id=t2.id; select * from t1 inner join t2 on t1.id=t2.id inner join t3 on t1.id=t3.id; selec * from t1 inner join t2 on t1.id=t2.id and t2.age>10 where t1.name >=’a’; |
一次插入多条数据 | 10 | 一次插入的数据要同时成功或失败。 | insert into t1 values(1,1),(2,2),(3,3); |
唯一索引 | 10 | 唯一索引:create unique index | create unique index i_id on t1(id); insert into t1 values(1,1); insert into t1 values(1,2); – failed |
支持NULL类型 | 10 | 包括但不限于建表、查询和插入。默认情况不允许为NULL,使用nullable关键字表示字段允许为NULL。 Null不区分大小写。 注意NULL字段的对比规则是NULL与任何 数据对比,都是FALSE。 | create table t1 (id int not null, age int not null, address nullable); create table t1 (id int, age int, address char nullable); insert into t1 values(1,1, null); |
简单子查询 | 10 | 支持简单的IN(NOT IN)语句; 支持与子查询结果做比较运算; 支持子查询中带聚合函数。 子查询中不会与主查询做关联。 | select * from t1 where name in(select name from t2); select * from t1 where t1.age >(select max(t2.age) from t2); select * from t1 where t1.age > (select avg(t2.age) from t2) and t1.age > 20.0; NOTE: 表达式中可能存在不同类型值比较 |
多列索引 | 20 | 单个索引关联了多个字段 | create index i_id on t1(id, age); |
超长字段 | 20 | 超长字段的长度可能超出一页,比如常见的text,blob等。这里仅要求实现text(text 长度固定4096字节),可以当做字符串实现。 注意:当前的查询,只能支持一次返回少量数据,需要扩展 | create table t(id int, age int, info text); insert into t(1,1, ‘a very very long string’); select * from t where id=1; |
查询条件支持表达式 | 20 | 查询条件中支持运算表达式,这里的运算表达式包括 +-*/。 仅支持基本数据的运算即可,不对date字段做考察。 运算出现异常,按照NULL规则处理。 只需要考虑select。 | select * from t1,t2 where t1.age +10 > t2.age *2 + 3-(t1.age +10)/3; select t1.col1+t2.col2 from t1,t2 where t1.age +10 > t2.age *2 + 3-(t1.age +10)/3; |
复杂子查询 | 20 | 子查询在WHERE条件中,子查询语句支持多张表与AND条件表达式,查询条件支持max/min等 | select * from t1 where age in (select id from t2 where t2.name in (select name from t3)) |
排序 | 10 | 支持oder by功能。不指定排序顺序默认为升序(asc)。 不需要支持oder by字段为数字的情况,比如select * from t order by 1; | select * from t,t1 where t.id=t1.id order by t.id asc,t1.score desc; |
分组 | 20 | 支持group by功能。group by中的聚合函数也不要求支持表达式 | select t.id, t.name, avg(t.score),avg(t2.age) from t,t2 where t.id=t2.id group by t.id; |
题目中要求实现一个LRU算法。但是LRU算法有很多种,所以大家可以按照自己的想法来实现。因为不具备统一性,所以不做统一测试。
可以考虑后期,评出排名后,再检查算法实现。
基础测试是隐藏的测试case,是代码本身就有的功能,比如创建表、插入数据等。如果选手把原生仓库代码提交上去,就能够测试通过basic。
这个测试对应了“元数据校验”。选手们应该先做这个case。
常见测试失败场景有一个是 where 条件校验时 server core了。
目前遇到最多的失败情况是没有校验元数据,比如表删除后,再执行select,按照“元数据校验”规则,应该返回”FAILURE”。
date测试需要注意校验日期有效性。比如输入”2021-2-31”,一个非法的日期,应该返回”FAILURE”。
date不需要考虑和string(char)做对比。比如 select * from t where d > ‘123’; select * from t where d < ‘abc’;
不会测试这种场景。但是需要考虑日期与日期的比较,比如select * from t where d > ‘2021-01-21’;
。
date也不会用来计算平均值。
select * form t where d=’2021-02-30‘;
这种场景在mysql下面是返回空数据集,但是我们现在约定都返回 FAILURE。
温馨提示:date 可以使用整数存储,简化处理
按照输出要求,浮点数最多保留两位小数,并且去掉多余的0。目前没有直接的接口能够输出这种格式。比如 printf(“%.2f”, f); 会输出 1.00,printf(“%g”, f); 虽然会删除多余的0,但是数据比较大或者小数位比较多时展示结果也不符合要求。
比如 create table t(a int, b float); 在当前的实现代码中,是不支持insert into t values(1,1); 这种做法的,因为1是整数,而字段b
是浮点数。那么,我们在比赛中,也不需要考虑这两种转换。
但是有一种例外情况,比如聚合函数运算:select avg(a) from t;
,需要考虑整数运算出来结果,是一个浮点数。
update 也要考虑元数据校验,比如更新不存在的表、更新不存在的字段等。
需要考虑不能转换的数据类型更新,比如用字符串更新整型字段。
对于整数与浮点数之间的转换,不做考察。学有余力的同学,可以做一下。
更新需要考虑的几个场景,如果这个case没有过,可以对比一下:
假设存在这个表:
create table t (id int, name char, col1 int, col2 int);
表上有个索引
create index i_id on t (id);
– 单行更新
update t set name=’abc’ where id=1;
– 多行更新
update t set name=’a’ where col1>2;
– 假设where条件能查出来多条数据
– 更新索引
update t set id=4 where name=’c’;
– 全表更新
update t set col1=100;
– where 条件有多个
update t set name=’abc’ where col1=0 and col2=0;
一些异常场景:
- 更新不存在的表
- 更新不存在的字段
- 查询条件中包含不合法的字段
- 查询条件查出来的数据集合是空(应该什么都不做,返回成功)
- 使用无法转换的类型更新某个字段,比如使用字符串更新整型字段
多表查询的输入SQL,只要是字段,都会带表名。比如不会存在 select id from t1,t2;
不带字段名称的场景(会测试):select * from t1,t2;
带字段:select t1.id, t1.age, t2.name from t1,t2 where t1.id=t2.id;
或者:select t1.* , t2.name from t1,t2 where t1.id=t2.id;
多表查询,查询出来单个字段时,也需要加上表名字。原始代码中,会把表名给删除掉。比如select t1.id from t1,t2; 应该输出列名: t1.id。这里需要调整原始代码。输出列名的规则是:单表查询不带表名,多表查询带表名。
不要仅仅使用最简单的笛卡尔积运算,否则可能会内存不足。
不需要考虑聚合字段与普通字段同时出现的场景。比如: select id, count(1) from t1;
必做题中的聚合运算只需要考虑单张表的情况。
字符串可以不考虑AVG运算。
最少需要考虑的场景:
假设有一张表
create table t(id int, name char, price float);
select count(*) from t;
select count(id) from t;
select min(id) from t;
select min(name) from t; – 字符串
select max(id) from t;
select max(name) from t;
select avg(id) from t; – 整数做AVG运算,输出可能是浮点数,所以要注意浮点数输出格式
select avg(price) from t;
select avg(price), max(id), max(name) from t;
还需要考虑一些异常场景:
select count(*,id) from t;
select count() from t;
select count(not_exists_col) from t;
NULL的测试case描述的太过简单,这里做一下补充说明。 NULL的功能在设计时,参考了mariadb的做法。包括NULL的比较规则:任何
值与NULL做对比,结果都是FALSE。
因为miniob的特殊性,字段默认都是不能作为NULL的,所以这个测试用例中,要求增加关键字nullable
,表示字段可以是NULL。
需要考虑的场景
- 建表
create table t(id int, num int nullable, birthday date nullable);
表示创建一个表t,字段num和birthday可以是NULL, 而id不能是NULL。
建索引 create index i_num on t(num);
支持在可以为NULL的字段上建索引
需要支持增删改查
insert into t values(1, 2, '2020-01-01');
insert into t values(1, null, null);
insert into t values(1, null, '2020-02-02'); -- 同学们自己多考虑几种场景
insert into t values(null, 1, '2020-01-02'); -- 应该返回FAILURE,因为ID不能是NULL
select * from t; -- 全表遍历
-- null 条件查询,同学们自己多测试几种场景
select * from t where id is null;
select * from t where id is not null;
select * from t where num is null;
select * from t where num > null;
select * from t where num <> null;
select * from t where 1=null;
select * from t where 'a'=null;
select * from t where null = null;
select * from t where null is null; -- 注意 = 与 is 的区别
select * from t where '2020-01-31' is null;
不要忘记多表查询
聚合
select count(*) from t;
select count(num) from t;
select avg(num) from t;
字段值是NULL时,比较特殊,不需要统计在内。如果是AVG,不会增加统计行数,也不需要默认值。
miniob设计的目标是让不熟悉数据库设计和实现的同学能够快速的了解与深入学习数据库内核,期望通过miniob相关训练之后,能够对各个数据库内核模块的功能与它们之间的关联有所了解,并能够在使用时,设计出高效的SQL。面向的对象主要是在校学生,并且诸多模块做了简化,比如不考虑并发操作。
注意:此代码仅供学习使用,不考虑任何安全特性。
NOTE: miniob代码本身可以在Linux/MacOS上编译测试。
后台测试环境说明:
操作系统:Linux version 4.19.91-23.al7.x86_64
编译器:gcc-8.3.0 (使用clang的同学注意,编译结果可能与gcc稍有不同)
cmake: 3.20.52
make: GNU Make 3.82