Spark3.0で知っておくべき7つのSQLパフォーマンスの最適化
過去のメモリビッグデータ過去のメモリビッグデータ
この記事は、IBM Tokyo ResearchInstituteの上級技術者であるDr.IshizakiがSparkSummit North America2020で「ApacheSpark3.0のSQLパフォーマンスの向上の概要」というトピックを共有したことによるものです。この記事のビデオについては、今日のツイートの3番目の記事を参照してください。PPT過去のメモリビッグデータに注意を払い、バックグラウンドでsparksql3に返信して取得してください。
先月、Spark 3.0の公式版がリリースされ、多くの機能が更新されました。過去のビッグデータを記憶するApache Spark 3.0.0の公式版がついにリリースされ、重要な機能が十分に分析されています。この記事では、SQLでのSpark3.0の最適化を紹介します。
SQLの最適化には、主に次の4つの方向が含まれます。
- 開発者との対話用。
- 動的最適化;
- 触媒の改善;
- インフラの更新。
また、以前の記事で、Spark3.0が合計3464の問題を処理したことにも言及しました。これほど多くの問題を1つずつ確認するのは難しいので、このセッションでは石崎和明博士からSQLの改善が行われました。
SQLの改善には、主に7つの側面が含まれます。
- 新しいフォーマットを説明します。
- すべての結合はヒントをサポートします。
- アダプティブクエリ実行。
- 動的パーティションカット;
- ネストされた列のトリミングとプッシュダウンを強化します。
- 集約のための強化されたコード生成。
- 新しいScalaおよびJavaバージョンのサポート。
新しいフォーマットを説明する
クエリのパフォーマンスを向上させるには、クエリがどのように最適化されているかを理解する必要があります。まず、クエリプランを理解する必要があります。次のようなクエリがあるとします。
SELECT key, Max(val)
FROM temp
WHERE key > 0
GROUP BY key
HAVING max(val) > 0
Spark2.4およびSpark3.0クエリがこのSQLをどのように計画するかを見てみましょう。
Spark 2.4でEXLPAINを使用してクエリプランを表示すると、出力が長すぎることがわかります。!各行に不要な属性がたくさんあるからです。これが何のためにあるのか一目でわかるのは難しいです。
Spark 3.0は、EXPLAINに基づいてFORMATTEDのサポートを追加し、非常に簡潔な形式で詳細情報を表示します。この出力は、主に2つの部分で構成されています。
最初の部分は主に一連の演算子であり、
2番目の部分は一連の属性です
上記の出力から、Spark SQLがこのクエリをどのように処理するかが一目でわかります。出力などのより詳細な情報が必要な場合は、2番目の部分で属性を確認できます。
すべての結合はヒントをサポートします
SQLの2番目の最適化は、結合タイプのヒントです。
Spark 2.4では、ブロードキャストにヒントのヒントしか与えることができず、他のタイプの結合はサポートされていません。Spark 3.0では、ヒントヒントはすべてのタイプの結合でサポートされています。ヒントは、SQLまたはDSLで直接使用できます。Sparkで選択されたこの結合戦略は、不要な場合に非常に役立ちます。
アダプティブクエリ実行
3番目の最適化は、適応クエリ最適化です。
- 統計を実行することにより、3つの側面が最適化されます。
- 妥当な数のReduceを自動的に設定します。
- パフォーマンスを向上させるために、より適切な結合戦略を選択してください。
- TiltJoinのデータを最適化します。
これらの最適化は、手動で調整する必要はまったくありません。TPC-DSのQ77クエリでは、パフォーマンスが8倍向上しています。
上記は2.4でのSQLの動作ステータスです。5つのパーティションに5つのreduceプロセスがある場合、データが少ないため、Reduce0を非常に迅速に完了できます。2番目はReduce4、最も遅いのはReduce3です。その結果、このSQLクエリの消費時間は主にReduce 3に費やされ、他のCPUはアイドル状態です。
Spark 3.0では、適切な数のReduceが自動的に選択されるため、Redueがアイドル状態になることはありません。
Spark 2.4は、静的統計に基づいて結合戦略を選択します。たとえば、上記のtable1とtable2の静的統計はそれぞれ100GBと80GBであるため、上記の結合はソートマージ結合を使用します。
Spark 3.0は、この結合が実行時の統計に基づいてブロードキャスト結合を選択する必要があることを認識しています。
2つのテーブルの結合時間は、最大のパーティションの時間によって異なります。したがって、結合プロセス中にパーティションにデータの偏りがある場合、処理時間は想像できます。
Spark 3.0の適応実行により、スキューされたパーティションを分割できます。比較的かなりの実行時間を達成するために。Spark 3.0のアダプティブ実行については、過去のメモリビッグデータのSpark 3.0アダプティブクエリ最適化の概要を参照してください。この記事は、実行時のSparkSQLの実行パフォーマンスを高速化します。
動的パーティショントリミング
4番目の最適化は、動的パーティションプルーニングです。これは、Apache Spark3.0動的パーティションプルーニングについての記事とApacheSpark3.0動的パーティションプルーニングの使用についての記事で確認できます。ここでは紹介しません。以下は動的パーティションカットの例です
ネストされた列のトリミングとプッシュダウンの強化
5番目の最適化は、ネストされた列の最適化です。
Spark 2.4は、Parquetのネストされた列の最適化をサポートし、必要な部分のみを読み取りますが、この関数は非常に制限されています。たとえば、再パーティション化はネストされた列のクリッピングをサポートしていません。必要な部分を選択する前に、列全体を再パーティション化する必要があります。
Spark 3.0はこの部分を最適化するため、ネストされた列の調整は、上記の再パーティション化を含むすべての演算子をサポートします。これにより、データの読み取りが減少するため、IOが大幅に減少します。次に、ネストされた列のクリッピングの例を示します。
Spark 2.4は、ネストされた列(ParquetおよびORC)のプッシュダウンをサポートしていません。すべてのデータを読み取ってから、フィルター操作を実行する必要があります。
Sparkはこの部分を最適化し、ParquetとORCの両方のネストされた列のフィルタリングプッシュダウンをサポートするようになりました。
集約のための強化されたコード生成
6番目の最適化は、集約のためのコード生成を強化することです。
Spark 2.4の複雑な集約は非常に遅いです。これは、Spark2.4の複雑なクエリがローカルコードにコンパイルされていないためです。したがって、TPC-DSを実行すると、Q66が非常に遅いことがわかります。
Sparkでは、CatalystはクエリをJavaコードに変換する役割を果たします。OpenJDKのHotSpotコンパイラは、Javaコードをローカルコードに変換する役割を果たします。
ただし、メソッドの命令が8000 Javaバイトコードを超えると、HotSpotコンパイラはJavaコードのローカルコードへの変換をあきらめます。
Catalyst of Spark 3.0は、集約されたロジックを複数の小さなメソッドに分割し、HotSpotコンパイラーがそれをローカルコードに変換できるようにするため、クエリのパフォーマンスは2.4よりもはるかに高速になります。以下は例です。
上の図の上部はSpark3.0を使用しており、最大メソッドサイズが8000未満であることがわかります。次の図は、この機能をオフにするためのもので、最大メソッドサイズが8000を超えています。