Cognos Framework Managerのリレーションの設定でのパフォーマンスチューニング

#概要
へえ～、これ知らんかったわ、でもこれ、結構重要じゃね。
と、最近思ったシリーズです。

「こいつこんなのも知らんのか」と、スキルレベルがバレてしまいますが、気にせず投稿します。

今回の「へえ～」は、Framework Managerのリレーションのプロパティの一つである「(DQM)フィルター・タイプ」です。
![004.JPG](https://qiita-image-store.s3.amazonaws.com/0/147246/56726ab1-74b3-dacb-27be-61d87dd7ea66.jpeg)

#動きの説明
前述のSLS_PRODUCT_DIMとSLS_SALES_FACTを、PRODUCT_KEYでリレーション張っただけのモデルをパッケージとして発行し、こんなレポートを作ってみます。
例のプロパティは、とりあえずデフォルトの「なし」です。
PRODUCT_KEYはSLS_PRODUCT_DIM表から、QUANTITYはSLS_SALES_FACT表から取ってます。
![005.JPG](https://qiita-image-store.s3.amazonaws.com/0/147246/40b3d32b-1332-3167-ccea-f50f09c0d4ef.jpeg)

クエリーはこんな感じで、PRODUCT_KEYにIN句で、30010と30200にフィルターをかけています。
ちなみに、PRODUCT_KEYは、30001から30274まであります。
![006.JPG](https://qiita-image-store.s3.amazonaws.com/0/147246/f74caffb-7ae0-80c8-421f-165b4a6d5ffd.jpeg)

レポート実行すると、こんな結果です。
![001.JPG](https://qiita-image-store.s3.amazonaws.com/0/147246/bd0749c7-793d-1a10-c2a0-a99038b6048a.jpeg)

**(DQM)フィルター・タイプ = なし の場合**
どの設定でも、出力される結果は同じです。

発行されるクエリーが異なり、この設定では以下のクエリーが発行されます。
ちなみに、Db2側でアクセスパスを取得したところ、コストは **2248.25** でした。

```html
SELECT
    "SLS_PRODUCT_DIM"."PRODUCT_KEY" AS "PRODUCT_KEY", 
    SUM("SLS_SALES_FACT"."QUANTITY") AS "QUANTITY"
FROM
    "GOSALESDW"."SLS_PRODUCT_DIM" "SLS_PRODUCT_DIM"
        INNER JOIN "GOSALESDW"."SLS_SALES_FACT" "SLS_SALES_FACT"
        ON "SLS_PRODUCT_DIM"."PRODUCT_KEY" = "SLS_SALES_FACT"."PRODUCT_KEY" 
WHERE 
    "SLS_PRODUCT_DIM"."PRODUCT_KEY" IN ( 
        '30010', 
        '30200' ) 
GROUP BY 
    "SLS_PRODUCT_DIM"."PRODUCT_KEY" FOR FETCH ONLY;
```


**(DQM)フィルター・タイプ = 指定の値の間 の場合**
この設定では以下のクエリーが発行されます。
WHERE句で、SLS_SALES_FACTの方にもBETWEEN 30010 AND 30200という絞込みが入っているのがわかりますね。
つまり、IN句の指定値の中で、最小値の30010と最大値の30200でBETWEENしています。
これにより、SLS_PRODUCT_DIMの結果データと、SLS_SALES_FACTの結果データを結合(INNER JOIN)する前に、SLS_SALES_FACT側のデータが絞り込まれているので、結合の対象となるデータ量を少なくすることができます。
アクセスパスのコストは、残念ながらちょっと上がって **2331.92** でした。

```html
SELECT
    "SLS_PRODUCT_DIM"."PRODUCT_KEY" AS "PRODUCT_KEY", 
    SUM("SLS_SALES_FACT"."QUANTITY") AS "QUANTITY"
FROM
    "GOSALESDW"."SLS_PRODUCT_DIM" "SLS_PRODUCT_DIM"
        INNER JOIN "GOSALESDW"."SLS_SALES_FACT" "SLS_SALES_FACT"
        ON "SLS_PRODUCT_DIM"."PRODUCT_KEY" = "SLS_SALES_FACT"."PRODUCT_KEY" 
WHERE 
    "SLS_PRODUCT_DIM"."PRODUCT_KEY" IN ( 
        '30010', 
        '30200' ) AND
    "SLS_SALES_FACT"."PRODUCT_KEY" BETWEEN 30010 AND 30200 
GROUP BY 
    "SLS_PRODUCT_DIM"."PRODUCT_KEY" FOR FETCH ONLY;
```

**(DQM)フィルター・タイプ = テーブル の場合**
この設定では以下のクエリーが発行されます。
さすがに最後にもってくるからには、良い結果なんだろうと想像されたと思いますが、その通りです。
WHERE句で、SLS_SALES_FACTの方にもPRODUCT_KEYが 30010 と 30200という絞込みが入っているのがわかりますね。
つまり、IN句の指定値で絞込みしています。
これにより、SLS_PRODUCT_DIMの結果データと、SLS_SALES_FACTの結果データを結合(INNER JOIN)する前に、SLS_SALES_FACT側のデータが絞り込まれているので、結合の対象となるデータ量を少なくすることができます。
アクセスパスのコストは、ちゃんと落ちが付いて良かった **1346.86** でした。

```html
SELECT
    "SLS_PRODUCT_DIM"."PRODUCT_KEY" AS "PRODUCT_KEY", 
    SUM("SLS_SALES_FACT"."QUANTITY") AS "QUANTITY"
FROM
    "GOSALESDW"."SLS_PRODUCT_DIM" "SLS_PRODUCT_DIM"
        INNER JOIN "GOSALESDW"."SLS_SALES_FACT" "SLS_SALES_FACT"
        ON "SLS_PRODUCT_DIM"."PRODUCT_KEY" = "SLS_SALES_FACT"."PRODUCT_KEY" 
WHERE 
    "SLS_PRODUCT_DIM"."PRODUCT_KEY" IN ( 
        '30010', 
        '30200' ) AND
    "SLS_SALES_FACT"."PRODUCT_KEY" IN ( 
        SELECT
            "joinKeyQuery"."joinKey1"
        FROM
            (
            VALUES 
                (30010), 
                (30200)
            ) "joinKeyQuery"("joinKey1") ) 
GROUP BY 
    "SLS_PRODUCT_DIM"."PRODUCT_KEY" FOR FETCH ONLY;
```

という感じですね。

フィルターで指定される値が大量にある場合は「指定の値の間」、少ない場合は「テーブル」を指定するのが正解なのかな。
この設定、これまで気にした事無かったですが、なんか普通にリレーションの使い方考えて、「指定の値の間」か「テーブル」か、どっちかに設定しておいた方がパフォーマンス良くなるんじゃないか、と思い、今度実戦で使ってみようと思う次第です。
皆様も是非使ってみて頂き、知見が得られたらフィードバック頂けると幸いです！