履歴ベースの最適化(HBO)

HBOは、クエリの統計情報を記録し、同様のプランを持つ将来のクエリでその統計情報を再利用できるようにするフレームワークです。同様のプランを持つクエリを照合するために、クエリプランは正規化され、プラン間の無関係な違い(たとえば、プラン内の中間変数の命名)が排除され、各プランノードは文字列値にハッシュされます。同じハッシュ値に関連付けられた履歴統計がHBOで使用されます。 HBO統計は、コストモデルからの推定よりも優先されます。履歴統計が利用できない場合、オプティマイザはコストベースの統計にフォールバックします。 HBO用に記録された統計は、以下を含む `PlanStatistics` 構造体にあります。

フィールド

説明

オプティマイザ

rowCount

プランノードによって出力される行数

結合分散タイプの決定、準結合分散タイプの決定、Exchangeを介した部分集計のプッシュ

outputSize

プランノードによる出力のサイズ

結合分散タイプの決定、準結合分散タイプの決定、Exchangeを介した部分集計のプッシュ

joinNodeStatistics

プローブとビルドの両方の入力について、入力行の総数とNULL結合キーを持つ行数を含めます

外部結合におけるNULLキーのランダム化

tableWriterNodeStatistics

テーブルライターのタスク数

スケーリングされた Writer ルール

partialAggregationStatistics

部分集計ノードの入力と出力の行数とサイズ

Exchangeを介した部分集計のプッシュ

HBOの使用方法

Prestoは、クエリ最適化で履歴統計の使用をサポートしています。 HBOでは、現在のクエリの統計が保存され、将来のクエリの最適化に使用できます。 Redis HBOプロバイダーは、履歴統計のストレージとして使用できます。 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

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

HBOオプティマイザでのクエリ登録のタイムアウトを強制します

False

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

結合中に、信頼度の低いゼロ推定を `UNKNOWN` として扱います。

False

optimizer.confidence-based-broadcast

使用されている統計の信頼度に基づいてブロードキャストします。最も信頼度の高い統計を持つ結合ノードの側をブロードキャストします。信頼度が同じ場合は、元の動作が適用されます。

False

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

HBOが既存のクエリプランの変更に役立つ場合、失敗したクエリを自動的に再試行します

False

hbo.history-matching-threshold

現在のテーブルと履歴テーブルのサイズ差がこのしきい値を超えると、履歴統計と一致しません。値が0.0の場合は、2つのサイズが完全に同じ場合にのみ履歴統計と一致します。

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を使用した最適化

結合分散タイプの決定と準結合分散タイプの決定

これら2つの最適化は、結合にブロードキャストを行うか、再分割を行うかを決定します。最適化では、プローブとビルドの入力サイズを使用します。

  • HBOが有効になっている場合、履歴クエリから記録されたデータサイズが使用されます。

  • HBO統計が利用できないか、HBOが無効になっている場合、コストモデルからの統計が使用されます。

結合の順序変更

この最適化は、入力と出力のサイズに基づいて結合順序を変更します。 HBOが有効になっている場合、履歴クエリから記録されたデータサイズが使用されます。

Exchangeを介した部分集計のプッシュ

この最適化は、集計を部分集計と最終集計に分割するかどうかを決定します。

  • 部分集計ノードの出力サイズを追跡するには、`track_partial_aggregation_history` をtrueに設定します。

  • 部分集計ノードの統計情報を使用して集計を分割するかどうかを決定するには、use_partial_aggregation_history を true に設定します。部分集計統計情報の追跡は、本番クエリで見られるパターンを対象としています。このパターンでは、最終集計ノードはカーディナリティを削減しますが、部分集計は削減しません。use_partial_aggregation_history が有効になっていないか、部分集計統計情報が利用できない場合は、最終集計統計情報の使用にフォールバックします。

注: オプティマイザが部分集計を無効にすると、部分集計に関する統計情報は存在せず、部分集計統計情報は利用できません。

ScaledWriterRule

スケールドライターは、ファイル書き込みタスクの数を動的に増やすことで、小さすぎるファイルの書き込みを回避することをサポートしています。デフォルトでは、1つの書き込みタスクから開始します。HBOでは、ファイルの書き込みに使用されるタスクの数が履歴として記録されます。ScaledWriterRule は、この情報に基づいて開始するタスクの数を決定します。スケールドライターは書き込みタスクの数を増やすだけで、履歴実行からまったく同じ数のタスクを使用すると減ることは決してないため、HBOに記録された書き込みタスクの数の半分から開始します。この最適化は、セッションプロパティ enable_history_based_scaled_writer によって有効にすることができます。

RandomizeNullKeyInOuterJoin

RandomizeNullKeyInOuterJoin は、外部結合における NULL 値の偏りを軽減するために使用されます。これは、NULL キーを、決して一致しない非 NULL キーに書き換えることによって行われます。結合キーに NULL 値の偏りがある外部結合を含むクエリに有効です。HBOでは、結合ノードの NULL キーの数と結合キーの合計数が追跡されます。この最適化は、NULL キーの割合が次のしきい値を超えた場合に有効になります。

  • NULL キーの数。これは 100,000 にハードコードされています。

  • NULL キーの割合。これはセッションプロパティ randomize_outer_join_null_key_null_ratio_threshold で設定でき、デフォルトは 2% です。

この最適化は、randomize_outer_join_null_key_strategyCOST_BASED に設定することで有効にすることができます。