כוונון ביצועים של שאילתות מסד נתונים רב-ממדי

כאשר Oracle Analytics עושה שימוש במסד נתונים רב-ממדי כמקור נתונים, ישנם שיקולי עיצוב נוספים שעשויה להיות להם השפעה גדולה על הביצועים.

חשוב להבין שפתרונות העיצוב לשיפור ביצועים משתנים על פי תרחיש השימוש. נושא זה לא יספק לך את שיטות העבודה המומלצות או פתרון אחד שמתאים לכולם ויש ליישם תמיד. במקום זאת, אנו מציעים שיטות כוונון וטכניקות שיעזרו לך לשפר את הביצועים של הניתוחים שלך והקוד שנוצר.

זוהי אחריותו של צוות הפיתוח לבחון אפשרויות אלו, לנתח את יומני השאילתות של Oracle Analytics, ולבחור את הפתרון הטוב ביותר עבור תרחיש השימוש שלך.

נושא זה לא מתייחס לבעיות ביצועים שנגרמו בגלל התשתית שלך, כגון דפדפני הרשת או מצגת הדוח.

מתודולוגיה

אנו ממליצים להשלים את המשימות הבאות כדי להגביר את הביצועים. כדרישה מקדימה למשימות אלו, חשוב להבין את מבנה השאילתא של ביטוי רב-ממדי (MDX) וגם להבין את יומני השאילתות ש-Oracle Analytics מפיק. אלו המשימות העיקריות:

  • פישוט ה-MDX שהופק.
  • הפחתת מספר שאילתות ה-MDX שהופקו.
  • הקפדה על החלה של מסננים ובחירות אופטימליים ב-MDX.
  • כוונון ביצועים עם מנהלן מסד הנתונים (DBA) בצד השרת הרב-ממדי ובדיקה מדוע מסד הנתונים במקור עדיין מבצע גרוע.
  • שינוי הניתוח במבוסס על משוב של DBA.

אופטימיזציה של שלבי הבחירה

כאשר תבצע אופטימיזציה של שלבי בחירה תוכל לפשט את שאילתות ה-MDX, להפחית את מספר שאילתות ה-MDX המופקות, ולהגביר את הביצועים.

הנה דוגמה:

להלן תיאור של GUID-43E6F348-B14C-40DC-8C21-DA34DAE44344-default.jpg
.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.

המשתמש מבקש דוח שמראה רווח לפי רבעון ויחידת שמירת מלאי של מוצר נבחר. בנוסף, יחידות שמירת המלאי מקובצות יחד בשתיים-עשרה קטגוריות. לקטגוריה "קולה אחרת" הוקצו המוצרים הבאים של תחום פעילות עסקית: קולה, קולה דיאט, קולה דיאט משותפת.

להלן תיאור של GUID-7198F143-54E6-4A48-9579-96624936A94D-default.jpg
.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 כדי לשנות שמות מותגים, ומנחה לוח המידע מרשה למשתמשים לבחור את המותג:

להלן תיאור של GUID-56356AA9-2AF6-4A67-8ADD-FC4F7F70306C-default.jpg
.jpg

להלן תיאור של GUID-E63719C8-9936-412B-8228-F20E8F048C46-default.jpg
.jpg

כיוון שמשפט הCASE אינו נתמך ב-MDX, לא ניתן להחיל את המסנן על ‘Brand2’ בשאילתת ה-MDX. נבחרים כל המותגים, וזה לא ממוטב.

להלן תיאור של GUID-6BE1F274-8257-4E31-8D42-406357A07B2A-default.jpg
.jpg

בתרחיש זה, אנו ממליצים להסיר את משפט הCASE ולשנות את שמות האיברים במסד הנתונים או ליצור כינויים.

בעת שימוש במסד נתונים רב-ממדי כמקור נתונים, ייתכן שתחווה בעיות ביצועים ב-Oracle Analytics שיובילו להפקת שאילתות לא אופטימליות ב-MDX. על-ידי שינוי העיצוב, תוכל לשפר את שאילתות ה-MDX המופקות ב-Oracle Analytics. לפעולה זו עשויה להיות השפעה עצומה, לא רק על ביצועי הדוחות שלך אלא גם על נפח המשאבים שבהם נעשה שימוש במסד הנתונים. היה זהיר באופן שבו אתה עושה שימוש בפונקציות נתמכות או לא נתמכות ב-MDX, כיוון שיש לזה השפעה גדולה על שאילתות ה-MDX המופקות ועל הביצועים.