כאשר Oracle Analytics עושה שימוש במסד נתונים רב-ממדי כמקור נתונים, ישנם שיקולי עיצוב נוספים שעשויה להיות להם השפעה גדולה על הביצועים.
חשוב להבין שפתרונות העיצוב לשיפור ביצועים משתנים על פי תרחיש השימוש. נושא זה לא יספק לך את שיטות העבודה המומלצות או פתרון אחד שמתאים לכולם ויש ליישם תמיד. במקום זאת, אנו מציעים שיטות כוונון וטכניקות שיעזרו לך לשפר את הביצועים של הניתוחים שלך והקוד שנוצר.
זוהי אחריותו של צוות הפיתוח לבחון אפשרויות אלו, לנתח את יומני השאילתות של Oracle Analytics, ולבחור את הפתרון הטוב ביותר עבור תרחיש השימוש שלך.
נושא זה לא מתייחס לבעיות ביצועים שנגרמו בגלל התשתית שלך, כגון דפדפני הרשת או מצגת הדוח.
מתודולוגיה
אנו ממליצים להשלים את המשימות הבאות כדי להגביר את הביצועים. כדרישה מקדימה למשימות אלו, חשוב להבין את מבנה השאילתא של ביטוי רב-ממדי (MDX) וגם להבין את יומני השאילתות ש-Oracle Analytics מפיק. אלו המשימות העיקריות:
אופטימיזציה של שלבי הבחירה
כאשר תבצע אופטימיזציה של שלבי בחירה תוכל לפשט את שאילתות ה-MDX, להפחית את מספר שאילתות ה-MDX המופקות, ולהגביר את הביצועים.
הנה דוגמה:
.jpg
משפטי CASE
הפונקציונליות של משפט CASE
אינה נתמכת ב-MDX ויש תמיד להחיל אותה ב-Oracle Analytics. הלוגיקה המוסברת להלן לגבי משפטי CASE
תקפה לרוב הפונקציות שאינן נתמכות ב-MDX (אם null
, וכן הלאה).
ישנם יתרונות וחסרונות כשמשתמשים במשפטי CASE
. כאשר אתה כולל משפטי CASE
בנוסחאות דוח, הם לא נכללות ב-MDX. זה יכול לפשט את שאילתת ה-MDX ולשפר את הביצועים. עם זאת, הפשרה היא שאינך יכול לסנן ביעילות רבה, מה שאומר שהשאילתא עשויה להחזיר יותר רשומות מהנדרש.
כפי שתוכל לראות, כל תרחיש שימוש הוא ייחודי. המטרה העיקרית היא לפשט את שאילתות ה-MDX ובאותה עת להחיל מסננים ובחירות אופטימליים.
ישנן הגבלות ל שימוש בפונקציונליות של משפט CASE
:
CASE
לא משלב מספר איברים, עמודת הבסיס המשמשת במשפט חייבת להיות כלולה בשאילתא ובתצוגות כעמודה נפרדת נסתרת.CASE
משלב מספר איברים, אי אפשר לכלול את עמודת הבסיס בתצוגה מבלי להשפיע על רמת הסכימה. במקרה זה:
SUM
, MAX
, MIN
). זה עובד רק אם כלל הסכימה הפנימי משמש לשילוב איברים ונותן תוצאות נכונות.פונקציית FILTER
שלא כמו משפט הCASE
, ניתן לשלוח את פונקציית הFILTER
למסד הנתונים לצורך ביצוע.
FILTER
בנוסאות דוח הוא שהבחירה מיושמת בשאילתת ה-MDX ונפח הנתונים המחושבים ומאוחזרים ממסד הנתונים מצטמצם.FILTER
הוא שהיא עשויה להגדיל את מספר שאילתות MDX שיבוצעו. לפי ברירת המחדל, מתבצעת שאילתא אחת לכל פונקציית FILTER
שבה נעשה שימוש.זכור שכל תרחיש שימוש הוא ייחודי. המטרה היא לפשט שאילתות MDX ובאותו הזמן להחיל מסננים ובחירות אופטימליים.
תרחיש CASE
לעומת FILTER
הבה נמשיך להתבונן באותו התרחיש עם התוצאות של שימוש במשפט הCASE
עונת פונקציונליות FILTER
.
המשתמש מבקש דוח שמראה רווח לפי רבעון ויחידת שמירת מלאי של מוצר נבחר. בנוסף, יחידות שמירת המלאי מקובצות יחד בשתיים-עשרה קטגוריות. לקטגוריה "קולה אחרת" הוקצו המוצרים הבאים של תחום פעילות עסקית: קולה, קולה דיאט, קולה דיאט משותפת.
.jpg
הנה השאילתא הלוגית של משפט 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
אין קיבוץ המבוסס על משפט הCASE
, הופק MDX פשוט, כאשר משפט הCASE
בר עיבוד ב-Oracle Analytics. הנה ה-MDX שהופק:
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
מתבצע ב-BI Server, ואת זה ניתן לראות לפי הגדרת מסד הנתונים שנקבעה על “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]
תרחיש משפט מסנן
לחלופין, תוכל להשתמש במסנן כנגד מדד הרווח כדי לאחזר את איברי תחום הפעילות העסקית בלבד. בתרחיש זה, יוצרים 3 מדדים כשמחילים את המסננים המתאימים.
הנה השאילתא הלוגית של משפט 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
בתרחיש זה מופקות שלוש שאילתות, אחת לכל מסנן, ואתה חווה בעיות בביצועים:
שאילתא 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] ]]
שאילתא 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] ]]
שאילתא 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]
תרחיש 'הוחל מסנן מוצרים'
גישה טובה יותר היא לכלול את עמודת המוצר בדוח עם עמודת מדד יחידה ללא מסנן. לאחר מכן צור מסנן שכולל את המוצרים הדרושים. אם תרצה לקבץ את המוצרים בקטגוריות אחרות, ניתן להשתמש במשפט CASE
. בתרחיש זה, תופק שאילתת MDX יחידה עם השורות שסוננו ולמרות ש-Oracle Analytics יחיל את משפט הCASE
, המשפט יעשה שימוש בתת-סל של נתונים ולא בכל הרשומות.
הבה נתבונן בתרחיש אחר שבו משפטי CASE
גורמים לבעיות בביצועים.
מפתח מחיל משפטCASE
כדי לשנות שמות מותגים, ומנחה לוח המידע מרשה למשתמשים לבחור את המותג:
.jpg
.jpg
כיוון שמשפט הCASE
אינו נתמך ב-MDX, לא ניתן להחיל את המסנן על ‘Brand2’ בשאילתת ה-MDX. נבחרים כל המותגים, וזה לא ממוטב.
.jpg
בתרחיש זה, אנו ממליצים להסיר את משפט הCASE
ולשנות את שמות האיברים במסד הנתונים או ליצור כינויים.
בעת שימוש במסד נתונים רב-ממדי כמקור נתונים, ייתכן שתחווה בעיות ביצועים ב-Oracle Analytics שיובילו להפקת שאילתות לא אופטימליות ב-MDX. על-ידי שינוי העיצוב, תוכל לשפר את שאילתות ה-MDX המופקות ב-Oracle Analytics. לפעולה זו עשויה להיות השפעה עצומה, לא רק על ביצועי הדוחות שלך אלא גם על נפח המשאבים שבהם נעשה שימוש במסד הנתונים. היה זהיר באופן שבו אתה עושה שימוש בפונקציות נתמכות או לא נתמכות ב-MDX, כיוון שיש לזה השפעה גדולה על שאילתות ה-MDX המופקות ועל הביצועים.