Når du bruger en flerdimensional database som datakilde i Oracle Analytics, kan du opleve problemer med ydeevnen, hvilket resulterer i, at der genereres MDX-genererede (Multidimensional Expression) forespørgsler, der ikke fungerer optimalt.
Ved at modificere designet kan du forbedre de MDX-forespørgsler, som Oracle Analytics genererer. Dette kan have en enorm virkning både på din rapports ydeevne og den mængde ressourcer, der bruges i databasen. Den måde, du bruger understøttede eller ikke-understøttede funktioner i MDX på, påvirker de genererede MDX-forespørgsler og dermed ydeevnen.
Da hvert anvendelsesområde er unikt, skal dit udviklingsteam gennemgå mulighederne, analysere Oracle Analytics-forespørgselsloggene og vælge den bedste løsning til dit anvendelsesområde.
Dette emne omhandler ikke problemer med ydeevnen, der skyldes din infrastruktur, for eksempel netværk, browsere eller rapportpræsentation.
Metodologi
Oracle anbefaler, at du fuldfører følgende opgaver for at øge ydeevnen. Det er vigtigt, at du forstår strukturen i MDX-forespørgsler samt de forespørgselslogge, som Oracle Analytics genererer.
Optimering af valgtrin
Når du optimerer valgtrin, kan du forenkle MDX-forespørgslerne, reducere antallet af genererede MDX-forespørgsler og øge ydeevnen.
Den følgende figur viser et eksempel på en sammenligning af optimerede og ikke-optimerede valgtrin.
.jpg
CASE-sætninger
Funktionaliteten af CASE
-sætninger understøttes ikke i MDX-forespørgsler og skal altid anvendes i Oracle Analytics. Den logik, der forklares i dette afsnit vedrørende CASE
-sætninger, gælder for de fleste funktioner, der ikke understøttes i MDX-forespørgsler (if null
osv.).
Der er fordele og ulemper ved brugen af CASE
-sætninger. Når du inkluderer CASE
-sætninger i rapportformularer, inkluderes de ikke i MDX-forespørgslen. Dette kan forenkle MDX-forespørgslen og forbedre ydeevnen. Ulempen er dog, at du ikke kan filtrere lige så effektivt, hvilket betyder, at forespørgslen kan returnere flere records end nødvendigt.
Der gælder følgende begrænsninger for brugen af funktionalitet af CASE
-sætninger:
CASE
-sætningen ikke kombinerer flere medlemmer, skal den basiskolonne, der bruges i sætningen, inkluderes i forespørgslen og visningerne som en skjult separat kolonne.CASE
-sætningen kombinerer flere medlemmer, kan basiskolonnen ikke inkluderes i visningen, uden at det påvirker aggregeringsniveauet. Hvis dette er tilfældet:
SUM
, MAX
, MIN
). Dette virker kun, hvis den interne aggregeringsregel anvendes til at kombinere medlemmer og giver korrekte resultater.Funktionen FILTER
I modsætning til funktionaliteten af CASE
-sætningen kan funktionen FILTER
sendes til databasen til udførelse.
Den største fordel ved at bruge funktionen FILTER
i rapportformler er, at valget anvendes i MDX-forespørgslen, og at den mængde data, der beregnes og hentes fra databasen, reduceres.
Den største ulempe ved at bruge funktionen FILTER
er, at det kan øge antallet af udførte MDX-forespørgsler. Der udføres som standard én forespørgsel for hver brugt FILTER
-funktion.
Eksempel på CASE vs. FILTER
I dette eksempel anmoder en bruger om en rapport, der viser profit efter kvartal og valgt produkt-SKU. Derudover er SKU'erne grupperet i 12 kategorier. Kategorien Other Cola har følgende LOB-produkter tildelt: Cola, Diet Cola og Shared Diet Cola.
.jpg
Her er den logiske forespørgsel med CASE
-sætningen:
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
Der er ingen gruppering baseret på CASE
-sætningen. Der genereres en simpel MDX-forespørgsel, og CASE
-sætningen behandles af 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]
CASE
-sætningen udføres på BI Server, og dette ses ved, at databasen angiver sæt til 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]
Alternativt kan du bruge et filter mod profitmetrikken for kun at hente de påkrævede LOB-medlemmer. I dette scenarie opretter du tre metrikker med de tilsvarende filtre anvendt.
Her er den logiske forespørgsel med FILTER
-sætningen:
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
I dette scenarie genereres der tre forespørgsler, en for hvert filter, og du oplever problemer med ydeevnen.
Forespørgsel 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] ]]
Forespørgsel 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] ]]
Forespørgsel 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]
Eksempel på anvendelse af produktfilter
En bedre tilgang er at inkludere produktkolonnen i rapporten med en enkelt målingskolonne uden et filter. Opret derefter et filter, der inkluderer de påkrævede produkter. Brug en CASE
-sætning, hvis du vil gruppere produkterne i forskellige kategorier. I dette scenarie genereres der en enkelt MDX-forespørgsel med de filtrerede rækker, og selvom CASE
-sætningen anvendes af Oracle Analytics, bruger den dataundersættet og ikke alle records.
Her er et andet scenarie, hvor CASE
-sætninger forårsager problemer med ydeevnen.
En udvikler anvender en CASE
-sætning for at omdøbe varemærker, og en instrumentbrætprompt gør det muligt for brugere at vælge varemærket.
.jpg
.jpg
Da CASE
-sætningen ikke understøttes i MDX'en, kan filteret på Brand2
ikke anvendes i MDX-forespørgslen. Alle varemærker vælges, og dette optimeres ikke.
.jpg
I denne type scenarie anbefaler Oracle, at du fjerner CASE
-sætningen og omdøber medlemmer i databasen eller opretter aliasser.