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


概要

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

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

今回の「へえ~」は、Framework Managerのリレーションのプロパティの一つである「(DQM)フィルター・タイプ」です。

動きの説明

前述のSLS_PRODUCT_DIMとSLS_SALES_FACTを、PRODUCT_KEYでリレーション張っただけのモデルをパッケージとして発行し、こんなレポートを作ってみます。
例のプロパティは、とりあえずデフォルトの「なし」です。
PRODUCT_KEYはSLS_PRODUCT_DIM表から、QUANTITYはSLS_SALES_FACT表から取ってます。

クエリーはこんな感じで、PRODUCT_KEYにIN句で、30010と30200にフィルターをかけています。
ちなみに、PRODUCT_KEYは、30001から30274まであります。

レポート実行すると、こんな結果です。

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

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

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 でした。

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 でした。

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;

という感じですね。

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