基于历史的优化 (HBO)

HBO 是一个框架,它允许记录查询的统计信息,以便在将来使用类似计划的查询重复使用这些统计信息。为了将查询与类似计划的查询匹配,查询计划被规范化,以消除计划之间不相关的差异(例如,计划中中间变量的命名),并且每个计划节点都散列到一个字符串值。HBO 使用与相同散列值关联的历史统计信息。HBO 统计信息优先于成本模型的估计值。当历史统计信息不可用时,优化器会回退到基于成本的统计信息。为 HBO 记录的统计信息位于 PlanStatistics 结构中,其中包含

字段

描述

优化器

rowCount

计划节点输出的行数

DetermineJoinDistributionType DetermineSemiJoinDistributionType PushPartialAggregationThroughExchange

outputSize

计划节点输出的大小

DetermineJoinDistributionType DetermineSemiJoinDistributionType PushPartialAggregationThroughExchange

joinNodeStatistics

包括探测和构建输入的总输入行数和具有 NULL 连接键的行数

RandomizeNullKeyInOuterJoin

tableWriterNodeStatistics

表写入器中的任务数

ScaledWriterRule

partialAggregationStatistics

部分聚合节点的输入和输出的行数和大小

PushPartialAggregationThroughExchange

如何使用 HBO

Presto 支持在查询优化中使用历史统计信息。在 HBO 中,当前查询的统计信息将被存储,并可用于优化未来的查询。Redis HBO Provider 可用作历史统计信息的存储。HBO 受以下配置属性和会话属性控制

配置属性

HBO 可用以下配置属性

配置属性名称

描述

默认值

optimizer.use-history-based-plan-statistics

使用历史统计信息进行查询优化。

False

optimizer.track-history-based-plan-statistics

记录当前查询的统计信息作为历史统计信息,以便将来查询使用。

False

optimizer.track-history-stats-from-failed-queries

从失败查询的完整计划片段中跟踪基于历史的计划统计信息。

True

optimizer.history-based-optimizer-timeout

基于历史的优化器的超时时间。

10 seconds

optimizer.enforce-timeout-for-hbo-query-registration

强制对 HBO 优化器中的查询注册进行超时

False

optimizer.treat-low-confidence-zero-estimation-as-unknown

在连接期间将 LOW 置信度、零估计值视为 UNKNOWN

False

optimizer.confidence-based-broadcast

根据正在使用的统计信息的置信度进行广播,通过广播连接节点中置信度最高的统计信息的一侧。如果置信度相同,则将遵循原始行为。

False

optimizer.retry-query-with-history-based-optimization

如果 HBO 可以帮助更改现有查询计划,则自动重试失败的查询

False

hbo.history-matching-threshold

当当前表和历史表之间的大小差异超过此阈值时,不要匹配历史统计信息。当值为 0.0 时,仅当两者的尺寸完全相同是才匹配历史统计信息。

0.1

hbo.max-last-runs-history

存储历史统计信息的最后运行次数。

10

会话属性

会话属性设置在给定会话内执行的查询的行为更改。设置时,它们将覆盖当前会话中对应配置属性(如果有)的值。

会话属性名称

描述

默认值

use_history_based_plan_statistics

覆盖当前会话中配置属性 optimizer.use-history-based-plan-statistics 的行为。

optimizer.use-history-based-plan-statistics

track_history_based_plan_statistics

覆盖当前会话中配置属性 optimizer.track-history-based-plan-statistics 的行为。

optimizer.track-history-based-plan-statistics

track_history_stats_from_failed_queries

覆盖当前会话中配置属性 optimizer.track-history-stats-from-failed-queries 的行为。

optimizer.track-history-stats-from-failed-queries

history_based_optimizer_timeout_limit

覆盖当前会话中配置属性 optimizer.history-based-optimizer-timeout 的行为。

optimizer.history-based-optimizer-timeout

enforce_history_based_optimizer_register_timeout

覆盖当前会话中配置属性 optimizer.enforce-timeout-for-hbo-query-registration 的行为。

optimizer.enforce-timeout-for-hbo-query-registration

restrict_history_based_optimization_to_complex_query

仅为复杂查询(即包含连接和聚合的查询)启用基于历史的优化。

True

history_input_table_statistics_matching_threshold

覆盖当前会话中配置属性 hbo.history-matching-threshold 的行为。

hbo.history-matching-threshold

treat-low-confidence-zero-estimation-as-unknown

覆盖当前会话中配置属性 optimizer.treat-low-confidence-zero-estimation-as-unknown 的行为。

optimizer.treat-low-confidence-zero-estimation-as-unknown

confidence-based-broadcast

覆盖当前会话中配置属性 optimizer.confidence-based-broadcast 的行为。

optimizer.confidence-based-broadcast

retry-query-with-history-based-optimization

覆盖当前会话中配置属性 optimizer.retry-query-with-history-based-optimization 的行为。

optimizer.retry-query-with-history-based-optimization

示例

下面显示了一个带有 HBO 统计信息的查询计划示例。对于计划节点,当统计信息来自 HBO 时,估计统计信息将显示源 HistoryBasedSourceInfo

Fragment 1 [HASH]                                                                                                                                            >
    Output layout: [orderpriority, count]                                                                                                                    >
    Output partitioning: SINGLE []                                                                                                                           >
    Stage Execution Strategy: UNGROUPED_EXECUTION                                                                                                            >
    - Project[PlanNodeId 392][projectLocality = LOCAL] => [orderpriority:varchar(15), count:bigint]                                                          >
            Estimates: {source: HistoryBasedSourceInfo, rows: 5 (117B), cpu: ?, memory: ?, network: ?}                                                       >
        - Aggregate(FINAL)[orderpriority][$hashvalue][PlanNodeId 4] => [orderpriority:varchar(15), $hashvalue:bigint, count:bigint]                          >
                Estimates: {source: HistoryBasedSourceInfo, rows: 5 (117B), cpu: ?, memory: ?, network: ?}                                                   >
                count := "presto.default.count"((count_8)) (1:50)                                                                                            >
            - LocalExchange[PlanNodeId 354][HASH][$hashvalue] (orderpriority) => [orderpriority:varchar(15), count_8:bigint, $hashvalue:bigint]              >
                - RemoteSource[2] => [orderpriority:varchar(15), count_8:bigint, $hashvalue_9:bigint]

使用 HBO 的优化

DetermineJoinDistributionType 和 DetermineSemiJoinDistributionType

这两种优化决定是为连接执行广播还是重新分区。它们使用探测和构建输入的大小进行优化。

  • 启用 HBO 时,将使用从历史查询记录的数据大小。

  • 当 HBO 统计信息不可用或 HBO 被禁用时,将使用来自成本模型的统计信息。

ReorderJoins

此优化根据输入和输出的大小重新排序连接顺序。启用 HBO 时,将使用从历史查询记录的数据大小。

PushPartialAggregationThroughExchange

此优化决定是将聚合拆分为部分聚合和最终聚合。

  • track_partial_aggregation_history 设置为 true 以跟踪部分聚合节点的输出大小。

  • use_partial_aggregation_history 设置为 true 以使用部分聚合节点统计信息来决定是否拆分聚合。部分聚合统计信息的跟踪针对我们在生产查询中发现的模式,其中最终聚合节点是基数减少的,但部分聚合不是。当未启用 use_partial_aggregation_history 或部分聚合统计信息不可用时,它将回退到使用最终聚合统计信息。

注意:当优化器禁用部分聚合时,没有关于部分聚合的统计信息,并且部分聚合统计信息不可用。

ScaledWriterRule

缩放写入器支持动态增加文件写入任务的数量,以避免写入太多的小文件。默认情况下,它从一个写入任务开始。在 HBO 中,用于写入文件的任务数被记录为历史记录。ScaledWriterRule 根据此信息决定要启动的任务数。它将从 HBO 中记录的写入任务数的一半开始,因为缩放写入器只会增加写入任务数,如果我们使用与历史运行中完全相同的任务数,则它永远不会减少。此优化可以通过会话属性 enable_history_based_scaled_writer 启用。

RandomizeNullKeyInOuterJoin

RandomizeNullKeyInOuterJoin 用于通过将空值键重写为永远不会匹配的非空值键来减轻外连接中空值的倾斜。它有利于外连接查询,其中连接键在空值上有倾斜。在 HBO 中,连接节点会跟踪空值键的数量和总连接键数;当空值键的比例超过以下阈值时,将启用此优化。

  • 空值键的数量,硬编码为 100,000。

  • 空值键的比例,可以通过会话属性 `randomize_outer_join_null_key_null_ratio_threshold` 设置,默认值为 2%。

可以通过将 `randomize_outer_join_null_key_strategy` 设置为 `COST_BASED` 来启用此优化。