När du använder en flerdimensionell databas som datakälla i Oracle Analytics kan du få prestandaproblem, vilket gör att suboptimala flerdimensionella uttrycksfrågor genereras.
Genom att ändra designen kan du se till att Oracle Analytics genererar bättre flerdimensionella uttrycksfrågor. Det här kan få stor effekt, inte bara när det gäller dina rapporters prestanda utan även på mängden resurser som databasen förbrukar. Hur du använder funktioner som stöds eller inte stöds har stor påverkan på de flerdimensionella uttrycksfrågor som genereras och deras prestanda.
Eftersom varje användningsfall är unikt bör ditt utvecklingsteam granska alternativen, analysera frågeloggarna i Oracle Analytics och välja den lösning som passar bäst för användningsfallet.
Hjälpavsnittet omfattar inte prestandaproblem som beror på infrastrukturen, till exempel nätverk, webbläsare eller presentationen av rapporten.
Metodik
Oracle rekommenderar att du utför följande uppgifter om du vill få bättre prestanda. Det är viktigt att du förstår den flerdimensionella uttrycksfrågans struktur och frågeloggarna som Oracle Analytics genererar.
Optimera urvalsstegen
När du optimerar urvalsstegen kan du förenkla de flerdimensionella uttrycksfrågorna, minska antalet flerdimensionella uttrycksfrågor som genereras och förbättra deras prestanda.
Följande figur visar ett exempel på en jämförelse av optimerade urvalssteg och urvalssteg som inte optimerats.
.jpg
CASE-satser
Multifunktionella uttrycksfrågor saknar stöd för CASE
-satser, så de måste alltid tillämpas i Oracle Analytics. Logiken i den här sektionen angående CASE
-satser gäller för de flesta funktioner som flerdimensionella uttrycksfrågor saknar stöd för (if null
och liknande).
Det finns fördelar och nackdelar med att använda CASE
-satser. När du tar med CASE
-satser i rapportformler inkluderas de inte i den flerdimensionella uttrycksfrågan. Det kan förenkla den flerdimensionella uttrycksfrågan och ge högre prestanda. Nackdelen är emellertid att du inte kan filtrera så effektivt, vilket gör att frågan kan returnera fler poster än nödvändigt.
Följande är begränsningar för hur du använder CASE
-satser:
CASE
-satsen inte kombinerar flera medlemmar måste baskolumnen i satsen ingå i frågan och vyn som en dold, separat kolumn.CASE
-satsen kombinerar flera medlemmar påverkas aggregeringsnivån om baskolumnen ingå i vyn. Då gör du så här:
SUM
, MAX
eller MIN
). Det här fungerar bara om den interna aggregeringsregeln används till att kombinera medlemmar och ger korrekta resultat.FILTER-funktion
Till skillnad från CASE
-satser så kan funktionen FILTER
skickas till databasen för körning.
Den största fördelen med att använda funktionen FILTER
i rapportformler är att urvalet tillämpas i den flerdimensionella uttrycksfrågan så att mindre data beräknas och hämtas från databasen.
Den största nackdelen med att använda funktionen FILTER
är att fler flerdimensionella uttrycksfrågor kan köras. Som standard körs en fråga för varje FILTER
-funktion som används.
Exempel på CASE kontra FILTER
I det här exemplet begär en användare en rapport som visar vinsten per kvartal och vald produktlagerenhet. Lagerenheterna är dessutom indelade i tolv kategorier. Kategorin Other Cola har följande affärsområdesprodukter tilldelade: Cola, Diet Cola och Shared Diet Cola.
.jpg
Här är den logiska frågan med CASE
-satsen:
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 görs ingen gruppering baserat på CASE
-satsen. En enkel flerdimensionell uttrycksfråga genereras, där CASE
-satsen bearbetas i 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
-satsen körs på BI-servern, vilket du ser genom att databasinställningen är 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 också använda ett filter mot vinstmåttet för att hämta de affärsområdesmedlemmar som behövs. I det här scenariot skapar du tre mått med motsvarande filter tillämpade.
Här är den logiska frågan med FILTER
-satsen:
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 det här scenariot genereras tre frågor, ett för varje filter, och du får prestandaproblem.
Fråga 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] ]]
Fråga 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] ]]
Fråga 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]
Exempel med tillämpat produktfilter
Det är bättre att ta med produktkolumnen i rapporten med en enda måttkolumn utan filter. Sedan skapar du ett filter för de produkter du vill ha. Använd en CASE
-sats om du vill gruppera produkterna i andra kategorier. I det här scenariot genereras en enda flerdimensionell uttrycksfråga med de filtrerade raderna, och trots att CASE
-satsen tillämpas i Oracle Analytics används en delmängd data snarare än samtliga poster.
Här är ett annat scenario där CASE
-satser ger upphov till prestandaproblem.
En utvecklare använder en CASE
-sats till att ändra namn på varumärken, och användaren får välja varumärke via en fråga på infopanelen.
.jpg
.jpg
Eftersom det flerdimensionella uttrycket saknar stöd för CASE
-satsen kan inte filtret Brand2
tillämpas i den flerdimensionella uttrycksfrågan. Alla varumärken väljs, vilket inte är optimalt.
.jpg
I den här typen av scenario rekommenderar Oracle att du tar bort CASE
-satsen och byter namn på medlemmarna i databasen eller skapar alias.