execution函数入口。
参数为:
1、执行计划的指针(来自Plan和Optimizer)
2、vector存放提取的数据
3、事务
4、执行器上下文
execution调用入口:
while函数不断调用Next,将数据存储在vector中。这里的executor是一个基类指针,会自动根据executor类型调用不同算子的Next的函数。
seq_scan_executor
我们只需要拿到table_info,就可以拿到第一个page的迭代器,取一个数据把迭代器++,知道迭代器到达end()。
注意这里的迭代器如果到了一个page的末尾会进入到下一个page的头部。
auto SeqScanExecutor::Next(Tuple *tuple, RID *rid) -> bool {
if (table_iterator_ != table_info_->table_->End()) {
*tuple = *table_iterator_;
*rid = table_iterator_->GetRid();
++table_iterator_;
return true;
}
return false;
}
insert_sacn_executor
插入的时候还需考虑表是否建有索引,若有索引还得同步更新索引信息。所以在Init阶段去拿table和索引信息,在Next阶段调用TableHeap的InsertTuple新增tuple;若有索引信息,调用上一个projcet实现的InsertEntryt添加索引信息。
DeleteExecutor
和插入类似,在Init阶段拿table和索引信息,在Next阶段调用TableHeap的MarkDelete删除tuple和调用DeleteEntry删除索引信息。
Index_scan_executor
类似于seq_scan,也是用迭代器遍历,只是这里索引迭代器拿到的是rid,并不是真实要的数据。还需要GetTuple从表中拿到数据再返回。
auto IndexScanExecutor::Next(Tuple *tuple, RID *rid) -> bool {
if(iterator_ != index_->GetEndIterator()) {
*rid = (*iterator_).second;
if(table_info_->table_->GetTuple(*rid, tuple, exec_ctx_->GetTransaction())){
++iterator_;
return true;
}
}
return false;
}
Aggregation_executor
聚合实现的是分组(group by),聚集(count*,count列,min,max,sum)
聚合的模式是先分组列,再聚合列。实现聚合的策略是哈希表,涉及到SimpleAggregationHashTable,需要先实现SimpleAggregationHashTable中的CombineAggregateValues函数。
例如下表:
如选择按等级进行分组,则aggregate_key为等级这一列,aggregate_value为姓名和年龄这两列。
InsertCombine会先给aggregate_key生成初始值,初始值规则为若是count*,则为0,若是其他则为NULL。注意调用CombineAggregateValues并没有使用agg_key,而是使用agg_key对应的内容(参数1)
CombineAggregateValues函数:
参数1为已经存在的聚集内容,参数2为新加入的数据。
例如我们在InsertCombine已经插入等级上中的[张三,18],在插入[张麻子,45]时,result为[张三,18]对应的数据(Value可能存的的是一个int,如count*,根据聚合类型所表现的Value不同),input为[张麻子,45]
根据聚集类型,选择对应的处理方式,如count*则是每次插入就将结果+1,需要调用Value的Add函数。
Next函数
next函数就是从哈希表的begin()迭代器开始遍历到end,每次输出一行数据
1、先把分组的数据全部放进vector
2.再把聚集的数据放入vector
再++迭代器即可
注意:如果是空表,即迭代器为end时,则count*返回0,其他都返回NULL
nested_loop_join_executor
select * from a,b where a.id=b.id
嵌套循环链接,实现思路很简单,就是两个循环,用B表的id号依次去匹配A表的id,若能匹配上则合并这一行。
要分为左连接和内连接,左连接如果A表的id号在B表中没有,也要保留这一行,将B表的部分设为NULL。而内连接若没匹配上则不管。
实现方式:因为next只能调一次,所以在init中先用右表调next把数据存在vector中
Next函数:左表去遍历右表进行匹配,注意可能会有多行成功匹配,此时不能在第一个匹配上就返回,所以设置了index来表示本次遍历到右边的哪一行。index为0时先用next进行第一个符合条件的行的匹配,若匹配到则更新index,还需要从index开始继续往下找,直到把右表找完。
nested_index_join_executor
和嵌套循环连接类似,只是采用索引来进行匹配,不需要遍历,提升了性能。也要分左连接和内连接讨论
sort_executor
Init里把所有数据读完自定义排序就行,Next函数直接一个个输出即可
升序则return a<b,降序 return a>b
limit_executor
最简单的,就next里吐limit个数据就行
topN_executor
方法1:sort加limit
方法2:优先级队列实现topN
topN算法:假设要最小的N个数,则搞一个大顶堆,维护大顶堆的size为n,一旦超过N,则弹出堆顶元素,直到所有元素都遍历完,堆里剩下的元素就为最后N个元素。