前回は「リンクされたエンティティ」の更新時の動作について検証しましたが、今回はそれに加えて、「計算されたエンティティ」に関するシナリオも見ていきます。前回よりも詳細に掘り下げていますが、最後まで読んでいただければ、データフローの更新ロジックについての理解が深まると思います。
計算されたエンティティ
「計算されたエンティティ」とは、同じデータフロー内のテーブルを参照したり、異なるクエリをマージ・結合するなど、ある種の演算を行って作り出されるエンティティのことです。例えば、Salesテーブルを参照してSalesQtyByCustomerというクエリを作った場合、アイコンが⚡の状態となり、これが「計算されたエンティティ」となります。
また、単純に参照を行っただけでも「計算されたエンティティ」となります。
今回の例では、「計算されたエンティティ」は、データソースではなく、既にキャッシュされたテーブルであるSalesを参照して、新たにキャッシュされたテーブルを作り出します。オンプレミスデータの場合、データ更新のたびにゲートウェイの負荷が増加してしまうため、データフローのベストプラクティスの1つとして、ステージングデータフローを作成し、それを参照して変換用のデータフローを構築することが挙げられます。
ただし、例外的な場合として、Salesクエリが読込無効であった場合、Salesを参照したSales (2)が直接ソースに接続されることになります。そのため、Salesはスキップされ、Sales (2)がステージングクエリとして扱われます。Sales (2)を更新する際には、元々のデータソースからデータを取得することになり、オリジナルソースに負担がかかるようになります。
シナリオ
シナリオはシンプルで、以下のようになります。
ポイントはDF2におけるSales Aというテーブルを無効にした場合、以下の質問に対する回答がどのようになるかとなります。
- Sales Bは「リンクされたエンティティ」になるのか、それとも「計算されたエンティティ」になるのか
- どこでPower BIのリソースが使用され、オリジナルソースであるDBはどのような影響を受けるのか
- DF1を更新した場合、どのような結果になるのか
- DF2の場合、各テーブルの更新はSalesクエリのソース先(オンプレデータ or 異なるワークスペースにあるデータフローを参照)別にどう違うのか
検証
1の「どちらのエンティティになるか」というのはすぐに確認できます。下記のダイアグラムに示される通り、Sales B⚡は「計算されたエンティティ」となります。Sales Aの読込を無効にしても、Sales BがSales Aを参照した場合、間接的にはSalesを参照したことになるため、Sales BもSalesと同じエンティティになることになります。
次に、DF1とDF2のリソース消費場所やオリジナルソースへの影響についても簡単に説明します。DF1の更新はすべてオリジナルソースに負担がかかります。DF2はDF1がキャッシュされた状態を参照するため、Power BIサービスの処理エンジンを通じて実行されます。
3と4ですが、DF1が更新された場合、「リンクされたエンティティ」について前回の記事で説明したように、以下のようになります。
一方、DF2を更新した場合、DF1やオリジナルソースに影響があるかどうかが気になるかもしれません。しかし、通常はDF2の更新がDF1やオリジナルソースに影響を与えることはありません。これは、DF2がDF1のキャッシュされたバージョンを参照しているためであり、DF2が更新された場合、変更はDF2自体に限定されるようになります。
しかし、ここで1つ疑問が生じます。Sales Aを読み込まずにSales Bとして参照するために、異なるワークスペース(Workspace A)にあるSalesテーブルを参照する場合、Workspace AのSalesテーブルが更新された場合、Sales Bは最新の情報を参照することができるのでしょうか?順番として
- Workspace AのSalesが更新される
- Workspace BのSales Bは自動的に最新の状態に更新されるかどうか?
となります。(下図)
念の為、この例ではSales AをSales A'、Sales BをSales B'とします。
これを元に構築したSales B'を見ると、下図のようになりました。
どうやら、異なるワークスペースにあるTable(今回の例ではWorkspace AのSales)を参照した読込無効のクエリ(Sales A')を更に参照して作成したSales B'は、同じワークスペース内のものと同じように「計算されたエンティティ⚡」にはならず、あたかもDF1がGatewayを通じてオンプレミスデータを抽出したかのようなクエリになってしまうようです。異なるワークスペースはPro / Premium環境に関係なく、全て同じように適用されます。
となると、上記Currency Codeでグループ化された状態のSales B'(Currency Code)は、Workspace AのSalesが更新されたとしても、自動的に更新されないだろうと推測されます。試しに、⚡Sales BとSales B'の両方のソースであるSalesの行数を増やしてみます。前回のデモではTable.Repeat関数を使って行数を2倍に増やしましたが、これを3倍にしてみます。
同じワークスペースにある場合
同じワークスペースにある場合、⚡Sales Bはすぐに反映されました。
異なるワークスペースにある場合
ワークスペースAにあるSalesを同じく3倍に設定し、保存 > 更新を実施。
しかし、結果は予想通り、異なるワークスペースにあるクエリを参照していることから、結果はBeforeと変わらず。
Workspace Bの当該データフロー(Dataflow_PPU)を下記より更新してもう一度見ると、結果はようやく更新された状態に。
更新履歴による確認
細かい話が多くなっていますが、この仕組みを理解していないと、無駄にデータフローをスケジュール更新させたり、不用意にリソースを無駄に使ってしまうことになります。クエリが適切に更新されたかどうかを確認するためには、やはりデータフローの更新履歴を可視化することが良い方法であり、前回と同様、下記のダウンロード🔗リンク先のDataflow_RefreshHistory_dynamic_header_pq.pbixを少しカスタマイズしたものを使って、これまで述べてきた更新状況を確認してみます。
更新による確認は以下2つを想定します。
- DF1を更新
- DF2を更新(DF2の中にはSales BとSales B'の2つが含まれる)
DF1を更新
1の更新結果は以下の通りです。
おさらいになりますが、Power BI Proの環境では、対象となるSalesテーブル(約40万行)が1分間で更新されたことしか分からず、それ以外の有用な情報を得ることができません。
そこでWorkspace A(Pro環境)のデータフローをWorkspace C(Premium環境)へ移行して、更新履歴を確認してみたいと思います。以下、図説となります。
- Workspace Aから「.jsonのエクスポート」
- Workspace C > 「新規」>「データフロー」
- 「モデルのインポートモード」
- JSONを保存した場所からインポート
- インポートされたDataflow_Proを更新
- エラーの発生
ここまで流れ作業ですが、最後の最後でショッキングな更新エラーが発生してしまいました。しかし、更新履歴を見ることでその理由をある程度掴むことができます。続けて以下のように進めていきます。
- Dataflow_Proの更新履歴を保存
- 保存した履歴の中身を「Dataflow_RefreshHistory_dynamic_header_pq.pbix」で確認
どうやら、資格情報の認証に問題がありそう。となれば、認証をもう一度設定するだけです - 「接続の構成」
-
資格情報を入力
- データ確認 > 「今すぐ更新」
- 更新履歴の保存
保存できたら、もう一度「Dataflow_RefreshHistory_dynamic_header_pq.pbix」で可視化を行う。
- 更新履歴の再度チェック
「Dataflow_Pro」という名前のデータフローはそのままで、Premium環境において更新が行われることになりました。このため、処理するデータ量や時間などがわかりました。ここで注目すべき点は、コンピューティングエンジンが使用されていないことです。その理由は、この更新がゲートウェイを経由したオリジナルソースデータの更新であるためです。
Pro tips ①:
データフローの名前を変更する場合、以下のように行います。
DF2を更新
DF2のデータフローを更新を説明する前に、もう一度系列及びクエリの依存関係について確認しておきます。
まず、オリジナルソースはSQL Serverでゲートウェイが必要となります。
更新されるクエリはa) Sales、b) Sales B、c) Sales B'の3つ。
- Sales
SQL Serverのデータを更新するために、ゲートウェイを介してアクセスします - Sales B
Salesを参照するSales A(読込無効)に基づいて作成された「計算されたエンティティ」。コンピューティングエンジンを使用して最適化を実現可能 - Sales B'
異なるワークスペース(Pro環境)にあるSalesクエリを、読込無効のSales A'として参照し、Sales B'を構築。Sales Bと同じく、Sales B'もCurrency Codeでグループ化処理を実施
既にデータの更新ロジックについて確認していますが、下記の更新履歴を見ることで、より深い理解ができると思います。
①~④に対する解釈は以下の通りです。
- Salesクエリはフル更新が必要であり、更新には24秒かかっています。このクエリはキャッシュされた状態であり、Sales Bはこのキャッシュ状態を利用して処理されます
- Salesの更新が終了した直後、Sales Bの更新が開始されます
- コンピューティングエンジンは、キャッシュされたデータを参照して処理を行うため、クエリフォールディング(折りたたみ処理)が行われ、更新時間(08.期間)は1秒未満です
- Sales B'は異なるワークスペース(Workspace A)のSalesを参照しているため、キャッシュされたデータを利用した処理は行われません。そのため、コンピューティングエンジンは使用されず、更新時間はSales Bよりも長い4秒となります
データフローの更新履歴を可視化することにより、各クエリのパフォーマンスや、ボトルネックになっているクエリを特定しやすくなる可能性が高くなります。
Pro tips ②:
更新履歴は、スライサーでフィルターできるように、分かりやすい名前のファイルに変更しておくことをお勧めします。更新の開始時間などの情報は履歴の中に入っているため、ファイル名を参照する必要はありません。
クエリフォールディングの重要性
オリジナルのデータソースがクエリフォールディングに対応している場合、DF1の更新がかなり早く終わる可能性が高くなります。Power Queryのベストプラクティスの1つに、常にクエリフォールディングを可能な限り、「適用されたステップ」の最後まで実行することが挙げられます。クエリフォールディングは、ソースシステムに処理をプッシュバックすることで、処理が大変なオペレーションをソースシステム側で処理する機能です。これにより、1つのT-SQL構文で処理を完結させることができます。
この場合のクエリフォールディングはオリジナルソースのデータベースが行いますが、上述したWorkspace B(プレミアム環境)にあるDataflow_PPUのSalesクエリでは、キャッシュされたSalesに対してコンピューティングエンジンがその威力を発揮します。
繰り返しになりますが、
クエリフォールディングが効いているかどうか
を常に気をつけながら進めていくことが重要です。
まとめ
「計算されたエンティティ」はデータフローにキャッシュされたクエリを参照して実現されます。読取専用である「リンクされたエンティティ」とうまく使い分けることで、業務効率を大幅に改善させることができるでしょう。
- データフローの更新ロジックに対する理解
- 履歴の可視化(更新エラーの確認なども可能)
上記2つを念頭にデータフローを構築されると、デバッグに際しても効率良く行うことが可能になると思います。次回はデータフロー構築に際しての戦略について、どのような選択肢があるかを見ていきたいと思います。