How to Get the Best Performance from Delta Lake Star Schema Databases - The Databricks Blogの翻訳です。
本書は抄訳であり内容の正確性を保証するものではありません。正確な内容に関しては原文を参照ください。
Delta Lakeを用いてどのようにデータウェアハウスとデータマートで使われているスタースキーマから一貫性のあるベストなパフォーマンスを得るのか
データウェアハウスを用いるほとんどの開発者は、以前から存在しているスタースキーマに非常に慣れ親しんでいます。1990年代にRalph Kimballによって導入されたスタースキーマは、ビジネスデータをディメンジョン(時間や製品など)とファクト(トランザクションの数量など)に非正規化します。スタースキーマはデータを効率的に格納し、ビジネスの定義の繰り返しによる重複を削減することで履歴とデータの更新を維持し、集計やフィルタリングを高速にします。
BIアプリケーションをサポートするスタースキーマの共通的な実装はルーチンとなっており、数多くのデータモデラーは眠っていても実際にそれらを実装することができるようになっています。Databricksにおいて、我々は数多くのデータアプリケーションを生み出しており、経験的な目安として役立つベストプラクティスのアプローチや、素晴らしい成果を導くことを保証する基本的な実装を常に探しています。
従来型のデータウェアハウスと同じように、お使いのDeltaテーブルによるスタースキーマのジョインを劇的に改善するDelta Lakeにおいて従うべき鉄則となるシンプルなルールが存在します。
成功に至る基本的ステップは以下の通りです。
- ファクトとディメンジョンテーブルを作成するためにDeltaテーブルを使う
- 高速なファイルプルーニングのためにファイルサイズを最適化する
- ファクトテーブルに対してZ-Orderを作成する
- ディメンジョンのキーフィールドと頻繁に使われる検索条件に対してZ-Orderを作成する
- Adaptive Query Executionオプティマイザの統計情報を収集するためにテーブルを解析する
1. ファクトとディメンジョンテーブルを作成するためにDeltaテーブルを使う
Delta Lakeはお使いのデータレイク上のテーブルに対して簡単にインサート、アップデート、デリートできる機能とACIDトランザクションを提供するオープンなストレージフォーマットレイヤーであり、メンテナンスや履歴管理をシンプルにします。また、Delta Lakeは高速なSQLクエリーのための最適化を行う動的ファイルプルーニングを実行するための機能も提供します。
Delta LakeがデフォルトのテーブルフォーマットになっているDatabricksランタイム8.x以降では構文はシンプルです。以下のようにSQLを用いてDeltaテーブルを作成することができます。
CREATE TABLE MY_TABLE (COLUMN_NAME STRING)
Databricksランタイム8.xより前のバージョンでは、USING DELTA
構文を指定してテーブルを作成する必要があります。
2. 高速なファイルプルーニングのためにファイルサイズを最適化する
Apache Spark™のクエリーにおいて最も時間を要する2つの部分は、クラウドストレージからのデータ読み込みと、背後にあるすべてのファイルを読み込まなくてはいけないことに要する時間です。Delta Lakeのデータスキッピングを用いることで、クエリーは適切なデータを含むDeltaファイルのみを選択的に読み込むことができ、劇的に時間を削減します。データスキッピングは静的なファイルプルーニングと動的なファイルプルーニング、静的なパーティションプルーニングと動的なパーティションプルーニングによるものです。
データスキッピングをセットアップする際に検討すべき最初のことの一つが理想的なデータファイルサイズです。小さすぎると多すぎる数のファイルを持つことになります(よく知られている「小さなファイル問題」です)。大きすぎるとデータを十分にスキップすることができないかもしれません。
望ましいファイルサイズのレンジは32-128MB(もちろん32MBとは1024102432 = 33554432です)です。繰り返しになりますが、ファイルサイズが大きすぎると、動的ファイルプルーニングは適切なファイルまでスキップしますが、あまりに大きいので依然として処理する量が大きいままとなります。より小さいファイルを作成することで、joinに必要なデータを取得する際のI/Oを最小化できるのでファイルプルーニングのメリットを得ることができます。
PYthonでノートブック全体におけるファイルサイズの値を設定することができます。
spark.conf.set("spark.databricks.delta.targetFileSize", 33554432)
あるいは、SQLでは以下のようになります。
SET spark.databricks.delta.targetFileSize=33554432
あるいは以下のように特定のテーブルにのみ設定することができます。
ALTER TABLE (database).(table) SET TBLPROPERTIES (delta.targetFileSize=33554432)
もし、既にテーブルを作成した後にこの記事を読んでいるのでしたら、テーブルプロパティにファイルサイズを設定することができますし、ZORDERを作成し最適化する際にはファイルが新たなファイルサイズに分配されます。既にZORDERを追加している場合には、最終的なZORDERの設定に至る前に再書き込みを強制する前にカラムの追加削除を行うことができます。詳細はステップ3のZORDERをご覧ください。
より完全なドキュメントはこちらから参照でき、SQLに加えてPythonやScalaを使いたいのであれば、完全な文法はこちらにあります。
Databricksでは新たな機能や能力が追加され続けており、テーブルサイズに応じてファイルサイズを自動でチューニングすることもできます。小規模なデータベースに対しては、上述の設定は優れたパフォーマンスを発揮しますが、より大規模なデータベースに対応する、あるいはよりシンプルにするために、こちらのガイドを参照するかテーブルプロパティdelta.tuneFileSizesForRewrites
を実装することもできます。
3. ファクトテーブルに対してZ-Orderを作成する
クエリーのスピードを改善するために、Delta Lakeはクラウドストレージに格納されているデータのレイアウトを、多次元クラスタリングとしても知られるZ-Orderingを用いて最適化する機能をサポートしています。Z-Orderはデータベースの世界におけるクラスターインデックスとして、同様なシチュエーションでも用いられていますが、実際のところ補助的な構造でもありません。Z-Orderの定義において、Z-Orderはカラムの値のような行が可能な限り少ないファイルで近い位置に配置されるようにデータをクラスタリングします。
多くのデータベースシステムは、クエリーのパフォーマンスを改善するためにインデックスを導入しました。インデックスはファイルであり、データのサイズが増えるにつれて、インデックス自体も解決すべきビッグデータの問題となります。そうならないように、Delta Lakeはオブジェクトストレージにおけるレンジ選択がより効率的になるようにParquetファイルのデータを並び替えます。統計情報収集プロセスとデータスキッピングを組み合わせることで、Z-Orderはクエリーが検索するために必要とする計算処理のボトルネックを引き起こすことなしに、インデックスが解決する検索対スキャンオペレーションと同様なものになります。
Z-OrderingにおけるべストプラクティスはZ-Orderのカラムの数を1-4に限定するというものです。我々はワーカーノードにブロードキャストするには大きすぎる最大3つのディメンジョンの外部キー(実際に強制される外部キーではなく使用する外部キーです)を選択しました。
OPTIMIZE MY_FACT_TABLE
ZORDER BY (LARGEST_DIM_FK, NEXT_LARGEST_DIM_FK, ...)
加えて、お使いのファクトテーブルが膨大なスケールで1000億の行、あるいはペタバイトのデータがあるのであれば、ファイルスキッピングをさらに改善するためにパーティショニングを検討すべきです。パーティショニングされたフィールドに対してフィルタリングをアクティブに行う場合にはパーティションが有効です。
4. ディメンジョンのキーフィールドと頻繁に使われる検索条件に対してZ-Orderを作成する
DatabricksはDeltaテーブルに主キーを強制しませんが、あなたはこの記事を読んでいるので、おそらくあなたはデイメンションとサロゲートキーを持っているのでしょう。これは整数値あるいは大規模整数値であり、ユニークであることが検証され、そうであることが期待されているのでしょう。
我々がこれまでに直面したディメンジョンの一つは10億行以上のデータであり、Z-Orderに検索条件を追加する前にファイルスキッピングと動的ファイルプルーニングのメリットを享受することができました。より小規模なディメンションでは、ディメンションキーに対するZ-Orderを行、ファクトとjoinする際にこれらはブロードキャストされました。ファクトテーブルでのアドバイスと同様に、Z-Orderのカラムの数をディメンションテーブルでキーに加えてフィルタリング条件に含まれるであろう1-4のフィールドに限定します。
OPTIMIZE MY_BIG_DIM
ZORDER BY (MY_BIG_DIM_PK, LIKELY_FIELD_1, LIKELY_FIELD_2)
5. Adaptive Query Executionオプティマイザの統計情報を収集するためにテーブルを解析する
Apache Spark™ 3.0における主な改善点の一つはAdaptive Query Execution、AQEでした。Spark 3.0時点でのAQEの主要な機能には、シャッフル語のパーティション数の強制、ソートマージジョインをブロードキャストジョインへの変換、偏りのあるジョインの最適化が含まれます。つまり、これらの機能によって、Sparkにおけるディメンジョンモデルのパフォーマンスを加速することが可能になります。
あなたのために、AQEがどのプランを選択するのかを知るには、テーブルに関する統計情報を収集する必要があります。ANALYZE TABLEコマンドを実行することでこれを実現することができます。我々のお客さまはテーブルの統計情報を収集することで、複雑なジョインを含むディメンジョンモデルに対するクエリー実行時間を劇的に削減できたとおっしゃっています。
ANALYZE TABLE MY_BIG_DIM COMPUTE STATISTICS FOR ALL COLUMNS
まとめ
上述のガイドラインに従うことで企業はクエリー実行時間を削減することができます。我々の事例では、同じクラスターでも90秒から10秒に削減できたケースがあります。これらの最適化によって適切なコンテンツのみを処理できるようになり、I/Oを削減しました。また、BIツールから行われるアドホックなタイプのクエリーを取り扱え、かつスケールできるDelta Lakeの柔軟な構造によるメリットを得ることができました。
この記事で述べたスキッピングの最適化に加え、DatabricksはDatabricks PhotoによるSpark SQLの性能改善に多大なる投資をしています。DatabricksにおけるあなたのすべてのSpark SQLクエリーの性能をブーストするPhotonをチェックしてみてください。
お客さまは、DatabricksランタイムでPhotonを有効化することでETL/ELTやSQLクエリーの性能を改善できると期待しています。ここで説明したベストプラクティスとPhoton有効化Databricksランタイムを組み合わせることで、ベストなクラウドデータウェアハウスを上回る低レーテンシーのクエリー性能の実現を期待することができます。
Databricks SQLを活用してスタースキーマデータベースを構築してみませんか。