Skip to content

Commit aed05f9

Browse files
committed
C on Agg
1 parent 56b2b2b commit aed05f9

File tree

4 files changed

+59
-0
lines changed

4 files changed

+59
-0
lines changed

src/backend/executor/execExprInterp.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1738,6 +1738,11 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
17381738

17391739
EEO_CASE(EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYVAL)
17401740
{
1741+
/**
1742+
aggstate 是聚合操作的全局状态,包含所有聚合相关的信息。
1743+
pertrans 表示当前聚合函数的转换状态定义,包括是否按值传递(transtypeByVal)。
1744+
pergroup 是当前组的聚合状态,存储每组的中间结果。
1745+
*/
17411746
AggState *aggstate = castNode(AggState, state->parent);
17421747
AggStatePerTrans pertrans = op->d.agg_trans.pertrans;
17431748
AggStatePerGroup pergroup =

src/backend/executor/nodeAgg.c

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,7 @@
330330
*/
331331
typedef struct HashAggSpill
332332
{
333+
// npartitions: 表示分区的数量。溢出的数据被划分为多个分区,每个分区对应一个磁盘文件。
333334
int npartitions; /* number of partitions */
334335
LogicalTape **partitions; /* spill partition tapes */
335336
int64 *ntuples; /* number of tuples in each partition */
@@ -2141,6 +2142,21 @@ lookup_hash_entries(AggState *aggstate)
21412142
}
21422143
}
21432144

2145+
/**
2146+
ExecAgg 的主要职责是根据聚合策略处理输入数据并生成聚合结果:
2147+
- 分组聚合: 如果查询包含分组键(如 GROUP BY),函数会为每个分组生成一个结果元组。
2148+
- 全局聚合: 如果查询没有分组键,函数会对整个输入数据生成一个结果元组。
2149+
2150+
NB: 无论是哪种聚合方式,聚合结果都会存储在表达式上下文中,
2151+
以便后续调用 ExecProject生成最终的输出元组并存储到slot中。
2152+
2153+
#0 ExecProject (projInfo=0xb9bc3e38c9d0) at ../../../src/include/executor/executor.h:363
2154+
#1 0x0000b9bc2b0dc79c in project_aggregates (aggstate=aggstate@entry=0xb9bc3e38bbe0) at nodeAgg.c:1385
2155+
#2 0x0000b9bc2b0de5f8 in agg_retrieve_hash_table_in_memory (aggstate=aggstate@entry=0xb9bc3e38bbe0) at nodeAgg.c:2878
2156+
#3 0x0000b9bc2b0dfdd0 in agg_retrieve_hash_table (aggstate=aggstate@entry=0xb9bc3e38bbe0) at nodeAgg.c:2752
2157+
#4 0x0000b9bc2b0e02dc in ExecAgg (pstate=<optimized out>) at nodeAgg.c:2175
2158+
2159+
*/
21442160
/*
21452161
* ExecAgg -
21462162
*
@@ -2170,7 +2186,12 @@ ExecAgg(PlanState *pstate)
21702186
case AGG_HASHED:
21712187
if (!node->table_filled)
21722188
agg_fill_hash_table(node);
2189+
21732190
/* FALLTHROUGH */
2191+
/**
2192+
AGG_MIXED: 混合聚合策略,同时使用排序和哈希表。
2193+
这种策略通常在输入数据的特性较复杂时使用,例如部分数据适合排序聚合,而另一部分数据适合哈希聚合。
2194+
*/
21742195
case AGG_MIXED:
21752196
result = agg_retrieve_hash_table(node);
21762197
break;
@@ -2180,6 +2201,7 @@ ExecAgg(PlanState *pstate)
21802201
break;
21812202
}
21822203

2204+
// 通过slot每次返回一个Agg结果元组(TTSVirtual类型):如TPCHQ1那就是4个结果元组
21832205
if (!TupIsNull(result))
21842206
return result;
21852207
}
@@ -2533,6 +2555,12 @@ agg_retrieve_direct(AggState *aggstate)
25332555
return NULL;
25342556
}
25352557

2558+
/**
2559+
它从外部计划节点获取输入元组,将这些元组插入哈希表中,并对聚合函数进行更新。
2560+
最终,它标记哈希表已填充完毕,并初始化哈希表的迭代器以供后续操作。
2561+
2562+
代码设计注重内存管理(通过上下文重置)和性能优化(通过哈希表操作和溢出处理)
2563+
*/
25362564
/*
25372565
* ExecAgg for hashed case: read input and build hash table
25382566
*/
@@ -2763,6 +2791,11 @@ agg_retrieve_hash_table(AggState *aggstate)
27632791
return result;
27642792
}
27652793

2794+
/**
2795+
这段代码实现了 agg_retrieve_hash_table 函数,用于从哈希表中检索聚合组(groups)。
2796+
它是哈希聚合(hashed aggregation)执行过程中的关键部分,
2797+
负责*逐步*返回聚合结果,直到所有内存中的和溢出到磁盘的元组都被处理完毕.
2798+
*/
27662799
/*
27672800
* Retrieve the groups from the in-memory hash tables without considering any
27682801
* spilled tuples.
@@ -2787,6 +2820,11 @@ agg_retrieve_hash_table_in_memory(AggState *aggstate)
27872820
peragg = aggstate->peragg;
27882821
firstSlot = aggstate->ss.ss_ScanTupleSlot;
27892822

2823+
/**
2824+
aggstate->current_set: 表示当前正在处理的分组集的索引。
2825+
分组集是 SQL 查询中 GROUP BY 子句的扩展形式,所以这个函数是带着状态的。
2826+
应该是通过select_current_set函数设置的。
2827+
*/
27902828
/*
27912829
* Note that perhash (and therefore anything accessed through it) can
27922830
* change inside the loop, as we change between grouping sets.

src/include/executor/executor.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,10 @@ ExecEvalExpr(ExprState *state,
343343
*
344344
* Same as ExecEvalExpr, but get into the right allocation context explicitly.
345345
*/
346+
/**
347+
ExprState *state: 表示要评估的表达式状态,包含表达式的执行计划和相关元信息。
348+
ExprContext *econtext: 提供表达式评估所需的上下文信息,例如当前元组和参数值。
349+
*/
346350
#ifndef FRONTEND
347351
static inline Datum
348352
ExecEvalExprSwitchContext(ExprState *state,

src/include/nodes/execnodes.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,11 @@ typedef struct ExprState
110110
/* original expression tree, for debugging only */
111111
Expr *expr;
112112

113+
/**
114+
evalfunc_private 用于存储与 evalfunc 相关的私有状态或上下文信息。
115+
它为 evalfunc 提供辅助数据,例如缓存、优化信息或其他运行时元数据。
116+
具体内容由 evalfunc 的实现决定,不同的求值函数可能需要不同的私有数据。
117+
*/
113118
/* private state for an evalfunc */
114119
void *evalfunc_private;
115120

@@ -2456,6 +2461,13 @@ typedef struct SharedAggInfo
24562461
* ---------------------
24572462
*/
24582463
/* these structs are private in nodeAgg.c: */
2464+
/**
2465+
AggStatePerAgg: 指向每个聚合函数的状态数据,可能包括聚合函数的具体实现和相关元信息。
2466+
AggStatePerTrans: 用于管理聚合的过渡状态(transition state),例如 SUM 的累加值或 AVG 的计数器。
2467+
AggStatePerGroup: 存储每个分组的聚合状态,支持 GROUP BY 操作。
2468+
AggStatePerPhase: 用于管理聚合操作的不同阶段(phase),例如分组聚合和哈希聚合的切换。
2469+
AggStatePerHash: 与哈希聚合相关的状态数据,例如哈希表的元信息。
2470+
*/
24592471
typedef struct AggStatePerAggData *AggStatePerAgg;
24602472
typedef struct AggStatePerTransData *AggStatePerTrans;
24612473
typedef struct AggStatePerGroupData *AggStatePerGroup;

0 commit comments

Comments
 (0)