Ako upotrebljavate višedimenzionalnu bazu podataka kao izvor podataka, u izvedbi servisa Oracle Analytics mogli biste doživjeti probleme koji će rezultirati generiranjem neoptimalnih upita višedimenzionalnih izraza (MDX).
Izmjenom dizajna možete unaprijediti MDX upite koje Oracle Analytics generira. To može imati značajan utjecaj, ne samo na izvedbu izvješća, već i na količinu resursa koji se upotrebljavaju u bazi podataka. Način na koji upotrebljavate podržane ili nepodržane funkcije u MDX-u značajno utječe na generirane MDX upite, a time i na izvedbu.
Budući da je svaki slučaj upotrebe jedinstven, vaš razvojni tim treba pregledati opcije, analizirati zapisnike upita za Oracle Analytics i odabrati najbolje rješenje za vaš slučaj upotrebe.
Ova tema ne otklanja probleme u izvedbi uzrokovane infrastrukturom, npr. mrežama, preglednicima ili prezentacijom izvješća.
Metodologija
Za poboljšanje izvedbe Oracle preporučuje izvršavanje sljedećih zadataka. Važno je da razumijete strukturu MDX upita, kao i zapisnike upita koje Oracle Analytics generira.
Optimizacija koraka odabira
Nakon što optimizirate korake odabira, moći ćete pojednostaviti MDX upite, smanjiti broj generiranih MDX upita i povećati razinu izvedbe.
Sljedeća slika pokazuje primjer usporedbe optimiziranih i neoptimiziranih koraka odabira.
.jpg
CASE naredbe
Funkcionalnost CASE
naredbe nije podržana u MDX upitima i mora se uvijek primijeniti u servisu Oracle Analytics. Logika objašnjena u ovom odjeljku s obzirom na CASE
naredbe valjana je za većinu funkcija koje nisu podržane u MDX upitima (vrijednost null
itd.).
Postoje prednosti i nedostaci upotrebe CASE
naredbi. Ako želite uključiti naredbe CASE
u formule izvješća, neće biti uključene u MDX upit. To može pojednostaviti MDX upit i unaprijediti radne značajke. Međutim, time se onemogućava učinkovito filtriranje, što znači kako bi upit mogao vratiti više zapisa no što je potrebno.
Donosimo ograničenja kod upotrebe funkcije CASE
naredbe:
CASE
naredba ne kombinira više članova, osnovni stupac koji se upotrebljava u naredbi treba se uključiti u upit i prikaze kao skriven zasebni stupac.CASE
naredba kombinira više članova, osnovni stupac ne može biti uključen u prikaz bez da to utječe na razinu sabiranja. Ako je to slučaj:
SUM
, MAX
, MIN
). To će funkcionirati samo ako interno pravilo sabiranja služi za kombiniranje članova i prikazuje točne rezultate.Funkcija FILTER
Za razliku od naredbe CASE
, funkcija FILTER
može se isporučiti u bazu podataka radi izvođenja.
Glavna prednost upotrebe funkcije FILTER
u formulama izvješća odnosi se na primjenu odabira na upit MDX uz smanjenje količine izračunatih i dohvaćenih podataka iz baze podataka.
Glavni nedostatak upotrebe funkcije FILTER
u potencijalnom je povećanju broja izvršenih MDX upita. Po zadanim postavkama, izvodi se jedan upit za svaku upotrijebljenu funkciju FILTER
.
Primjer za CASE u odnosu na FILTER
U ovom primjeru, korisnik traži izvješće koje pokazuje dobit po tromjesečju i SJ odabranog proizvoda. Osim toga, skladišne jedinice grupiraju se u 12 kategorija. Kategoriji Druga Cola dodijeljeni su sljedeći proizvodi: Cola, Dijetalna Cola i Zajednička dijetalna Cola.
.jpg
Ovo je logički upit naredbe 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
Nema grupiranja temeljem naredbe CASE
. Generirat će se jednostavan MDX upit, s naredbom CASE
koju obrađuje 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]
Naredba CASE
izvodi se na BI poslužitelju, što je prikazano kroz postavljanje postavke baze podataka na 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]
S druge strane, možete upotrijebiti filtriranje metrike dobiti kako biste dohvatili samo željene članove skupa. U tom ćete scenariju stvoriti tri metričke vrijednosti s primijenjenim odgovarajućim filtrima.
Ovo je logički upit naredbe 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
U tom će se scenariju generirati tri upita, po jedan za svaki filtar, a vi ćete osjetiti probleme u izvedbi.
1. upit:
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] ]]
2. upit:
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] ]]
3. upit:
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]
Primjer s primijenjenim filtrom proizvoda
Bolji je pristup uključiti stupac proizvoda u izvješće s jednim stupcem mjere, bez filtra. Zatim stvorite filtar koji uključuje tražene proizvode. Ako proizvode želite grupirati u različite kategorije, upotrijebite naredbu CASE
. U tom će se scenariju generirati jedan MDX upit s filtriranim stupcima, a unatoč primjeni naredbe CASE
, Oracle Analytics će upotrijebiti podskup podataka, ne sve zapise.
Donosimo i drugi scenarij u kojemu naredbe CASE
uzrokuju probleme u izvedbi.
Razvojni programer primijenit će naredbu CASE
radi promjene naziva robnih marki, a odzivnik dashboarda omogućit će korisnicima odabir robne marke.
.jpg
.jpg
Budući da MDX ne podržava naredbu CASE
, u MDX upitu neće se moći primijeniti filtar za Robnu marku 2
. Odabrat će se sve robne marke odabrane, a to nije optimalno.
.jpg
U takvom scenariju, Oracle preporučuje uklanjanje naredbe CASE
i preimenovanje članova u bazi podataka ili stvaranje drugih naziva.