用户指南

指标

师成师成· 更新于 2026-09-28· 阅读 16 分钟· 0 次阅读

登录后可跨设备保存划线和私人笔记登录

指标

DataFusion 算子会暴露运行时指标,帮助你了解时间消耗在哪里,以及有多少数据流经整个管道。更多信息请参阅 EXPLAIN ANALYZE。

通用指标

BaselineMetrics

大多数物理算子都提供 BaselineMetrics,用于采集常用的度量数据。

指标说明
elapsed_compute算子主动处理工作所消耗的 CPU 时间。
output_rows算子产生的总行数。
output_bytes所有输出批次的内存占用。注意:该值可能会被高估。如果多个输出 RecordBatch 实例共享底层内存缓冲区,它们的大小会被重复计算多次。
output_batches算子产生的输出批次总数。

算子专用指标

FilterExec

指标说明
selectivity过滤器的选择率,计算方式为 output_rows / input_rows

HashJoinExec

HashJoinExec 同样暴露通用的 BaselineMetrics。它的 elapsed_compute 指标等于构建端收集时间与后续连接处理时间之和。

指标说明
build_time收集并构建连接构建侧(build side)所花费的总时间。
build_input_batches从构建侧消耗的输入批次数。
build_input_rows从构建侧消耗的输入行数。
build_mem_used构建侧跟踪到的峰值内存使用量,单位为字节。
join_time构建侧收集完成后,处理连接所花费的总时间。
input_batches从探测侧(probe side)消耗的输入批次数。
input_rows从探测侧消耗的输入行数。
probe_hit_rate在应用任何连接过滤条件之前,探测侧行中能在构建侧找到连接键匹配的行所占比例。
avg_fanout在应用任何连接过滤条件之前,每条匹配的探测侧行平均对应的构建侧连接键匹配数。
array_map_created_countHashJoinExec 为完美哈希连接查找执行创建 ArrayMap 的次数。

AggregateExec

AggregateExec 会暴露通用的 BaselineMetrics、下述算子级指标,以及每个聚合表达式和执行阶段对应的一个计时器。

指标说明
time_calculating_group_ids准备分组键所花费的时间;关于特定路径的覆盖范围,请参见下方说明。
aggregate_arguments_time计算聚合函数输入所花费的总时间。agg_expr_{index}_arguments_time 会按表达式进一步拆分这一耗时。
aggregation_time调用累加器 update 和 merge 操作所花费的时间。
emitting_time物化分组值以及累加器 state 或 evaluate 结果所花费的时间。
topk_maintenance_time维护 Grouped TopK 优先级映射所花费的时间,包括批次准备、插入、比较和 NULL 处理。
skipped_aggregation_rows当跳过部分聚合时,未经聚合直接透传的输入行数。
reduction_factor部分聚合每消费一行所产生的输出行数,以 66.67% (2/3) 形式显示。
spill_count聚合超出内存预算时写入的溢写文件数量。
spilled_bytes写入溢写文件的总字节数。
spilled_rows写入溢写文件的总行数。
peak_mem_used分组聚合跟踪到的峰值内存占用(以字节计);仅由回退分组哈希路径记录。

这些算子级指标仅由分组聚合路径记录:没有 GROUP BY 的 AggregateExec 只会上报 BaselineMetrics 和各聚合表达式的计时器。reduction_factor 和 skipped_aggregation_rows 仅在部分聚合模式下记录。skipped_aggregation_rows 仅在满足以下条件时记录:启用了部分聚合跳过、GROUP BY 为单一分组且不包含分组集(grouping sets)、并且其输入未按分组表达式排序;将 datafusion.execution.skip_partial_aggregation_probe_ratio_threshold 设置为 >= 1.0 可禁用该功能。

time_calculating_group_ids 涵盖分组表达式求值以及将结果行解析为组 ID 的过程,包括驻留(interning)和排序初始化。aggregation_time 仅涵盖累加器的 update 与 merge 调用。在基于累加器的分组聚合路径上,state 和 evaluate 被计入 emitting_time,包括部分聚合在内存压力下物化状态的情况。对于没有 GROUP BY 的 AggregateExec,每个聚合的 state 和 evaluate 计时器会记录在 elapsed_compute 中;它不会报告 emitting_time 这类分组算子指标。跳过聚合的部分聚合会针对这些行报告 convert_to_state 而非 aggregation_time。

当针对带限额的分组聚合选择了特化的 Grouped TopK 路径时,它没有累加器。其分组键表达式求值被计入 time_calculating_group_ids,优先级映射相关工作由 topk_maintenance_time 报告;它不会报告累加器阶段指标。规划器的选择取决于查询形态:不带排序要求的带限额 DISTINCT 查询会改用常规聚合路径。

每个聚合的计时器命名为 agg_expr_{index}_{phase}_time,其中 index 是聚合表达式在算子中的从零开始的位置,phase 为以下之一:

阶段说明
arguments将聚合的参数表达式求值为输入数组。
update使用原始输入值更新累加器。
merge合并部分累加器状态。
state获取累加器的中间状态,用于部分输出或聚合溢写。
convert_to_state跳过常规累加器更新,将原始聚合输入直接转换为部分状态。
evaluate将累加器求值为其最终结果。

例如,当规划了部分阶段时,SELECT SUM(a), SUM(b) FROM t 对应的部分 AggregateExec 会为 SUM(a) 报告 agg_expr_0_arguments_time 和 agg_expr_0_update_time,为 SUM(b) 报告 agg_expr_1_arguments_time 和 agg_expr_1_update_time。该索引是按位置确定的,对应算子计划行上打印的 aggr=[...] 列表中的相同位置,这正是带索引的计时器映射回聚合表达式的方式。由于索引是指标名称的一部分,因此在合并各分区指标时,作用于不同列的相同函数依然保持可区分。

每个聚合计时器还带有一个 aggregate 标签,其值为渲染后的聚合表达式(例如 sum(t.a))。跨分区合并指标时会丢弃标签,因此该标签仅出现在 EXPLAIN ANALYZE VERBOSE 的“Plan with Full Metrics”部分,该部分按分区报告指标。

arguments 在所有模式下都会记录。所记录的累加器阶段取决于聚合模式和实现。对于非分组聚合,partial 模式记录 update 和 state,partial reduce 模式记录 merge 和 state,final 模式记录 merge 和 evaluate,single 模式记录 update 和 evaluate。哈希聚合在 partial 模式下使用 update、state 和 convert_to_state;在 partial-reduce 模式下使用 merge 和 state;在 final 模式下使用 merge、state 和 evaluate;在 single 模式下使用 update、state、merge 和 evaluate。其 state 计时器测量中间状态的输出耗时,包括溢写(spilling)期间的耗时。分组 TopK 聚合路径只记录每个聚合的 arguments 计时器,因为它直接维护值,而不使用累加器。

当聚合带有 FILTER 子句时,其求值耗时会计入 aggregate_arguments_time。如果过滤器是按每个聚合分别求值的,那么每个聚合的 arguments 计时器会包含过滤器的耗时。传统的分组哈希路径会统一求值过滤器,因此其每个聚合的 arguments 计时器只涵盖参数表达式;这些计时器的总和不一定等于 aggregate_arguments_time。

聚合实现还可以暴露可选的内部子指标。它们使用 agg_expr_{index}_internal_{subphase}_time 命名和 aggregate 标签。internal 段使它们与调用边界计时器区分开来;subphase 是由聚合实现拥有并记录的稳定标识符。这些子指标仅在聚合请求时才会惰性注册,因此没有内部子指标的聚合不会增加任何指标。注册按(聚合表达式索引、subphase、分区)进行:该分区中的替换累加器共享同一个耗时,而常规的指标展示会将该耗时跨分区合并。聚合可以在构造累加器时请求其子指标,因此即使输入为空,该子指标也可能出现。例如,array_agg(DISTINCT ...) 会将输入值去重所花费的时间记录为 agg_expr_{index}_internal_distinct_time。分组累加按每个输入批次记录一次,而不是按每个分组记录一次,以避免使指标采集开销与分组基数成正比。这些子指标是对 update、merge、state 和 evaluate 计时器的补充,而不是对它们的细分或替代。因此,内部子指标可能与其所属阶段的计时器重叠;它是一种补充性的诊断信息,不得作为分解结果累加到阶段耗时中。

除了 Summary 指标 reduction_factor 之外,这些算子级指标和各个聚合指标都属于 Dev 指标。当 datafusion.explain.analyze_level 包含 Dev(默认值)时,它们会出现在 EXPLAIN ANALYZE 的输出中;而在 Summary 级别下则会被省略。常规显示会将各分区合并展示;若要额外显示各分区的取值以及每个聚合计时器的 aggregate 标签,请使用 EXPLAIN ANALYZE VERBOSE。对于如下所示的查询,各表达式的指标仍保持可读,而算子的 aggr=[...] 列表会标明每个计时器索引所对应的聚合:

EXPLAIN ANALYZE
SELECT k, SUM(a), SUM(b), COUNT(c)
FROM t
GROUP BY k;

下面这个经过缩略的局部聚合计划行展示了该对应关系(已省略耗时统计和无关指标):

AggregateExec: mode=Partial, gby=[k@0 as k], aggr=[sum(t.a), sum(t.b), count(t.c)],
  metrics=[..., agg_expr_0_arguments_time=..., agg_expr_1_arguments_time=...,
  agg_expr_2_arguments_time=...]

因此 agg_expr_0_* 对应 sum(t.a),agg_expr_1_* 对应 sum(t.b),agg_expr_2_* 对应 count(t.c)。在 verbose 输出中,相应的 aggregate 标签会为每个分区提供相同的映射关系。

待办事项

为其余运算符添加指标。

评论

登录后参与评论

正在加载评论…