参考内容
PostgreSQL 源码解读(181)- 查询#97(聚合函数#2-ExecInitAgg)
主要做三件事:
- 分配slot并标记类型
- 标记聚合函数用的列
- 为每个scan阶段标记聚合函数并优化
聚合过程会有一个优化:聚合函数之间可能有可共享的情况:
- 共享聚合函数:比如Sum(x)函数对同一列出现两次(下图红色部分)
- 共享聚合中间参数:比如AVG和平方差函数一起出现,平方差用到了avg的结果。(下图橙色部分)
scan的注意点:
- hash只会在第一阶段执行
- sort可能在任何阶段执行
- 如果不做hash,第一阶段就是空的
参考内容
PostgreSQL 源码解读(182)- 查询#98(聚合函数#3-ExecAgg)
PostgreSQL 源码解读(183)- 查询#99(聚合函数#4-ExecAgg)
PostgreSQL 源码解读(186)- 查询#102(聚合函数#7-advance_aggregates)
PostgreSQL 源码解读(189)- 查询#105(聚合函数#10 - agg_retrieve_hash_table)
PostgreSQL 源码解读(190)- 查询#106(聚合函数#11 - finalize_aggregate)
聚合函数的执行部分:
对于hash的情况:
- 创建hash表,并在每步执行 中间步骤 (HASH)
- 对hash表的每个条目(每个set)执行最终聚集函数 (MAX)
具体聚合的执行实际是调用ExecInterpExpr
参考内容
PostgreSQL 源码解读(191)- 查询#107(聚合函数#12 - agg_retrieve_direct)
参考内容
PostgreSQL 源码解读(192)- 查询#108(排序#1 - ExecInitSort)
参考内容
PostgreSQL 源码解读(193)- 查询#109(排序#2 - ExecSort)
PostgreSQL 源码解读(194)- 查询#110(排序#3 - 实现)
PostgreSQL 源码解读(195)- 查询#111(排序#4 - 实现)
PostgreSQL 源码解读(197)- 查询#112(排序#5 - mergeruns)
PostgreSQL 源码解读(198)- 查询#113(排序#6 - Tuplesortstate)
PostgreSQL 源码解读(199)- 查询#114(排序#7 - inittapes&dumptuples)
排序执行会先分tape,对每个tape获取元组,获取满时执行快速排序和刷盘,最后对所有tape执行merge
对有limit限制的情况是使用堆排序实现的
最后的多路归并是使用 Fibonacci 斐波那契外部排序算法:(mergeruns函数)
首先生成序列(例如10个tape)(initapes 与 selectnewtape 函数)
fib = [1,1,1,1,1,1,1,1,1,1,0]
run = [0,0,0,0,0,0,0,0,0,0,0]
dummy = [1,1,1,1,1,1,1,1,1,1,0]
dest = 0
while True:
dummy[dest] -= 1
run[dest] += 1
if dummy[dest] < dummy[dest+1]:
dest += 1
continue
if dummy[dest] != 0:
dest = 0
continue
a = fib[0]
for i in range(10):
dummy[i] = a + fib[i+1] - fib[i]
fib[i] = a + fib[i+1]
dest = 0
其中一次的中间结果是这样
最后的merge是函数中做的
- 每次merge以最后一个位置为结果缓存位置
- 当heap中值都比缓存中的值小时,就把缓存中值插入堆中,取堆顶值入缓存。
- 这一轮完成时,倒数第二个位置会是空的,只要循环移位一下(把输出缓存放在最前面,后面依次移位,则刚才倒数第二位置就变成了输出缓存的位置)
总体流程如下:
参考内容
等号通过大于小于实现
if > {}
else if < {}
else{} // 等于