Keď ako dátový zdroj v službe Oracle Analytics použijete multidimenzionálnu databázu, môžete zaznamenať problémy s výkonom, ktoré spôsobia nižšiu kvalitu generovaných dopytov MDX (multidimensional expression).
Úpravou návrhu môžete zlepšiť dopyty MDX, ktoré služba Oracle Analytics generuje. Môže to mať obrovský vplyv nielen na výkon zostáv, ale aj na množstvo prostriedkov využívaných v databáze. Spôsob, akým využívate podporované alebo nepodporované funkcie, výrazne vplýva na generované dopyty MDX, a teda na výkon.
Keďže každý prípad použitia je jedinečný, vývojársky tím by mal skontrolovať voľby, analyzovať protokoly dopytov služby Oracle Analytics a vybrať to najlepšie riešenie pre váš prípad použitia.
Táto téma sa nevenuje problémom s výkonom spôsobeným vašou infraštruktúrou, ako sú siete, prehľadávače alebo prezentácia zostavy.
Metodológia
Spoločnosť Oracle odporúča vykonať nasledujúce úlohy na zvýšenie výkonu. Je dôležité, aby ste chápali štruktúru dopytov MDX, ako aj protokoly dopytov, ktoré Oracle Analytics generuje.
Optimalizácia krokov výberu
Keď optimalizujete kroky výberu, môžete zjednodušiť dopyty MDX, znížiť počet generovaných dopytov MDX a zvýšiť výkon.
Na nasledujúcom obrázku je znázornený príklad porovnania optimalizovaných a neoptimalizovaných krokov výberu.
.jpg
Príkazy CASE
Funkcionalita príkazov CASE
nie je v dopytoch MDX podporovaná a musí byť vždy použitá v službe Oracle Analytics. Logika vysvetlená v tejto sekcii v súvislosti s príkazmi CASE
platí pre väčšinu funkcií, ktoré nie sú v dopytoch MDX podporované (if null
atď.).
Používanie príkazov CASE
má svoje výhody a nevýhody. Keď do vzorcov zostavy pridáte príkazy CASE
, nebudú zahrnuté do dopytu MDX. Môže sa tým zjednodušiť dopyt MDX a zvýšiť výkon. Kompromisom je však to, že dáta nemožno filtrovať tak efektívne, čo znamená, že dopyt môže vrátiť viac záznamov, ako je potrebné.
Používanie funkcionality príkazov CASE
má nasledujúce obmedzenia:
CASE
nekombinuje viaceré členy, základný stĺpec použitý v príkaze by mal byť zahrnutý do dopytu a do zobrazení ako skrytý samostatný stĺpec.CASE
kombinuje viaceré členy, základný stĺpec nemožno zahrnúť do zobrazenia bez toho, aby to nemalo vplyv na úroveň agregácie. Ak je to tak:
SUM
, MAX
, MIN
). Funguje to len v prípade, že pravidlo internej agregácie sa používa na kombinovanie členov a poskytuje správne výsledky.Funkcia FILTER
Na rozdiel od funkcionality príkazov CASE
je funkciu FILTER
možné odoslať do databázy na spustenie.
Hlavnou výhodou použitia funkcie FILTER
vo vzorcoch zostáv je, že výber sa použije v dopyte MDX a zníži sa objem dát vypočítaných a vyvolaných z databázy.
Hlavnou nevýhodou funkcie FILTER
je, že môže zvýšiť počet vykonaných dopytov MDX. Predvolene sa vykoná jeden dopyt pre každú použitú funkciu FILTER
.
Príklad porovnávajúci príkaz CASE a príkaz FILTER
V tomto príklade používateľ požiada o zostavu, ktorá zobrazí zisk podľa štvrťroka a vybranej jednotky SKU produktu. Okrem toho sú jednotky SKU zoskupené do 12 kategórií. Kategória Other Cola má priradené nasledujúce produkty: Cola, Diet Cola a Shared Diet Cola.
.jpg
Toto je logický dopyt príkazu 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
Na základe príkazu CASE
sa nevykoná žiadne zoskupenie. Vygeneruje sa jednoduchý dopyt MDX s príkazom CASE
, ktorý je spracovaný v službe 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]
Príkaz CASE
je spustený na serveri BI, čo vidieť podľa hodnoty nastavenia databázy 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]
Ako alternatívu môžete použiť filter na metriku zisku a vyvolať len požadované členy predmetu obchodnej činnosti. V tomto scenári vytvoríte tri metriky so zodpovedajúcimi použitými filtrami.
Toto je logický dopyt príkazu 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
V tomto scenári sa vygenerujú tri dopyty, jeden pre každý filter, a zaznamenáte problémy s výkonom.
Dopyt 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] ]]
Dopyt 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] ]]
Dopyt 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]
Príklad použitia filtra produktov
Lepším riešením je zahrnúť stĺpec produktov do zostavy s jedným stĺpcom miery bez filtra. Potom vytvoríte filter, ktorý zahŕňa požadované produkty. Ak chcete zoskupiť produkty do rôznych kategórií, použite príkaz CASE
. V tomto scenári sa vygeneruje jeden dopyt MDX s vyfiltrovanými riadkami, a aj keď Oracle Analytics použije príkaz CASE
, použije len podmnožinu dát, nie všetky záznamy.
Tu je ďalší scenár, v ktorom príkazy CASE
spôsobujú problémy s výkonom.
Vývojár použije príkaz CASE
na premenovanie obchodných značiek a výzva panela umožní používateľom vybrať obchodnú značku.
.jpg
.jpg
Keďže príkaz CASE
nie je v dopyte MDX podporovaný, filter Brand2
nemožno použiť v dopyte MDX. Vybrané sú všetky značky, čo nie je optimálne.
.jpg
V tomto type scenára spoločnosť Oracle odporúča odobrať príkaz CASE
a premenovať členy v databáze alebo vytvoriť aliasy.