テクテク日記

テクテク=テクノロジー&一歩ずつ(テクテク)

Jeffrey WangによるDAXエンジンの解説②

Power BI CATチームのKasperさんのYoutubeチャネルにPower BI DAXエンジンの開発者であるJeffrey Wangさんが登場しました。今回はその②となります。

DAXに関する質疑応答

9. DAXの仕組みについて教えてほしい

DAXは非常にシンプルで、ユーザーが深く考える必要なく結果を得られることについて強調しておきたい。例えば、AVERAGEXで毎月のユニークな顧客数カウントするケースでは、テーブルに対してスキャンを行う手法であるものの、それ自体の計算ロジックはシンプルである。しかし、SQL出身の人からすると行レベルでスキャンして、DISTINCTCOUNTを行うのは自殺行為であり、計算が異様に遅くなってしまうだろうと心配される。しかし、DAXは最適化によりパフォーマンス上の弱点を克服している。

たまにDAXクエリがStorage Engine(SE)とFormula Engine(FE)のどちらで実行されているのかが分からないと気にする人がいるが、単純に言えば、

SEクエリとなるのはDAXが元データレベルでテーブルを参照する時のみであり、理論的にはそれ以外は全てFEで処理される

ことになる。

しかし実際にはこれをやった場合、非常にシンプルな計算でもテーブルを全てスキャンすることになるため、それではパフォーマンスが非常に悪くなってしまう。これが分かっていたからこそ、Power BIのDAX開発チームはDAXエンジンに対する途方もない最適化投資を行ってきた。

そして、クエリがSEとFEのどちらで処理されるかについて困っている人には申し訳ないが、SE/FEのどちらのエンジンで処理されるかはDAX言語によって決められているのではなく、製品開発チームがDAXエンジンに対して行ってきた最適化に左右されるものとなる。

10. DAXのDebugについて教えてほしい。これまでの話で最適化について話してきたことや、Debug用の関数も登場しているので、どのようにやれば良いか?

Debug関数に関してはある程度役に立つでしょう。DAXSQLも宣言型プログラミングです。例えば、SQLステートメントでTable1とTable2をジョインして、さらにTable3をジョインするように記述したとする。しかし実際には、SQLサーバーはカーディナリティを推測して、もしかしたら先にTable1をTable3とジョインし、最後にTable2をジョインするかもしれない。これは一例に過ぎないが、計算エンジンは結果は同じでもまったく違う実行戦略を選択するかもしれない。

DAXはこの実行戦略を極限にまで最適化したものである

その最たる例がFusion機能である。例えば、DirectQueryにおいてSUMXAVERAGEXを使うとする。まったく異なるメジャーでありながらも、全体で見たとき、別々の場所に存在するものを1つのクエリに送ることで複数のクエリではなく、1つでのクエリで実行できる。しかし、この最適化もEVALUATEANDLOGという新しい関数を使うと最適化が途切れてしまうため、この関数を使ってどのような最適化がなされたかを特定することに一番良い方法ではないだろう(関数の詳細は以下より)。

EVALUATEANDLOG AND DAX ENGINE OPTIMIZATIONS – pbidax

むしろ、この関数は結果の正誤性のチェックを行う際に使うと考えた方が正しいだろう。特徴として、どのようなDAX関数(メジャー)でも括ることができ、結果は変わらないが、途中までのDAXの実行ステップをプリント(表示)させることができる。ちなみにChris Webbがパフォーマンス測定用にこの関数の実例を紹介しているが、非常に素晴らしい考え方である一方、この関数の一般的な目的ではないことに留意してほしい(=パフォーマンスを調べるのではなく、正誤性チェックというが本来の目的)。

11. (何度も議論してきたことなので申し訳ないが)クエリプランをDebugできるようなツールを作ることは現実的か?

絶対に無理とは言いたくないが、その前に、DAX Debuggerを作りたい。そして一番最初にやりたいのは、評価コンテキスト(Evaluation Context, Row Context/Filter Context)を可視化させること。うまく受け入れられれば、難しい概念ではないのだが、一番のボトルネック評価コンテキストは目に見えないという部分である。

12. DirectQuery(DQ)の仕組みについて

DQについて誤解を持つ人は多くいるが、理由の1つとして今までは別のツールを使ってきたことにある。他のツールでDQを使ってビジュアルを作ったりしているわけだが、それらはSQLクエリで作られているものである。SQLに詳しい人は自分たちのやっていることがSQLで実現できると信じているが、多くの場合において簡単なメジャーを使っている時に正しいと言える。

そして、DAXSQLは根本的に違うとはっきり認識すべきである。なぜなら、DAXは一度定義すればあらゆるコンテキストで再利用可能であり、特定のビジュアルでしか使用できないものではない(=DQのように1つのSQLクエリに変換することを目的としたものではない)。

ちなみに、以前開発チームで試したことであるが、1つのクエリで処理を全て完結させるよりも、複数のクエリを送って処理させたほうがパフォーマンスが余程良かったことがある。これは、SQL Query Optimizerが複雑なクエリを処理できるようにデザインされているわけではないことに起因している。

そして注目すべきはDAXクエリをもって複数のSQLステートメントを集約してSQLサーバーへ送って処理できる機能を利用すれば、1つのクエリで処理が困難なクエリを効率良く実行することも可能となったことである(例:2つのファクトテーブルに対する処理等)。

最終的に「DQとは何か?」という質問に対する回答としては以下のことが言える。

  1. Power BIはSQLクエリをビルドしているのではなく、DAXクエリをビルドするツールである
  2. DQの場合、DAXエンジンは可能な限り、SQLサーバーへ最大限のワークロードをプッシュして処理させている
  3. DAXクエリはSQLクエリとは根本的に異なっており、最適化が行われていなければ、Power BIでDQを使用した場合、パフォーマンスが非常に遅くなってしまう可能性がある
13. Fusionについて簡単に教えてほしい

Fusionについて話をする前に、まずDAXメジャーについて知ってほしい。データの世界ではメジャーは革新的なものである。Excelで同じ概念のものはないし、SQLの世界でも同じ。メジャーを複数追加した場合、それぞれは独立したものであり、パフォーマンスを最大化させるため、DAXエンジンはディープな分析を行い、もし理に適うようであれば、それぞれのメジャーから1つずつクエリをSQLサーバーに送るのではなく、複数のクエリを1つに結合させて1回で処理を終えるよう、最適化を行う。

初期バージョンのFusionは異なる列の集計を結合して処理を行うものであった。条件として列が同じテーブルにあること、そして1つのSQLクエリに集約することができた場合、SEで処理を行うことができるようになる(DirectQueryとVertipaqエンジンのどちらでも同じ)。

最近のHorizontal Fusion(水平融合)はネーミングこそディスられているが、概念として例えば同じ列を集計していても、異なるフィルターを適用した場合(例:直近1年の売上と1年前の売上を算出する場合)、それを1つの処理で実行できることを意味する。簡単に考えるのであれば、複数の独立したメジャーで今まで複数発生していたSEクエリを1つにまとめて処理を行うことができるようになったことになる。

HF = Horizontal Fusion

14. DirectQuery(DQ)は遅い・問題が多いという批判をする人がいるが、共通する問題点は何か?

いくつかあるが以下のようなケースでしょうか。

  1. Power BIを使用すれば、複雑なモデルを簡単に作ることができてしまう
    複雑な指標であっても簡単にメジャーで書くことができてしまう。そしてDQを使用する多くのケースとして、データ量が多すぎることであるが、Power BIがSSBIとしてスタートしたことを考えると、期待値の部分でどうしようもないことがあると言える。
  2. RLS(Role Level Security)による影響
    モデルを構築した最初からRLSを設定していないユーザーがある時点で設定を行うとパフォーマンスが著しく落ちたことを確認してしまうケース。アドバイスとしてモデリングの初期からRLSの搭載を考慮したモデリングを行うこと。
15. 複合モデル(Composite Model)の主要なユースケースとは?

アドバイスとしては以下のようなケースが考えられる。

  • 複合モデルを本番環境で運用したい場合のTipsとして、データ量を控えめにすることである。そうでなければ、仮にデータ量が多いエンタープライズモデルであった場合、複合モデルのように別のモデルに繋げるのではなく、既存モデルをカスタマイズするのが最も好ましい(パフォーマンス的な問題やモデルの制約等の問題より)。
  • どうしてもモデルを追加する必要がある場合、データ量の少なく、カーディナリティの低いテーブルを追加することをお勧めする。
  • データ量の多いモデルを複合モデルとして使用するケースとして、ユーザーが単純にPower BI Desktopでチャートを作ってそれを使う必要がある場合が好ましい。
  • チームでモデリングをする必要がある場合、マスターモデルを1つ作り、それを基に複合モデルを作る。各モデリング担当者がそれぞれの複合モデルでモデリングを行い、最後に同じデータアイランド内にて1つのモデルとしてマージさせていくのも面白いかもしれない。

面白いことに、多く人がデータサイズを考慮せず複合モデルを量産することがあるが、こちらはお勧めできない。理由は"物理の法則"を考えれば分かる通り、異なるロケーションに存在するモデル同士をリレーションシップで繋げることは、物理的にデータを移動させることになるため、Power BIがいくら便利であると言っても克服できない問題の1つである。

16. 複合モデル(Composite Model)がなかなかGA*1にならない理由とは?

多くの理由があるが、Power BIサービスサイドの問題は以下のようなものが挙げられる。

エンジンサイドの問題は以下のようなものが挙げられる。

  • DAX(評価コンテキスト)が難しい。すなわち、ローカルモデルでの評価コンテキストをリモートモデルでも再現させるための技術的なエフォートが必要
17. DAXにおいて絶対にないこととは?
  • DAXは絶対にSQLにはならないだろう
  • DAXは絶対にMDXにはならないだろう
18. 前回話に出てきたStop & GoアプローチはDAXにはない概念ということであるが、CALCULATION GROUPSの概念が似ているのではないか?

試験的に導入したものではあるが、その通り。CALCULATION ITEMSでメジャーを調整するが、クエリをフルに実行する前の段階で行われるのが特徴である(中略)。

19. 機能を追加する時、最もチャレンジングなものはなんだったか?

複合モデル、バーチャルカラム、Fusion(フュージョン)が最も難易度が高かいものであった。特にFusionはグローバルな最適化が必要なため、クエリツリーのあらゆる部分(非常に多くの変数)からマージできる組合せ等を見つけ出して最適化をしていくため、非常に大変な作業である。また、エラーが生じやすいのも難易度を高めている要因の1つとなる。

20. DAXの新しい機能が誕生したとしても、そのまま製品に搭載することはできない。フロントエンドのプロダクト(Power BI Desktop等)でその機能が動くことを確かめなければいけないのが難しいですよね?

その通り。例えば、まだリリースできない「ダイナミック計算列」という機能がある。DAXエンジンサイドで機能が動いたとしても、フロントエンドの機能としてユーザーによるフィルターに呼応する必要があるため、Power BI Desktop側の調整が必要となる。また、DAXエンジンではなくMDXベースで動くExcelでそれを実現しようとするどうなるべきか、といった問題に対しても答えを用意しておく必要があり、実現するまでに越えなければいけない壁が多く存在している。

21. 振り返った場合、もっと早めに追加しておくと楽だったDAX機能は何だったか?

これは皮肉にも、追加しなければよかったか、あるいは、もう少し別のアプローチで対処できたかもしれないという振り返りに近いのだが、やはり

Row ContextとFilter Context

だろう。DAXを学ぶ人はなんといってもこの2つのコンセプトで苦労しているのは事実である。MDXのようなコンセプトにできれば良かったのだが、問題はMDXはFilter Contextという概念しかなく、非常にシンプルな結果を得るためでも非常に難しいことをしなければならなかった(例:MDXは計算列という概念が存在しない、等)。

そこでDAXによるこれら2つのコンテキストが登場したのだが、開発チームとして最初はこれらの概念を知らなくてもソリューションを構築できるであろうと想像していた。ところが、開発サイドの想定とは裏腹に、Filter Contextという概念をかなり早い段階で学ぶ必要があったことが実証され、これによりRow Contextも一緒に学ばないとDAXを自在に使いこなすことが困難であるということが分かった。

これはまったく想定していなかったことであり、もう少し別のやり方があれば良かったと思っている。

22. 新しい開発者がチームに加わった場合、どのようにして最速のペースで戦力化を図っていくか?恐ろしいほどに複雑なDAXエンジンについての理解と、DAXそのものについての理解も必要であろう。

結論から言うと、簡単な方法はない。最初は書き方についていろいろ教えることからスタートするが、やはりこのユニークな言語に対して興味を持てるかどうか、という部分が重要であろう。

23. DAXを学ぶ上で最も良いアプローチは何か?

DAXはReusable Calculations(再利用可能な計算=一度定義すればどこでも使える)という意味において、非常に革新的なコンセプトを持っている。プロのエンジニアとして様々なプログラミング言語を見てきたが、同じ概念の言語に出会ったことがない。似ているものがあるとすれば、LAMBDA関数であろう。

それゆえ、DAXを学ぶ上で重要なことは、この新しい概念(評価コンテキスト等)を受け入れ、素直に学ぶことである。学習曲線の最初のカーブが最も苦労するだろうが、いったん慣れてくれば、後は非常に簡単に感じるようになるだろう。

24. 過去1年のうち、Power BIで登場した最もエキサイティングな機能は何か?

ウェブオーサリング機能(データマート等)に注目したい。現時点ではまだ始まったばかりであるが、新しい市場を切り開くために非常に大事な第一歩であると考えている。

*1:General Availabilityの略。 プレビュー(ベータ版)を終えて、一般提供(正式版)に切り替わることを意味する