前言
在文章的开始作者为大家整理了很多资料!包括java核心知识点+全套架构师学习资料和视频+一线大厂面试宝典+面试简历模板+阿里美团网易腾讯小米爱奇艺快手哔哩哔哩面试题+Spring源码合集+Java架构实战电子书等等!
在此声明分享资料只为帮助到更多人,大家点击这里直接下载就好,下载码:csdn
笔者在源码笔记1之中分析过ClickHouse的聚合函数的实现,但是对于各个接口函数的实际如何共同工作的源码,回头看并没有那么明晰,主要原因是没有结合Aggregator的类来一起分析聚合函数的是如果工作起来的。所以决定重新再完成一篇聚合函数的源码梳理的文章,帮助大家进一步的理解ClickHouse之中聚合函数的工作原理。
本系列文章的源码分析基于ClickHouse v19.16.2.2的版本。
1.IAggregateFunction接口梳理
话不多说,直接上代码,笔者这里会将所有聚合函数的核心接口代码全部列出,一一梳理各个部分:
构造函数
IAggregateFunction(const DataTypes & argument_types_, const Array & parameters_)
: argument_types(argument_types_), parameters(parameters_) {}
上面的代码实现了IAggregateFunction
接口的构造函数,初始化了该接口的两个成员变量:
argument_type
:函数的参数类型,比如函数select sum(a), sum(b), c from test group by c
, 这里a
,b
分别是UInt16类型与Double类型,那么这个sum(a)
与sum(b)
的参数就不同。parameters
: 参数,实际类型为std::vector<Field>
。它代表着函数的除了数据的输入参数之外的其他参数。比如聚合函数topk
,其中需要传入的k
的值就在parameters
之中。
内存分配接口
在Clickhouse的聚合执行过程之中,所有的聚合函数都是通过列来进行的。而这里有两个重要的问题:
- 列内存从哪里分配
- 分配的内存结构,长度是如何的
笔者在梳理下面代码的过程之中给出解答,
/** Create empty data for aggregation with `placement new` at the specified location.
* You will have to destroy them using the `destroy` method.
*/
virtual void create(AggregateDataPtr place) const = 0;
/// Delete data for aggregation.
virtual void destroy(AggregateDataPtr place) const noexcept = 0;
IAggregateFunction
定义的两个接口create
与destory
接口完成了内存结构与长度的确定,这里可能描述的不是很明白,这里了解Doris聚合实现的同学可以这样理解。create
函数本身就是完成了Doris聚合函数之中init
函数所完成的工作。这里通过子类IAggregateFunctionDataHelper
的实现代码来进一步理解它做了什么事情:
void create(AggregateDataPtr place) const override
{
new (place) Data;
}
void destroy(AggregateDataPtr place) const noexcept override
{
data(place).~Data();
}
这部分代码很简单,Data
就是模板派生的类型,然后通过placement new
与placement delete
的方式完成了Data
类型的构造与析构。而这个Data
类型就是聚合函数存储中间结果的类型,比如sum
的聚合