メインコンテンツまでスキップ

アダプティブ クエリ実行

アダプティブ クエリ実行 (AQE) は、クエリの実行中に発生するクエリの再最適化です。

クエリーが実行される前に、オプティマイザはデータサイズの推定値に基づいてクエリー実行計画を選択します。テーブル統計が存在しない、最新でない、データがスキューしている、または複雑なクエリーの後のステップの場合、それらの推定値が間違っている可能性があります。間違った推定値に基づいて構築されたプランでは、低速の結合戦略を使用したり、シャッフルの後に過剰な数の小さなタスクを作成したり、ステージ全体を停止させる少数の過大タスクを作成したりする可能性があります。AQE は、クエリーの実行中に実際のデータサイズに基づいてプランを再最適化することで、これらの問題を解決します。

各シャッフルまたはブロードキャスト交換の終了時に、Databricks はこれまでに生成されたデータの正確な統計を持っています。AQE はこれらの統計を使用して、より良い物理的な戦略を選択し、シャッフル後のパーティションの最適な数とサイズを選択するか、スキュー結合処理など、クエリーのヒントを必要とする最適化を適用します。

AQE は default で有効になります。その利点を享受するためにクエリーを変更する必要はありません。低速のクエリーのトラブルシューティングを行う際は、 AQE がクエリープランを変更したかどうかを確認します。default がワークロードに合っていない場合にのみ、 AQE の設定を調整してください。クエリー・プランと構成を参照してください。

資格​

AQEには4つの主な機能があります:

  • ソート・マージ結合をブロードキャスト・ハッシュ結合に動的に変更します。
  • シャッフル交換後にパーティションを動的に合体します (小さなパーティションを適度なサイズのパーティションに結合します)。 非常に小さなタスクは I/O スループットが悪くなり、スケジュールのオーバーヘッドとタスク設定のオーバーヘッドに悩まされる傾向があります。 小さなタスクを組み合わせると、リソースが節約され、クラスターのスループットが向上します。
  • ソート、マージ結合、シャッフルハッシュ結合でスキューを動的に処理し、スキューされたタスクをほぼ均等なサイズのタスクに分割(および必要に応じてレプリケート)します。
  • クエリーの一部である空のリレーションを動的に検出し、伝播します。これらのリレーションは、行を返しません。

サポートされているクエリー​

AQE は、次の両方の条件を満たすクエリーに適用されます:

  • クエリーはストリーミングクエリーではありません。
  • クエリーには、少なくとも 1 つの交換 (通常は結合、集計、またはウィンドウから) 、少なくとも 1 つのサブクエリ、またはその両方が含まれています。

AQE はサポートされているすべてのクエリーを再最適化しますが、その結果はクエリーが実行される前にオプティマイザがコンパイルした計画と同じになる場合があります。AQE がクエリのプランを変更したかどうかを確認するには、「クエリープラン」を参照してください。

クエリ プラン​

AQE が適用されたクエリーには、通常、各メインクエリーまたはサブクエリーのルートノードとして、1 つ以上のAdaptiveSparkPlanノードが含まれています。各AdaptiveSparkPlanノードにはisFinalPlanフラグがあります。このフラグは、クエリー実行前および実行中にはfalseとなり、クエリーが終了するとtrueに変更されます。

クエリープランを表示するには、Spark UI、DataFrame.explain()、またはSQL EXPLAINを使用してください。それぞれに、AQEがプランをどのように変更するかについての異なる情報が表示されます。

Spark UI​

Spark UI のクエリー実行計画ダイアグラムは、最新の計画を示し、クエリーの実行に合わせて更新されます。すでに実行済みでメトリクスがあるノードは変更されません。実行されていないノードは、AQE が計画を再最適化する際に変更される可能性があります。

この例は、クエリープラン図を示しています:

クエリ プラン図

DataFrame.explain()​

DataFrame.explain() 各 AdaptiveSparkPlan ノードの下に、 AQE が最適化を適用する前の初期プランと現在のプランの 2 つのプランが表示されます。現在のプランはクエリーの実行中に変更され、クエリーが終了すると最終プランになります。

出力には、各シャッフルおよびブロードキャストステージのデータ統計が含まれます。統計は、ステージがランしたかどうかによって異なります。

  • ステージのラン前とラン中、 isRuntime は false であり、統計はコンパイル時の推定値です。例: Statistics(sizeInBytes=1024.0 KiB, rowCount=4, isRuntime=false)。
  • ステージの実行後、 isRuntime は true になり、統計はランタイム測定値になります。たとえば Statistics(sizeInBytes=658.1 KiB, rowCount=2.81E+4, isRuntime=true) です。

以下のスクリーンショットは、実行前、実行中、実行後の DataFrame.explain() 出力です。

  • 実行前

    実行前

  • 実行中

    実行中

  • 実行後

    実行後

SQL EXPLAIN​

SQL EXPLAIN クエリーを実行しないため、AQEはそれを再最適化できません。出力には初期プランのみが表示されます。これは、AQEが実行するプランとは異なる場合があります。

この例はSQL EXPLAINの出力を示しています:

SQLの説明

クエリー実行計画に適用された最適化を特定する​

AQEが最適化を適用すると、クエリー・プランが変更されます。どの最適化が有効になったかを確認するには、現在のプランまたは最終的なプランを初期プランと比較します。それぞれの最適化によって、計画は特定の方法で変更されます:

  • 結合戦略の変更。 現在または最終的なプランには、初期プランとは異なる物理結合ノードがあります。

    ジョイン戦略文字列

  • パーティションの合体。 プランには、Coalescedプロパティを持つCustomShuffleReaderノードが含まれています。

    カスタムシャッフルリーダー

    カスタムシャッフルリーダー文字列

  • スキュー結合の処理。 プランには、 isSkew フィールドが trueに設定された SortMergeJoin ノードが含まれています。

    スキュー・ジョイン計画

    スキュー結合文字列

  • 空のリレーションの伝播。 リレーションフィールドが空の LocalTableScan ノードが、プランの一部または全部を置き換えます。

    ローカル テーブル スキャン

    ローカル テーブル スキャン文字列

構成​

これらの Apache Spark 構成プロパティは、AQE を制御します。ほとんどのワークロードでは、default設定を変更する必要はありません。

AQE を有効にし、個々の最適化を調整する​

AQE をオンまたはオフにし、自動最適化されたシャッフル、ブロードキャスト結合の切り替え、および空のリレーションの伝播を調整するには、次のプロパティを使用します。

属性

Type

デフォルト

説明

spark.databricks.optimizer.adaptive.enabled

Boolean

true

適応型クエリー実行をオンにするかオフにするか。

spark.sql.shuffle.partitions

Integer

200

結合または集約のためにデータをシャッフルするときに使用する default のパーティション数。これを auto に設定すると、自動最適化シャッフルが有効になります。これにより、クエリープランとクエリー入力データサイズに基づいて、この数が設定されます。

構造化ストリーミングの場合、同じチェックポイント位置からのクエリー再起動の間で、この値を変更することはできません。

spark.databricks.adaptive.autoBroadcastJoinThreshold

Byte String

30MB

ランタイムにソートMerge結合をブロードキャストハッシュ結合に切り替えるためのサイズthreshold。

spark.databricks.adaptive.emptyRelationPropagation.enabled

Boolean

true

動的空リレーションの伝播をオンまたはオフにします。

属性

Type

デフォルト

説明

spark.databricks.optimizer.adaptive.enabled

Boolean

true

適応型クエリー実行をオンにするかオフにするか。

spark.sql.shuffle.partitions

Integer

200

結合または集約のためにデータをシャッフルするときに使用する default のパーティション数。これを auto に設定すると、自動最適化シャッフルが有効になります。これにより、クエリープランとクエリー入力データサイズに基づいて、この数が設定されます。

構造化ストリーミングの場合、同じチェックポイント位置からのクエリー再起動の間で、この値を変更することはできません。

spark.databricks.adaptive.autoBroadcastJoinThreshold

Byte String

30MB

ランタイムにソートMerge結合をブロードキャストハッシュ結合に切り替えるためのサイズthreshold。

spark.databricks.adaptive.emptyRelationPropagation.enabled

Boolean

true

動的空リレーションの伝播をオンまたはオフにします。

パーティションの動的合体​

属性

Type

デフォルト

説明

spark.sql.adaptive.coalescePartitions.enabled

Boolean

true

パーティションの合体をオンにするかオフにするかを切り替えます。

spark.sql.adaptive.advisoryPartitionSizeInBytes

Byte String

64MB

結合後のターゲットサイズ。結合されたパーティションは、このサイズに近くなりますが、これを超えることはありません。

spark.sql.adaptive.coalescePartitions.minPartitionSize

Byte String

1MB

結合後のパーティションの最小サイズ。合体されたパーティションは、このサイズより小さくありません。

spark.sql.adaptive.coalescePartitions.minPartitionNum

Integer

クラスターコア数の2倍

結合後のパーティションの最小数。このプロパティを設定しないでください。設定すると spark.sql.adaptive.coalescePartitions.minPartitionSize が上書きされるためです。

属性

Type

デフォルト

説明

spark.sql.adaptive.coalescePartitions.enabled

Boolean

true

パーティションの合体をオンにするかオフにするかを切り替えます。

spark.sql.adaptive.advisoryPartitionSizeInBytes

Byte String

64MB

結合後のターゲットサイズ。結合されたパーティションは、このサイズに近くなりますが、これを超えることはありません。

spark.sql.adaptive.coalescePartitions.minPartitionSize

Byte String

1MB

結合後のパーティションの最小サイズ。合体されたパーティションは、このサイズより小さくありません。

spark.sql.adaptive.coalescePartitions.minPartitionNum

Integer

クラスターコア数の2倍

結合後のパーティションの最小数。このプロパティを設定しないでください。設定すると spark.sql.adaptive.coalescePartitions.minPartitionSize が上書きされるためです。

スキュー結合を動的に処理する​

属性

Type

デフォルト

説明

spark.sql.adaptive.skewJoin.enabled

Boolean

true

スキュー結合処理のオン/オフを切り替えます。

spark.sql.adaptive.skewJoin.skewedPartitionFactor

Integer

5

パーティションが歪んだとみなされるために超える必要のある中央値パーティションサイズの乗数。

spark.sql.adaptive.skewJoin.skewedPartitionThresholdInBytes

Byte String

256MB

パーティションが歪んだとみなされるために超える必要のある最小サイズ。

属性

Type

デフォルト

説明

spark.sql.adaptive.skewJoin.enabled

Boolean

true

スキュー結合処理のオン/オフを切り替えます。

spark.sql.adaptive.skewJoin.skewedPartitionFactor

Integer

5

パーティションが歪んだとみなされるために超える必要のある中央値パーティションサイズの乗数。

spark.sql.adaptive.skewJoin.skewedPartitionThresholdInBytes

Byte String

256MB

パーティションが歪んだとみなされるために超える必要のある最小サイズ。

AQE は、(partition size > skewedPartitionFactor * median partition size) と (partition size > skewedPartitionThresholdInBytes) の両方の条件が true の場合にのみ、パーティションをスキューしているとみなします。

よくある質問(FAQ)​

AQE が小さな結合テーブルをブロードキャストしなかったのはなぜですか?​

テーブルが spark.databricks.adaptive.autoBroadcastJoinThreshold より小さいのに AQE がブロードキャストしない場合は、次の原因を確認してください。

  • 結合タイプはブロードキャストをサポートしていません。 一部の結合タイプでは、一方の側をブロードキャストできないことがあります。例えば、AQE は LEFT OUTER JOIN の左側をブロードキャストできません。
  • テーブルに空のパーティションが多く含まれています。 ソートマージ結合におけるほとんどのタスクは迅速に完了するか、スキュー結合の処理により結合が最適化されます。空でないパーティションの割合が spark.sql.adaptive.nonEmptyPartitionRatioForBroadcastJoin 未満の場合、AQE はソートMerge結合をブロードキャストハッシュ結合に変更しません。

AQE が有効な場合でも、ブロードキャスト結合ヒントを使用する必要がありますか?​

はい、クエリーをよく理解している場合です。クエリー実行前にオプティマイザが計画するブロードキャスト結合は、通常、ランタイム時に AQE が計画する結合よりもパフォーマンスが向上します。AQE は、結合の両側をシャッフルした後にテーブルの実際のサイズを学習するまで、ブロードキャスト結合に切り替えない可能性があります。

AQEは静的最適化と同じ方法でクエリーヒントを尊重し、ヒントの影響を受けない動的最適化を引き続き適用します。

スキュー結合のヒントを使用すべきか、AQEのスキュー結合処理を使用すべきか?​

AQEのスキュー結合処理を使用します。これは自動的に実行され、通常はスキュー結合ヒントよりも優れたパフォーマンスを発揮します。

AQEが結合を並べ替えなかったのはなぜですか?​

AQE は、ランタイムに結合を並べ替えません。結合の順序を改善するには、テーブルの統計情報を収集し、コストベースオプティマイザが最適な計画を選択できるようにします。コストベースオプティマイザを参照してください。

AQE でデータ スキューが検出されなかったのはなぜですか?​

AQE は、次の両方の条件が真である場合にのみ、パーティションをスキューとみなします。

  • パーティションはspark.sql.adaptive.skewJoin.skewedPartitionThresholdInBytes(default 256MB)より大きいです。
  • パーティションは、メディアンパーティションサイズの spark.sql.adaptive.skewJoin.skewedPartitionFactor (default 5) 倍を超えています。

AQE は、ソートMerge結合やシャッフルハッシュ結合であるシャッフルベースの結合でのみスキューを処理します。ブロードキャスト結合のスキューは決して最適化されません。シャッフルベースの結合では、結合のタイプによって AQE が最適化できる側が決まります。

結合タイプ

左側でスキュー最適化済み

右側でスキュー最適化済み

INNER

はい

はい

CROSS

はい

はい

LEFT OUTER

はい

No

RIGHT OUTER

No

はい

LEFT SEMI

はい

No

LEFT ANTI

はい

No

FULL OUTER

No

No

結合タイプ

左側でスキュー最適化済み

右側でスキュー最適化済み

INNER

はい

はい

CROSS

はい

はい

LEFT OUTER

はい

No

RIGHT OUTER

No

はい

LEFT SEMI

はい

No

LEFT ANTI

はい

No

FULL OUTER

No

No

遺産​

Spark 1.6 に導入された適応型実行は、Spark 3.0 の AQE とは異なる機能です。Spark 1.6 の適応型実行は、パーティションを動的に合体する機能しかありません。AQE は、ランタイムの統計に基づいてクエリーを計画および再計画するフレームワークであり、このページのすべての最適化をサポートしています。