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 @   焚风  阅读(1016)  评论(4编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」
主题色彩
点击右上角即可分享
微信分享提示