CMU 15-445(Fall 2023) Project3 Query Execution个人笔记
Task #1 - Access Method Executors#
SeqScan算子#
实现逻辑
- 使用
exec_ctx
属性获取对应的TableInfo - 调用
MakeIterator
方法,获取表的迭代器 - 在Next方法中,每次利用迭代器获得一个满足条件的元组(检查元组是否被删除、元组是否满足filter)
Insert算子#
实现逻辑
- 在Next方法中调用
child_executor_->Next
获取要插入的元组 - 使用TableHeap类的InsertTuple方法插入元组
- 插入索引
插入索引示例
i->index_->InsertEntry(child_tuple.KeyFromTuple(table->schema_, i->key_schema_, i->index_->GetKeyAttrs()),
new_rid.value(), nullptr);
Update算子#
实现逻辑
- 在Next方法中调用
child_executor_->Next
获取要更新的元组 - 利用TableHeap类的UpdateTupleMeta方法,将对应元组标记为删除
- 删除对应的索引
- 对旧的元组执行
plan_->target_expressions_
中所有表达式,获取更新后的元组 - 插入元组以及索引
Delete算子#
实现逻辑
- 在Next方法中调用
child_executor_->Next
获取要删除的元组 - 利用TableHeap类的UpdateTupleMeta方法,将对应元组标记为删除
- 删除对应的索引
SeqScan优化为IndexScan#
- 当计划类型为PlanType::SeqScan,尝试进行优化
- 遍历filter_predicate_中的表达式,当满足有且只有一个索引时,构造
IndexScanPlanNode
并且返回
IndexScan算子#
- 获取哈希表
htable_ = dynamic_cast<HashTableIndexForTwoIntegerColumn *>(index_info_->index_.get())
- 利用
ScanKey
方法获取对应的元素即可
Task #2 - Aggregation & Join Executors#
Aggregation算子#
和之前的算子不同,Aggregation算子的核心流程在Init
方法中完成,而Next
方法仅用于返回结果
- 利用
child_executor_->Next
方法遍历所有元组 - 对于每一个元组,利用
InsertCombine
方法将其插入到哈希表中,项目中已经提供好了MakeAggregateKey
和MakeAggregateValue
将元组转换为InsertCombine方法的参数
CombineAggregateValues方法实现思路#
// 方法定义
void CombineAggregateValues(AggregateValue *result, const AggregateValue &input);
result参数代表最终的聚合结果,input参数代表新到的一个参与聚合的元组,要根据聚合函数以及input的值动态的修改result中的值
例如聚合函数为AggregationType::CountStarAggregat
,则每执行一次CombineAggregateValues
方法,result
中的值就应该加一
NestedLoopJoin算子#
NestedLoopJoin算子也应当在Init
方法中就处理完逻辑,Next
方法仅做结果的返回
- 将左侧执行器和右侧执行器的结果保存到两个vector中
- 使用一个两层嵌套循环,将满足
plan_->predicate_->EvaluateJoin
的元组保存到结果集合中即可 - 对于left join,当遍历完右侧所有元组仍然没有满足条件的元组时,需要构造空值添加进结果集
空值构造:
res.push_back(ValueFactory::GetNullValueByType(c.GetType()));
Task #3 - HashJoin Executor and Optimization#
HashJoin算子#
- 模仿项目中的
SimpleAggregationHashTable
构造一个用于Hash Join的SimpleHashJoinHashTable
- 获取左右子节点的结果集,并利用右子节点的结果集构造哈希表
- 遍历左子节点结果集,对于每一个元组查找哈希表并尝试进行连接即可
NestedLoopJoin优化为HashJoin#
- 当计划类型为
PlanType::NestedLoopJoin
时,尝试进行优化 - 只有当连接条件是一个或者多个等值连接时,才应当进行优化
- 这里的条件表达式有两种情况,一是
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类提供了CompareEquals
、CompareLessThan
、CompareGreaterThan
等方法用于比较两个值
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#
- 利用
child_executor_->Next
获取所有元组并且保存 - 实验保证了如果有排序字段,所有窗口的排序字段是相同的,那么构造一个
SortExecutor
,将上一步的结果集进行排序 - 遍历所有的窗口函数,对于每个窗口函数,构造
AggregationExecutor
,计算每个窗口中的结果 - 将所有窗口的结果集进行组合,构造符合输出模式的元组集合
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」