履歴ベースの最適化(HBO)¶
HBOは、クエリの統計情報を記録し、同様のプランを持つ将来のクエリでその統計情報を再利用できるようにするフレームワークです。同様のプランを持つクエリを照合するために、クエリプランは正規化され、プラン間の無関係な違い(たとえば、プラン内の中間変数の命名)が排除され、各プランノードは文字列値にハッシュされます。同じハッシュ値に関連付けられた履歴統計がHBOで使用されます。 HBO統計は、コストモデルからの推定よりも優先されます。履歴統計が利用できない場合、オプティマイザはコストベースの統計にフォールバックします。 HBO用に記録された統計は、以下を含む `PlanStatistics` 構造体にあります。
| フィールド | 説明 | オプティマイザ | 
|---|---|---|
| rowCount | プランノードによって出力される行数 | 結合分散タイプの決定、準結合分散タイプの決定、Exchangeを介した部分集計のプッシュ | 
| outputSize | プランノードによる出力のサイズ | 結合分散タイプの決定、準結合分散タイプの決定、Exchangeを介した部分集計のプッシュ | 
| joinNodeStatistics | プローブとビルドの両方の入力について、入力行の総数とNULL結合キーを持つ行数を含めます | 外部結合におけるNULLキーのランダム化 | 
| tableWriterNodeStatistics | テーブルライターのタスク数 | スケーリングされた Writer ルール | 
| partialAggregationStatistics | 部分集計ノードの入力と出力の行数とサイズ | Exchangeを介した部分集計のプッシュ | 
HBOの使用方法¶
Prestoは、クエリ最適化で履歴統計の使用をサポートしています。 HBOでは、現在のクエリの統計が保存され、将来のクエリの最適化に使用できます。 Redis HBOプロバイダーは、履歴統計のストレージとして使用できます。 HBOは、以下の設定プロパティとセッションプロパティによって制御されます。
設定プロパティ¶
HBOでは、以下の設定プロパティを使用できます。
| 設定プロパティ名 | 説明 | デフォルト値 | 
|---|---|---|
| 
 | クエリ最適化に履歴統計を使用します。 | 
 | 
| 
 | 将来のクエリで使用するために、現在のクエリの統計を履歴統計として記録します。 | 
 | 
| 
 | 失敗したクエリの完全なプランフラグメントから履歴ベースのプラン統計を追跡します。 | 
 | 
| 
 | 履歴ベースのオプティマイザのタイムアウト。 | 
 | 
| 
 | HBOオプティマイザでのクエリ登録のタイムアウトを強制します | 
 | 
| 
 | 結合中に、信頼度の低いゼロ推定を `UNKNOWN` として扱います。 | 
 | 
| 
 | 使用されている統計の信頼度に基づいてブロードキャストします。最も信頼度の高い統計を持つ結合ノードの側をブロードキャストします。信頼度が同じ場合は、元の動作が適用されます。 | 
 | 
| 
 | HBOが既存のクエリプランの変更に役立つ場合、失敗したクエリを自動的に再試行します | 
 | 
| 
 | 現在のテーブルと履歴テーブルのサイズ差がこのしきい値を超えると、履歴統計と一致しません。値が0.0の場合は、2つのサイズが完全に同じ場合にのみ履歴統計と一致します。 | 
 | 
| 
 | 履歴統計が保存される最後の実行回数。 | 
 | 
セッション プロパティ¶
セッションプロパティを設定すると、特定のセッション内で実行されるクエリの動作が変更されます。設定すると、現在のセッションの対応する設定プロパティ(存在する場合)の値が上書きされます。
| セッションプロパティ名 | 説明 | デフォルト値 | 
|---|---|---|
| 
 | 現在のセッションで設定プロパティ `optimizer.use-history-based-plan-statistics` の動作をオーバーライドします。 | 
 | 
| 
 | 現在のセッションで設定プロパティ `optimizer.track-history-based-plan-statistics` の動作をオーバーライドします。 | 
 | 
| 
 | 現在のセッションで設定プロパティ `optimizer.track-history-stats-from-failed-queries` の動作をオーバーライドします。 | 
 | 
| 
 | 現在のセッションで設定プロパティ `optimizer.history-based-optimizer-timeout` の動作をオーバーライドします。 | 
 | 
| 
 | 現在のセッションで設定プロパティ `optimizer.enforce-timeout-for-hbo-query-registration` の動作をオーバーライドします。 | 
 | 
| 
 | 結合と集計を含むクエリなど、複雑なクエリに対してのみ履歴ベースの最適化を有効にします。 | 
 | 
| 
 | 現在のセッションで設定プロパティ `hbo.history-matching-threshold` の動作をオーバーライドします。 | 
 | 
| 
 | 現在のセッションで設定プロパティ `optimizer.treat-low-confidence-zero-estimation-as-unknown` の動作をオーバーライドします。 | 
 | 
| 
 | 現在のセッションで設定プロパティ `optimizer.confidence-based-broadcast` の動作をオーバーライドします。 | 
 | 
| 
 | 現在のセッションで設定プロパティ `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_strategy を COST_BASED に設定することで有効にすることができます。