(Power BI) IFとIF.EAGERのパフォーマンス測定　：DAX Studioをはじめてみる #2 

　DAXには、条件判断として **IF** と **IF.EAGER** があります。 **EAGER** とは何なのか、何の役に立つのか、sqlbiの ["Understanding eager vs. struct evaluation in DAX"](https://www.sqlbi.com/articles/understanding-eager-vs-strict-evaluation-in-dax/)を参考に考えます。

# EAGER とはどういう意味ですか
　eagerは一般的には「熱望する」とか「熱心に」などとと訳されます。
　書式はIFもIF.EAGERも同じです。以下はIF.EAGERでの書式です。

```text
IF.EAGER(
        <logical_test>          // TRUEまたはFALSEに評価できる値または式
        ,<value_if_true>        // logical_testがTRUEの場合に返される値
        [, <value_if_false>]    // （省略可能）logical_testがFALSEの場合に返される値。省略した場合はBLANKが返されます。
)
```

　違いは、評価と計算の実行の仕方です。
　専門用語では、IF.EAGERは **EAGER EVALUATION（先行評価）**、一方、通常のIFは **STRICT EVALUATION（正格評価）** と表現されます。熱心な評価と厳格な評価の違いは何でしょうか。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864075/db63c571-ee46-ca9e-4b89-5325c0d64fa6.png)

　また、返される値の型は、TRUEの場合とFALSEの場合いずれも同じにならなければなりません。異なる場合は、同じ型になるよう変換されます。


# どちらが効率的なのか
　トータルのリソース的にはIFの方が効率的なように見えます。IF.EAGERでは、せっかく計算させた結果を捨てているのですから。
　しかし、場合によってはIF.EAGERの実行速度がIFを上回る場合があります。

- 複雑な式 Complexity of the expressions depending on a condition
    - 分岐先の式が非常に複雑な場合、IFを使った方が必要な計算を減らすことができます。
- 条件式やTRUEとFALSEの計算が再利用可能 Presence of common sub-expressions in the expressions depending on a condition.
    - 同じ部分式が別の実行分岐で使用される場合、IF.EAGERは、部分式をキャッシュし最適化することができます。IFでは、複数回計算されます
- 結果の粗密 Sparsity of the result.
    - 一方への分岐が少数の場合、IFの方が必要な計算の数を減らすことができます。


# DAX Studioで検証
　DAX Studioを起動して、以下のDAXで調べてみます。Server Timingsをオンにして、

```text
DEFINE
    MEASURE Sales[m1] =
        SUM ( Sales[Units Sold] )

EVALUATE
{
    IF(
        ISBLANK ( [m1] ),
        0,
        [m1]
    )
}
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864075/6e1de280-5d1f-0292-22d9-69852d15f74f.png)

　Queryは２回実行され、最初に ISBLANK([m1]) が評価され、次に [m1] の評価が行われています。IFを使う場合は、必ず２回評価されます。

　次に、IF.EAGERを使って測定してみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864075/3a82ab6c-e739-310a-e2f2-08cedecd5c60.png)

　Queryは１回しか実行されていません。条件式やTRUE、FALSEの式に再利用できる計算がある場合は計算が最適化され、IF.EAGERはパフォーマンスがいい可能性があります。

　しかし、LayoutのCacheをオンにしてもう一度２つの結果を見比べてみると、クエリの間にCacheが入っていることがわかります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864075/40a1961b-6dee-7c4b-da05-777d052c61ec.png)

　これは、２回目のクエリでは１回目のキャッシュを利用しており、ほとんどパフォーマンスが落ちていないのです。
　２回目のクエリの内容を、キャッシュの利かないものにした場合、Cacheの表示がなくなり、Durationに数字が上がるようになります。再利用可能な計算かどうかは、Formula Engineが判断します。同じような計算でも、フィルター・コンテキストが異なる場合は、再利用されません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864075/8a032402-d3ad-5316-ffd2-f3b9afbd0f94.png)

　また、同じものをIF.EAGERで実行すると、まったく使われない分岐先の不要な計算も評価されてしまいます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864075/cfeb77ed-6c4b-0118-ea6b-7ed9248349c2.png)

# Storage Engine (SE) vs Formula Engine (FE)

https://www.sqlbi.com/articles/formula-engine-and-storage-engine-in-dax/

　画面上にSEやFEと表示されているのは、Strage Engine、Formula Engineのことです。
　
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864075/98771952-65ac-6c27-10b2-cc50504f2c5f.png)

　クエリは、最初にFormula Engineに渡り、**Query Plan**を作成します。次にStrage Engineが物理的なアクセスを行って必要なデータを取得します。取得されたデータ・キャッシュは、Formula Engineに渡され、残りの計算を実行し、Power BIに結果が送られます。

　Strage EngineがFormula Engineと切り離されているアーキテクチャになっていることで、異なる種類の物理デバイスにアクセスする別のエンジンに変更することができます。

# 結論
　IF式の最適化された計算により、パフォーマンスはほとんど問題ない場合が多いです。
　ただし、計算が複雑で、かつ共通の部分式を持っている場合、IF.EAGERが早い可能性があります。

　図で示すと、以下のような「３回計算してるけど、実質頑張ってるのは一人だけの図」になる？（あとの二人はコピペ？）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864075/424eaa2f-258d-3992-f999-ab0d293ed2e7.png)