指标
指标
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_count | HashJoinExec 为完美哈希连接查找执行创建 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 标签会为每个分区提供相同的映射关系。
待办事项
为其余运算符添加指标。
评论
登录后参与评论
KnowForge