クエリを分割するアプローチ採用したとき、はて?と思うことがあるようだ。なぜ何回もクエリを評価してしまうの?と。
Power Query エディタだけを眺めていると評価済みの結果が再利用されるのでは?そう錯覚したり期待するかもしれない。プレビュー用途や処理の都合上キャッシュが用意されることはあるけれど、別のクエリで再利用するという動作はしない。そもそも Power Query だけでクエリの評価結果を保存することはない。
たとえば
クエリの評価が一度だけとは限らない、つまり、クエリは必要なだけ繰り返し評価されるのはなぜ?という動作にはいくつかある。シンプルなケースで、
クエリ: SourceQuery を参照するクエリ、QueryA と QueryB があり、
QueryA が評価されるとき、SourceQueryは評価される。
QueryB が評価されるとき、SourceQueryは評価される。
ここでは SourceQuery は少なくとも2回評価されるということだ。一連のクエリの評価で Refresh All としても、QuaryA と QuaryB が個別に評価されるだけ。再利用するためにそれぞれ結果を保存するわけがない。
評価されたクエリの結果を使いまわせれば効率的なのでは?と思うかもだけど、SourceQuery の結果が 数 TB あったらどうするの。メモリがどれだけ必要なの?って話。扱えるデータ量にしきい値があるのは道具の用途としてよくない話だと思うね。
動作の実証
コードで実証するのは簡単
評価ごとに評価される動作
// SourceQuery
#table(
type table [Column1 = nullable text],
{
{
Text.NewGuid()
}
}
)
// Query1
SourceQuery
// Query2
SourceQuery
たとえば、Excel で [Reflesh All] してもそれぞれ異なる結果になる。
SourceQuery / Query1 で SourceQuery を参照 / Query2 で SourceQuery を参照 ですべてテーブルとしてロードしているから、少なくとも 3回
Table.Buffer 関数を使っても動作は変わらない。Table.Buffer を勘違いしているひと多いよね。
// SourceQuery
Table.Buffer(
#table(
type table [Column1 = nullable text],
{
{
Text.NewGuid()
}
}
)
)
バッファリングにより評価済みの値はメモリにキャッシュされるけれども、キャッシュが共有されるわけではない。
最初に理解すべきこと
見た目でそう思い込むことは不思議ではない。けど、クエリの評価結果を参照しているクエリに渡すという動作をしているわけではないということがポイント。
// SourceQuery
Text.NewGuid()
// Query1
SourceQuery
Query1 が評価されるとき、SourceQuery の評価結果、つまり "Text.NewGuid() の結果" を取得するのではなく式 "Text.NewGuid()" を参照しているということ。
思ったこと🙄
クエリの分割が可能というのは、論理的アプローチで実現している。
その他