Loading

CMU 15-445(Fall 2023) Project3 Query Execution个人笔记

Task #1 - Access Method Executors

SeqScan算子

实现逻辑

  1. 使用exec_ctx属性获取对应的TableInfo
  2. 调用MakeIterator方法,获取表的迭代器
  3. 在Next方法中,每次利用迭代器获得一个满足条件的元组(检查元组是否被删除、元组是否满足filter)

Insert算子

实现逻辑

  1. 在Next方法中调用child_executor_->Next获取要插入的元组
  2. 使用TableHeap类的InsertTuple方法插入元组
  3. 插入索引

插入索引示例

i->index_->InsertEntry(child_tuple.KeyFromTuple(table->schema_, i->key_schema_, i->index_->GetKeyAttrs()),
                             new_rid.value(), nullptr);

Update算子

实现逻辑

  1. 在Next方法中调用child_executor_->Next获取要更新的元组
  2. 利用TableHeap类的UpdateTupleMeta方法,将对应元组标记为删除
  3. 删除对应的索引
  4. 对旧的元组执行plan_->target_expressions_中所有表达式,获取更新后的元组
  5. 插入元组以及索引

Delete算子

实现逻辑

  1. 在Next方法中调用child_executor_->Next获取要删除的元组
  2. 利用TableHeap类的UpdateTupleMeta方法,将对应元组标记为删除
  3. 删除对应的索引

SeqScan优化为IndexScan

  1. 当计划类型为PlanType::SeqScan,尝试进行优化
  2. 遍历filter_predicate_中的表达式,当满足有且只有一个索引时,构造IndexScanPlanNode并且返回

IndexScan算子

  1. 获取哈希表
htable_ = dynamic_cast<HashTableIndexForTwoIntegerColumn *>(index_info_->index_.get())
  1. 利用ScanKey方法获取对应的元素即可


Task #2 - Aggregation & Join Executors

Aggregation算子

和之前的算子不同,Aggregation算子的核心流程在Init方法中完成,而Next方法仅用于返回结果

  1. 利用child_executor_->Next方法遍历所有元组
  2. 对于每一个元组,利用InsertCombine方法将其插入到哈希表中,项目中已经提供好了MakeAggregateKeyMakeAggregateValue将元组转换为InsertCombine方法的参数

CombineAggregateValues方法实现思路

// 方法定义
void CombineAggregateValues(AggregateValue *result, const AggregateValue &input);

result参数代表最终的聚合结果,input参数代表新到的一个参与聚合的元组,要根据聚合函数以及input的值动态的修改result中的值

例如聚合函数为AggregationType::CountStarAggregat,则每执行一次CombineAggregateValues方法,result中的值就应该加一

NestedLoopJoin算子

NestedLoopJoin算子也应当在Init方法中就处理完逻辑,Next方法仅做结果的返回

  1. 将左侧执行器和右侧执行器的结果保存到两个vector中
  2. 使用一个两层嵌套循环,将满足plan_->predicate_->EvaluateJoin的元组保存到结果集合中即可
  3. 对于left join,当遍历完右侧所有元组仍然没有满足条件的元组时,需要构造空值添加进结果集

空值构造:

res.push_back(ValueFactory::GetNullValueByType(c.GetType()));



Task #3 - HashJoin Executor and Optimization

HashJoin算子

  1. 模仿项目中的SimpleAggregationHashTable构造一个用于Hash Join的SimpleHashJoinHashTable
  2. 获取左右子节点的结果集,并利用右子节点的结果集构造哈希表
  3. 遍历左子节点结果集,对于每一个元组查找哈希表并尝试进行连接即可

NestedLoopJoin优化为HashJoin

  1. 当计划类型为PlanType::NestedLoopJoin时,尝试进行优化
  2. 只有当连接条件是一个或者多个等值连接时,才应当进行优化
  3. 这里的条件表达式有两种情况,一是LogicType::And,二是ComparisonType::Equal,对于And类型表达式,需要递归的处理其子表达式
// And表达式, 需要递归的处理
if (const auto *expr = dynamic_cast<const LogicExpression *>(nlj_plan.Predicate().get());
    expr != nullptr && expr->logic_type_ == LogicType::And)
// Equal表达式
if (const auto *expr = dynamic_cast<const ComparisonExpression *>(nlj_plan.Predicate().get());
    expr != nullptr && expr->comp_type_ == ComparisonType::Equal)



Task #4: Sort + Limit Executors + Window Functions + Top-N Optimization

Sort算子

使用std::sort实现,Value类提供了CompareEqualsCompareLessThanCompareGreaterThan等方法用于比较两个值

Limit算子

使用一个计数器保存当前返回的元组数量即可

Top-N算子

使用标准库中的优先队列,插入N的元素即可

std::priority_queue<Tuple, std::vector<Tuple>, std::function<bool(const Tuple &, const Tuple &)>> pq(
      [this](const Tuple &a, const Tuple &b) {
        return false;
      });

Window Functions

  1. 利用child_executor_->Next获取所有元组并且保存
  2. 实验保证了如果有排序字段,所有窗口的排序字段是相同的,那么构造一个SortExecutor,将上一步的结果集进行排序
  3. 遍历所有的窗口函数,对于每个窗口函数,构造AggregationExecutor,计算每个窗口中的结果
  4. 将所有窗口的结果集进行组合,构造符合输出模式的元组集合

Leaderboard暂未实现

通过截图

posted @ 2024-02-18 20:44  焚风  阅读(363)  评论(4编辑  收藏  举报