マルチディメンショナル・データベース問合せのパフォーマンスのチューニング

Oracle Analyticsでデータ・ソースとしてマルチディメンショナル・データベースを使用する場合、パフォーマンスの問題が発生し、最適ではないマルチディメンショナル式(MDX)問合せが生成される結果になることがあります。

設計を変更することで、Oracle Analyticsによって生成されるMDX問合せを改善できます。これは、レポートのパフォーマンスだけでなく、データベースで使用されるリソースの量にも非常に大きな影響を与える可能性があります。サポート対象またはサポート対象外の機能を使用する方法は、生成されるMDX問合せとパフォーマンスに大きな影響を与えます。

各ユース・ケースは一意であるため、開発チームは、オプションの確認、Oracle Analytics問合せログの分析、およびユース・ケースに応じた最適なソリューションの選択を行う必要があります。

このトピックは、ネットワーク、ブラウザ、レポート表示などのインフラストラクチャによって引き起こされるパフォーマンスの問題は対象としていません。

方法

パフォーマンスを向上させるために次のタスクを実行することをお薦めします。MDX問合せ構造と、Oracle Analyticsが生成する問合せログについて理解することが重要です。

  • 生成されるMDX問合せを単純化します。
  • 生成されるMDX問合せの数を減らします。
  • MDX問合せで最適なフィルタおよび選択が適用されていることを確認します。
  • マルチディメンショナル・データベースでデータベース管理者(DBA)とともにパフォーマンスをチューニングし、ソース・データベースのパフォーマンスが低いままである理由を検証します。
  • DBAのフィードバックに基づいて分析を変更します。

選択ステップの最適化

選択ステップを最適化すると、MDX問合せを単純化し、生成されるMDX問合せの数を減らして、パフォーマンスを向上できます。

次の図は、最適化された選択ステップと最適化されていない選択ステップの比較の例です。

GUID-43E6F348-B14C-40DC-8C21-DA34DAE44344-default.jpgの説明が続きます
.jpgの説明

CASE文

CASE文の機能は、MDX問合せでサポートされておらず、Oracle Analyticsで常に適用する必要があります。CASE文に関してこの項で説明するロジックは、MDX問合せでサポートされていないほとんどの機能(if nullなど)に対して有効です。

CASE文を使用する場合、利点と欠点があります。レポート式にCASE文を入れると、MDX問合せに含まれなくなります。これにより、MDX問合せがシンプルになり、パフォーマンスが向上します。ただし、効果的にフィルタできないというデメリットがあるため、問合せで必要以上のレコードが返される可能性があります。

CASE文の機能を使用する場合の制限事項は次のとおりです:

  • CASE文で複数のメンバーを結合しない場合、文で使用されるベース列を問合せおよび(非表示の個別列として)ビューに含める必要があります。
  • CASE文で複数のメンバーを結合する場合、集計のレベルに影響を与えずにベース列をビューに含めることはできません。これが該当する場合:
    • メジャーの集計ルールが外部集計である場合、ベース列を問合せから除外する必要があります。
    • メジャーの集計ルールが外部集計である場合、ベース列を問合せに含め、ビューからは除外する必要があります。メジャーの集計ルールをデフォルトから単純な内部集計ルール(SUMMAXMIN)に変更する必要があります。これが機能するのは、メンバーを結合して正しい結果を提供するために内部集計ルールが使用される場合のみです。

FILTER関数

CASE文の機能とは異なり、FILTER関数は実行のためにデータベースに提供できます。

レポート式でFILTER関数を使用することの主なメリットは、MDX問合せで選択が適用され、データベースから計算および取得されるデータの量が減少することです。

FILTER関数を使用することの主なデメリットは、実行されるMDX問合せの数が増加する可能性があることです。デフォルトでは、使用されるFILTER関数ごとに1つの問合せが実行されます。

CASEとFILTERの例

この例では、ユーザーが、四半期および選択した製品SKU別の利益を示すレポートをリクエストします。また、SKUは12のカテゴリにグループ化されています。Other Colaカテゴリには、Cola、Diet ColaおよびShared Diet ColaというLOBの製品が割り当てられています。

GUID-7198F143-54E6-4A48-9579-96624936A94D-default.jpgの説明が続きます
.jpgの説明

CASE文の論理問合せを次に示します:

SELECT

   0 s_0,

   CASE when XSA('Admin'.'Sample.BasicPM')."Product"."Product SKU" in ('Cola','Diet Cola','Shared Diet Cola') THEN 'Other Cola' ELSE XSA('Admin'.'Sample.BasicPM')."Product"."Product SKU" END s_1,

   DESCRIPTOR_IDOF(XSA('Admin'.'Sample.BasicPM')."Product"."Category") s_2,

   DESCRIPTOR_IDOF(XSA('Admin'.'Sample.BasicPM')."Product"."Product SKU") s_3,

   DESCRIPTOR_IDOF(XSA('Admin'.'Sample.BasicPM')."Year"."Quarter") s_4,

   SORTKEY(XSA('Admin'.'Sample.BasicPM')."Product"."Category") s_5,

   SORTKEY(XSA('Admin'.'Sample.BasicPM')."Product"."Product SKU") s_6,

   SORTKEY(XSA('Admin'.'Sample.BasicPM')."Year"."Quarter") s_7,

   XSA('Admin'.'Sample.BasicPM')."Product"."Category" s_8,

   XSA('Admin'.'Sample.BasicPM')."Product"."Product SKU" s_9,

   XSA('Admin'.'Sample.BasicPM')."Year"."Quarter" s_10,

   XSA('Admin'.'Sample.BasicPM')."Basic"."Profit" s_11

FROM XSA('Admin'.'Sample.BasicPM')

ORDER BY 8 ASC NULLS LAST, 11 ASC NULLS LAST, 5 ASC NULLS LAST, 2 ASC NULLS LAST, 7 ASC NULLS LAST, 10 ASC NULLS LAST, 4 ASC NULLS LAST, 6 ASC NULLS LAST, 9 ASC NULLS LAST, 3 ASC NULLS LAST

FETCH FIRST 125001 ROWS ONLY

CASE文に基づくグループ化はありません。Oracle Analyticsによって処理されるCASE文を使用した単純なMDX問合せが生成されます。

With 
  set [_Product3]  as 'Descendants([Product], [Product].Generations(3), leaves)'
  set [_Year2]  as 'Descendants([Year], [Year].Generations(2), leaves)'
select 
  { [Measures].[Profit]
  } on columns,
  NON EMPTY {crossjoin({[_Year2]},{[_Product3]})} properties GEN_NUMBER, [Product].[MEMBER_UNIQUE_NAME], [Product].[Memnor], [Year].[MEMBER_UNIQUE_NAME], [Year].[Memnor] on rows 
from [Sample.Basic]

CASE文は、BIサーバーで実行されます。これはdatabase 0:0,0に設定されたデータベース設定からわかります:

 RqList <<11777451>> [for database 0:0,0]
                            D1.c6 as c6 [for database 0:0,0],
                            D1.c4 as c4 [for database 0:0,0],
                            case  when D1.c7 in ([ 'Cola', 'Diet Cola', 'Shared Diet Cola'] ) then 'Other Cola' else D1.c7 end  as c2 [for database 0:0,0],
                            D1.c5 as c5 [for database 0:0,0],
                            D1.c3 as c3 [for database 0:0,0],
                            D1.c1 as c1 [for database 0:0,0],
                            D1.c7 as c7 [for database 0:0,0],
                            D1.c8 as c8 [for database 0:0,0]

別の方法として、利益メトリックに対してフィルタを使用し、必要なLOBメンバーのみを取得できます。このシナリオでは、対応するフィルタが適用された3つのメトリックを作成します。

FILTER文の論理問合せを次に示します:

SELECT

   0 s_0,

   DESCRIPTOR_IDOF(XSA('Admin'.'Sample.BasicPM')."Product"."Category") s_1,

   DESCRIPTOR_IDOF(XSA('Admin'.'Sample.BasicPM')."Product"."Product SKU") s_2,

   DESCRIPTOR_IDOF(XSA('Admin'.'Sample.BasicPM')."Year"."Quarter") s_3,

   SORTKEY(XSA('Admin'.'Sample.BasicPM')."Product"."Category") s_4,

   SORTKEY(XSA('Admin'.'Sample.BasicPM')."Product"."Product SKU") s_5,

   SORTKEY(XSA('Admin'.'Sample.BasicPM')."Year"."Quarter") s_6,

   XSA('Admin'.'Sample.BasicPM')."Product"."Category" s_7,

   XSA('Admin'.'Sample.BasicPM')."Product"."Product SKU" s_8,

   XSA('Admin'.'Sample.BasicPM')."Year"."Quarter" s_9,

   FILTER(XSA('Admin'.'Sample.BasicPM')."Basic"."Profit" USING XSA('Admin'.'Sample.BasicPM')."Product"."Product SKU" in ('Cola','Diet Cola','Shared Diet Cola')) s_10,

   FILTER(XSA('Admin'.'Sample.BasicPM')."Basic"."Profit" USING XSA('Admin'.'Sample.BasicPM')."Product"."Product SKU" in ('Sasprilla','Birch Beer','Dark Cream')) s_11,

   FILTER(XSA('Admin'.'Sample.BasicPM')."Basic"."Profit" USING XSA('Admin'.'Sample.BasicPM')."Product"."Product SKU" in ('xxxxx')) s_12

FROM XSA('Admin'.'Sample.BasicPM')

ORDER BY 7 ASC NULLS LAST, 10 ASC NULLS LAST, 4 ASC NULLS LAST, 6 ASC NULLS LAST, 9 ASC NULLS LAST, 3 ASC NULLS LAST, 5 ASC NULLS LAST, 8 ASC NULLS LAST, 2 ASC NULLS LAST

FETCH FIRST 125001 ROWS ONLY

このシナリオでは、フィルタごとに1つずつ、3つの問合せが生成され、パフォーマンスの問題が発生します。

問合せ1:

With

  set [_Product3]  as 'Filter([Product].Generations(3).members, ((IIF(IsValid([Product].CurrentMember.MEMBER_ALIAS), [Product].CurrentMember.MEMBER_ALIAS, [Product].CurrentMember.MEMBER_Name) = "xxxxx")))'

  set [_Year2]  as 'Descendants([Year], [Year].Generations(2), leaves)'

select

  { [Measures].[Profit]

  } on columns,

  NON EMPTY {crossjoin({[_Year2]},{[_Product3]})} properties MEMBER_NAME, GEN_NUMBER, property_expr([Product], [MEMBER_NAME], Ancestor(currentaxismember(), [Product].Generations(2)), "Category_Null_Alias_Replacement"), property_expr([Product], [Default], Ancestor(currentaxismember(), [Product].Generations(2)), "Category"), property_expr([Product], [MEMBER_UNIQUE_NAME], Ancestor(currentaxismember(), [Product].Generations(2)), "Category - Member Key"), property_expr([Product], [Memnor], Ancestor(currentaxismember(), [Product].Generations(2)), "Category - Memnor"), [Product].[MEMBER_UNIQUE_NAME], [Product].[Memnor], [Year].[MEMBER_UNIQUE_NAME], [Year].[Memnor] on rows

from [Sample.Basic]

]]

問合せ2:

With

  set [_Product3]  as 'Filter([Product].Generations(3).members, ((IIF(IsValid([Product].CurrentMember.MEMBER_ALIAS), [Product].CurrentMember.MEMBER_ALIAS, [Product].CurrentMember.MEMBER_Name) = "Birch Beer") OR (IIF(IsValid([Product].CurrentMember.MEMBER_ALIAS), [Product].CurrentMember.MEMBER_ALIAS, [Product].CurrentMember.MEMBER_Name) = "Dark Cream") OR (IIF(IsValid([Product].CurrentMember.MEMBER_ALIAS), [Product].CurrentMember.MEMBER_ALIAS, [Product].CurrentMember.MEMBER_Name) = "Sasprilla")))'

  set [_Year2]  as 'Descendants([Year], [Year].Generations(2), leaves)'

select

  { [Measures].[Profit]

  } on columns,

  NON EMPTY {crossjoin({[_Year2]},{[_Product3]})} properties MEMBER_NAME, GEN_NUMBER, property_expr([Product], [MEMBER_NAME], Ancestor(currentaxismember(), [Product].Generations(2)), "Category_Null_Alias_Replacement"), property_expr([Product], [Default], Ancestor(currentaxismember(), [Product].Generations(2)), "Category"), property_expr([Product], [MEMBER_UNIQUE_NAME], Ancestor(currentaxismember(), [Product].Generations(2)), "Category - Member Key"), property_expr([Product], [Memnor], Ancestor(currentaxismember(), [Product].Generations(2)), "Category - Memnor"), [Product].[MEMBER_UNIQUE_NAME], [Product].[Memnor], [Year].[MEMBER_UNIQUE_NAME], [Year].[Memnor] on rows

from [Sample.Basic]

]]

問合せ3:

With

  set [_Product3]  as 'Filter([Product].Generations(3).members, ((IIF(IsValid([Product].CurrentMember.MEMBER_ALIAS), [Product].CurrentMember.MEMBER_ALIAS, [Product].CurrentMember.MEMBER_Name) = "Cola") OR (IIF(IsValid([Product].CurrentMember.MEMBER_ALIAS), [Product].CurrentMember.MEMBER_ALIAS, [Product].CurrentMember.MEMBER_Name) = "Diet Cola") OR (IIF(IsValid([Product].CurrentMember.MEMBER_ALIAS), [Product].CurrentMember.MEMBER_ALIAS, [Product].CurrentMember.MEMBER_Name) = "Shared Diet Cola")))'

  set [_Year2]  as 'Descendants([Year], [Year].Generations(2), leaves)'

select

  { [Measures].[Profit]

  } on columns,

  NON EMPTY {crossjoin({[_Year2]},{[_Product3]})} properties MEMBER_NAME, GEN_NUMBER, property_expr([Product], [MEMBER_NAME], Ancestor(currentaxismember(), [Product].Generations(2)), "Category_Null_Alias_Replacement"), property_expr([Product], [Default], Ancestor(currentaxismember(), [Product].Generations(2)), "Category"), property_expr([Product], [MEMBER_UNIQUE_NAME], Ancestor(currentaxismember(), [Product].Generations(2)), "Category - Member Key"), property_expr([Product], [Memnor], Ancestor(currentaxismember(), [Product].Generations(2)), "Category - Memnor"), [Product].[MEMBER_UNIQUE_NAME], [Product].[Memnor], [Year].[MEMBER_UNIQUE_NAME], [Year].[Memnor] on rows

from [Sample.Basic]

製品フィルタ適用例

より適切なアプローチとしては、フィルタなしで1つのメジャー列を使用して、レポートに製品列を含めます。次に、必要な製品を含むフィルタを作成します。製品を別のカテゴリにグループ化する場合は、CASE文を使用します。このシナリオでは、フィルタされた行を使用して単一のMDX問合せが生成され、CASE文がOracle Analyticsによって適用されても、すべてのレコードではなくデータのサブセットが使用されます。

CASE文によってパフォーマンスの問題が引き起こされる別のシナリオを示します。

開発者がブランド名を変更するためのCASE文を適用し、ユーザーはダッシュボード・プロンプトを使用してブランドを選択できます

GUID-56356AA9-2AF6-4A67-8ADD-FC4F7F70306C-default.jpgの説明が続きます
.jpgの説明

GUID-E63719C8-9936-412B-8228-F20E8F048C46-default.jpgの説明が続きます
.jpgの説明

CASE文はMDXでサポートされていないため、Brand2に対するフィルタはMDX問合せで適用できません。すべてのブランドが選択され、最適化されません。

GUID-6BE1F274-8257-4E31-8D42-406357A07B2A-default.jpgの説明が続きます
.jpgの説明

このタイプのシナリオでは、CASE文を削除して、データベースのメンバー名を変更するか、別名を作成することをお薦めします。