Régler la performance des interrogations de la base de données multidimensionnelle

Lorsque vous utilisez une base de données multidimensionnelle comme source de données dans Oracle Analytics, vous pouvez rencontrer des problèmes de performance qui se traduisent par la génération d'interrogations d'expression multidimensionnelle (MDX) sous-optimales.

En modifiant la conception, vous pouvez améliorer les interrogations MDX générées par Oracle Analytics. Cela peut avoir une incidence considérable, non seulement sur la performance de votre rapport, mais aussi sur le volume des ressources utilisées dans la base de données. La manière dont vous utilisez les fonctions prises en charge ou non prises en charge a une incidence considérable sur les interrogations MDX générées et sur la performance.

Étant donné que chaque cas d'utilisation est unique, il appartient à votre équipe de développement de passer en revue les options, d'analyser les journaux d'interrogations d'Oracle Analytics et de sélectionner la meilleure solution pour votre cas d'utilisation.

Cette rubrique n'aborde pas les problèmes de performance causés par votre infrastructure, tels que réseaux, navigateurs ou présentation de rapport.

Méthodologie

Pour améliorer la performance, Oracle vous recommande d'effectuer les tâches suivantes. Il est important de comprendre la structure des interrogations MDX ainsi que les journaux d'interrogations générés par Oracle Analytics.

  • Simplifier les interrogations MDX générées.
  • Réduire le nombre d'interrogations MDX générées.
  • Veiller à ce que des filtres et des sélections optimaux soient appliqués dans l'interrogation MDX.
  • Régler la performance avec l'administrateur de base de données pour la base de données multidimensionnelle et vérifier pourquoi la base de données source n'est toujours pas performante.
  • Modifier l'analyse en fonction de la rétroaction de l'administrateur de base de données.

Optimisation des étapes de sélection

L'optimisation des étapes de sélection permet de simplifier les interrogations MDX, de réduire le nombre d'interrogations MDX générées et d'améliorer la performance.

L'illustration suivante présente un exemple de comparaison des étapes de sélection optimisées et des étapes de sélection non optimisées.

Description de GUID-43E6F348-B14C-40DC-8C21-DA34DAE44344-default.jpg ci-après
.jpg

Énoncés CASE

La fonctionnalité d'énoncé CASE n'est pas prise en charge dans les interrogations MDX et doit toujours être appliquée dans Oracle Analytics. La logique expliquée dans cette section concernant les énoncés CASE est valable pour la plupart des fonctions qui ne sont pas prises en charge dans les interrogations MDX (if null, etc.).

L'utilisation des énoncés CASE présente des avantages et des inconvénients. Lorsque vous ajoutez des énoncés CASE dans des formules de rapport, ils ne figurent pas dans l'interrogation MDX. Cela peut simplifier l'interrogation MDX et améliorer la performance. Toutefois, la contrepartie est que le filtrage n'étant pas aussi efficace, l'interrogation peut retourner plus d'enregistrements que nécessaire.

Les restrictions liées à l'utilisation de la fonctionnalité d'énoncé CASE sont les suivantes :

  • Si l'énoncé CASE ne combine pas plusieurs membres, la colonne de base utilisée dans l'énoncé doit être incluse dans l'interrogation et les vues en tant que colonne distincte masquée.
  • Si l'énoncé CASE combine plusieurs membres, la colonne de base ne peut pas être incluse dans la vue sans avoir une incidence sur le niveau d'agrégation. Si le cas se présente :
    • Si la règle d'agrégation de la mesure n'est pas Agrégation externe, la colonne de base ne doit pas figurer dans l'interrogation.
    • Si la règle d'agrégation de la mesure est Agrégation externe, la colonne de base doit être incluse dans l'interrogation et exclue de la vue. Vous devez passer de la règle d'agrégation de mesure par défaut à une règle d'agrégation interne simple (SUM, MAX, MIN). Cela ne fonctionne que si la règle d'agrégation interne est utilisée pour combiner les membres et fournit des résultats corrects.

Fonction FILTER

Contrairement à l'énoncé CASE, la fonction FILTER peut être envoyée à la base de données pour exécution.

Le principal avantage de l'utilisation de la fonction FILTER dans les formules de rapport est que la sélection est appliquée dans l'interrogation MDX et que le volume de données calculées et extraites de la base de données est réduit.

Le principal inconvénient de l'utilisation de la fonction FILTER est qu'elle peut augmenter le nombre d'interrogations MDX exécutées. Par défaut, une interrogation est exécutée pour chaque fonction FILTER utilisée.

Exemple illustrant l'utilisation de CASE par rapport à FILTER

Dans cet exemple, un utilisateur demande un rapport qui montre les profits par trimestre et par UGS de produit sélectionné. Les UGS sont regroupées en 12 catégories. Les produits suivants sont affectés à la catégorie Other Cola : Cola, Diet Cola et Shared Diet Cola.

Description de GUID-7198F143-54E6-4A48-9579-96624936A94D-default.jpg ci-après
.jpg

Voici l'interrogation logique de l'énoncé 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

Il n'y a pas de regroupement basé sur l'énoncé CASE. Une seule interrogation MDX est générée, avec l'énoncé CASE traité par Oracle Analytics :

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]

L'énoncé CASE est exécuté sur le serveur BI, ce qui se traduit par le réglage database 0:0,0 pour la base de données :

 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]

Vous pouvez également utiliser un filtre sur la mesure de profits pour n'extraire que les membres LOB requis. Dans ce scénario, vous créez trois mesures avec les filtres correspondants appliqués.

Voici l'interrogation logique de l'énoncé 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

Dans ce scénario, trois interrogations sont générées, une pour chaque filtre, et vous rencontrez des problèmes de performance.

Interrogation 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]

]]

Interrogation 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]

]]

Interrogation 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]

Exemple avec filtre de produit appliqué

Une meilleure approche consiste à inclure la colonne Product (Produit) dans le rapport avec une seule colonne Mesure sans filtre. Puis à créer un filtre incluant les produits requis. Si vous voulez regrouper les produits en différentes catégories, utilisez un énoncé CASE. Dans ce scénario, une seule interrogation MDX est générée avec les rangées filtrées. Même si l'énoncé CASE est appliqué par Oracle Analytics, elle utilise le sous-jeu de données et non l'ensemble des enregistrements.

Voici un autre scénario dans lequel les énoncés CASE posent des problèmes de performance.

Un développeur applique un énoncé CASE pour renommer les marques, et une invite du tableau de bord permet aux utilisateurs de sélectionner la marque .

Description de GUID-56356AA9-2AF6-4A67-8ADD-FC4F7F70306C-default.jpg ci-après
.jpg

Description de GUID-E63719C8-9936-412B-8228-F20E8F048C46-default.jpg ci-après
.jpg

L'énoncé CASE n'étant pas pris en charge dans l'interrogation MDX, le filtre sur Brand2 ne peut pas être appliqué dans l'interrogation MDX. Toutes les marques sont sélectionnées, ce qui n'est pas optimisé.

Description de GUID-6BE1F274-8257-4E31-8D42-406357A07B2A-default.jpg ci-après
.jpg

Dans ce type de scénario, Oracle recommande de supprimer l'énoncé CASE et de renommer les membres dans la base de données ou de créer des alias.