Når du bruker en flerdimensjonal database som datakilde i Oracle Analytics, kan du oppleve problemer med ytelsen som fører til at det genereres spørringer med flerdimensjonale uttrykk (MDX) som ikke er optimale.
Hvis du endrer utformingen, kan du forbedre MDX-spørringene som genereres i Oracle Analytics. Dette kan ha stor innvirkning både på rapportytelsen og ressursvolumet som brukes i databasen. Hvordan du bruker funksjoner som støttes eller ikke støttes, har stor innvirkning på de genererte MDX-spørringene, og dermed også på ytelsen.
Alle brukstilfeller er unike. Utviklingsteamet må derfor vurdere mulighetene, analysere spørringsloggene i Oracle Analytics og velge den beste løsningen for det aktuelle brukstilfellet.
Dette emnet dekker ikke svekket ytelse som skyldes problemer med infrastrukturen, for eksempel nettverk, nettlesere eller rapportpresentasjoner.
Metodikk
Oracle anbefaler at du utfører oppgavene nedenfor for å øke ytelsen. Det er viktig at du forstår MDX-spørringsstrukturen og spørringsloggene som genereres i Oracle Analytics.
Optimalisering av utvalgstrinn
Når du optimaliserer utvalgstrinn, kan du forenkle MDX-spørringene, redusere antallet genererte MDX-spørringer og øke ytelsen.
Figuren nedenforviser et eksempel på en sammenligning av optimaliserte og ikke-optimaliserte valgtrinn.
.jpg
CASE-setninger
Funksjoner med CASE
-setninger støttes ikke i MDX-spørringer og må alltid brukes i Oracle Analytics. Logikken som er forklart i dette avsnittet for CASE
-setninger, gjelder for de fleste funksjoner som ikke støttes i MDX-spørringer (if null
og så videre).
Det finnes både fordeler og ulemper med å bruke CASE
-setninger. Når du inkluderer CASE
-setninger i rapportformler, inkluderes de ikke i MDX-spørringen. Dette kan forenkle MDX-spørringen og gi bedre ytelse. Ulempen er imidlertid at du ikke kan filtrere like effektivt, slik at spørringen kanskje returnerer flere poster enn nødvendig.
Dette er begrensningene for bruk av funksjoner med CASE
-setninger:
CASE
-setningen ikke kombinerer flere medlemmer, må basiskolonnen som brukes i setningen, være inkludert i spørringen og visningene som en skjult separat kolonne.CASE
-setningen kombinerer flere medlemmer, kan ikke basiskolonnen være inkludert i visningene uten at det har innvirkning på aggregeringsnivået. Hvis dette er tilfellet:
SUM
, MAX
, MIN
). Dette fungerer bare hvis den interne aggregeringsregelen brukes til å kombinere medlemmer og gir riktige resultater.Funksjonen FILTER
I motsetning til funksjoner med CASE
-setninger kan funksjonen FILTER
sendes til databasen for utførelse.
Den største fordelen med å bruke funksjonen FILTER
i rapportformler er at utvalget brukes i MDX-spørringen, og datavolumet som beregnes og hentes fra databasen, reduseres.
Den største ulempen med å bruke funksjonen FILTER
er at det kan øke antallet MDX-spørringer som skal utføres. Det utføres som standard én spørring for hver FILTER
-funksjon som brukes.
Eksempel på CASE kontra FILTER
I dette eksemplet ber brukeren om en rapport som viser lønnsomheten etter kvartal og valgt lagerenhet for produkt. I tillegg grupperes lagerenhetene i tolv kategorier. Kategorien Other Cola har følgende tilordnede LOB-produkter: Cola, Diet Cola og Shared Diet Cola.
.jpg
Her er den logiske spørringen med CASE
-setning:
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
Det finnes ingen gruppering basert på CASE
-setningen. Det genereres en enkel MDX-spørring med CASE
-setningen som behandles av 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
-setningen utføres på BI-tjeneren, og dette skjer fordi databaseinnstillingen er satt 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]
Du kan også bruke et filter mot lønnsomhetsmålingen for å hente bare de nødvendige LOB-medlemmene. I dette scenarioet oppretter du tre målinger med bruk av de tilsvarende filtrene.
Her er den logiske spørringen med FILTER
-setning:
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 scenarioet genereres det tre spørringer, én for hvert filter, og du opplever problemer med ytelsen.
Spørring 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] ]]
Spørring 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] ]]
Spørring 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å bruk av produktfilter
En bedre tilnærmingsmåte er å inkludere produktkolonnen i rapporten med én målingskolonne uten filter. Deretter oppretter du et filter som inkluderer de nødvendige produktene. Hvis du vil gruppere produktene i andre kategorier, kan du bruke en CASE
-setning. I dette scenarioet genereres det én MDX-spørring med de filtrerte radene, og selv om CASE
-setningen benyttes i Oracle Analytics, brukes delsettet med data i stedet for alle postene.
Her er et annet scenario der CASE
-setninger fører til problemer med ytelsen.
En utvikler bruker en CASE
-setning til å gi nytt navn til varemerker, og brukerne kan benytte en ledetekst for instrumentpanel til å velge varemerket.
.jpg
.jpg
Ettersom CASE
-setningen ikke støttes i MDX, kan ikke filtreringen etter Brand2
brukes i MDX-spørringen. Alle varemerker er valgt, og dette optimaliseres ikke.
.jpg
I denne typen scenario anbefaler Oracle at du fjerner CASE
-setningen og gir nytt navn til medlemmer i databasen eller oppretter aliaser.