CMU15-445 Lab3记录

Task 1 Excutors

这次lab介绍非常非常长,要完成9个executors,有sequential scan, insert, update, delete, neted loop join, hash join, aggregation, limit, distinct,每一个种query plan都有init next方法,init是用来初始化的,next是提供给调用者一个tuple和对应的RID
每一个excutor都负责执行一个plan node type。plan node是一个query plan的单独模组。每个plan node可能定义了一个operator需要的特定的信息。
Executors 接受来自子节点的tuples,然后处理后把这些tuples给parent。可能executors依赖children的顺序(?)
本次实验并不需要保证是并发安全的。
project提供了一个ExecutionEnginehelper class,它将input query转化为一个query excutor,然后执行这个excutor。我们需要修改ExecutionEngine来捕获异常。
ExecutorFactor是负责在执行query exection时创建excutors的,每个executor都会在执行的时候访问ExcutorContext
当实现类似insert, update之类的修改类型的函数的时候,需要保证index的一致性,所以这些executors选哟去更新修改表的所有index。可以使用上次实现的extendible hash table来作为index的数据结构

Sequential Scan

这个较为简单,只需要从exec_ctx_中获取table中有关tuple的迭代器,遍历这个迭代器,然后根据plan中的GetPredicate,判断当且遍历到的tuple是否符合查询的条件,如果符合,那么就将tuple转换成plan中的格式,最后赋值给*tuple即可

1
2
3
4
5
6
std::vector<Value> values;
values.reserve(plan_->OutputSchema()->GetColumnCount());
for (const auto &col : plan_->OutputSchema()->GetColumns()) {
values.push_back(
col.GetExpr()->Evaluate(&(*ptr_), &exec_ctx_->GetCatalog()->GetTable(plan_->GetTableOid())->schema_));
}

Insert/Delete/Update

这三个大同小异,通过child plan或者从plan中获取的tuple,使用tableheap中的insert/delete更改表中的tuple,最后更新index中的信息。

1
2
3
4
5
6
std::vector<IndexInfo *> index_info_array =
exec_ctx_->GetCatalog()->GetTableIndexes(exec_ctx_->GetCatalog()->GetTable(plan_->TableOid())->name_);
for (auto &index_info : index_info_array) {
index_info->index_->InsertEntry(tuple->KeyFromTuple(exec_ctx_->GetCatalog()->GetTable(plan_->TableOid())->schema_,
index_info->key_schema_, index_info->index_->GetKeyAttrs()),
*rid, exec_ctx_->GetTransaction());

nested loop join

通过双重循环,判断left tuple和right tuple是否符合plan中的条件即可, 如果符合,通过col中的evaluatejoin来将left tuple和right tuple join起来

1
2
3
4
5
6
7
if (join_predicate_ == nullptr ||
join_predicate_->EvaluateJoin(&outer_tuple_, left_schema_, &inner_tuple_, right_schema_).GetAs<bool>()) {
std::vector<Value> values;
values.reserve(GetOutputSchema()->GetColumnCount());
for (const auto &col : GetOutputSchema()->GetColumns()) {
values.push_back(col.GetExpr()->EvaluateJoin(&outer_tuple_, left_schema_, &inner_tuple_, right_schema_));
}

hash join

这个需要参考aggregation来写一个hash table,key为tuple经过left plan转成的对应Value,value为vecotr<Tuple>,因为可能多个tuple对应了一个key,之后遍历right tuple,去看table对应的tuple(可能有多个),最后调用EvaluateJoin即可。

aggregation

这个核心代码都实现好了,只需要在init的时候构建对应的table即可。

1
2
3
while (child_->Next(&tuple, &rid)) {
aht_.InsertCombine(MakeAggregateKey(&tuple), MakeAggregateValue(&tuple));
}

然后在Next,如果没有having子语句或者符合having,那么返回迭代器当前指向的值就可以了。

1
2
3
4
5
6
7
8
9
10
11
12
while (
aht_iterator_ != aht_.End() &&
!have_node->EvaluateAggregate(aht_iterator_.Key().group_bys_, aht_iterator_.Val().aggregates_).GetAs<bool>()) {
++aht_iterator_;
}
if (aht_iterator_ == aht_.End()) {
return false;
}
for (auto &col : plan_->OutputSchema()->GetColumns()) {
values.push_back(
col.GetExpr()->EvaluateAggregate(aht_iterator_.Key().group_bys_, aht_iterator_.Val().aggregates_));
}

distinct和limit

这两个很简单,就不记录了

作者

xiaomaotou31

发布于

2022-05-15

更新于

2022-07-03

许可协议

评论