เมื่อคุณใช้ฐานข้อมูลแบบหลายไดเมนชันเป็นที่มาข้อมูลใน Oracle Analytics คุณอาจประสบปัญหาด้านประสิทธิภาพซึ่งทำให้เกิดการสืบค้น Suboptimal Multidimensional Expression (MDX) ที่สร้างโดยมีประสิทธิภาพลดลง
คุณสามารถปรับปรุงการสืบค้น MDX ที่ Oracle Analytics สร้างขึ้นได้โดยการแก้ไขการออกแบบ การดำเนินการนี้จะส่งผลกระทบอย่างมาก ไม่เฉพาะต่อประสิทธิภาพของรายงานของคุณ แต่กับปริมาณทรัพยากรที่ใช้ในฐานข้อมูลด้วย วิธีที่คุณใช้ฟังก์ชันที่รองรับหรือไม่รองรับจะส่งผลกระทบต่อการสืบค้น MDX ที่สร้างขึ้นและประสิทธิภาพการทำงานเป็นอย่างมาก
เนื่องจากแต่ละกรณีการใช้งานไม่ซ้ำกัน ทีมพัฒนาของคุณควรตรวจดูตัวเลือกต่างๆ ให้วิเคราะห์ล็อกการสืบค้น Oracle Analytics และเลือกทางแก้ปัญหาที่ดีที่สุดสำหรับกรณีการใช้งานของคุณ
หัวข้อนี้ไม่แสดงปัญหาด้านประสิทธิภาพที่เกิดจากโครงสร้างพื้นฐานของคุณ เช่น เน็ตเวิร์ก เบราเซอร์ หรือการนำเสนอรายงาน
วิธีการ
Oracle แนะนำให้คุณดำเนินการกับงานต่อไปนี้เพื่อเพิ่มประสิทธิภาพ สิ่งสำคัญคือคุณต้องเข้าใจโครงสร้างการสืบค้น MDX รวมถึงล็อกการสืบค้นที่ Oracle Analytics สร้างขึ้น
การออปติไมซ์ขั้นตอนการเลือก
คุณคุณออปติไมซ์ขั้นตอนการเลือก คุณจะสามารถลดความยุ่งยากของการสืบค้น MDX, ลดจำนวนการสืบค้น MDX ที่สร้าง และเพิ่มประสิทธิภาพ
รูปต่อไปนี้แสดงตัวอย่างการเปรียบเทียบขั้นตอนการเลือกที่ออปติไมซ์และที่ไม่ได้ออปติไมซ์
.jpg
คำสั่ง CASE
ฟังก์ชันของคำสั่ง CASE
ไม่ได้รับการรองรับในการสืบค้น MDX และต้องมีการใช้งานใน Oracle Analytics เสมอ ตรรกะที่อธิบายในส่วนนี้เกี่ยวกับคำสั่ง CASE
เป็นตรรกะที่ใช้ได้สำหรับฟังก์ชันส่วนมาก ซึ่งไม่ได้รับการรองรับในการสืบค้น MDX (if null
เป็นต้น)
มีข้อดีและข้อเสียเมื่อใช้คำสั่ง CASE
เมื่อคุณรวมคำสั่ง CASE
ไว้ในสูตรรายงาน คำสั่งเหล่านี้จะไม่รวมอยู่ในการสืบค้น MDX ซึ่งจะช่วยลดความยุ่งยากและปรับปรุงประสิทธิภาพของการสืบค้น MDX ได้ อย่างไรก็ตาม ข้อเสียคือ คุณจะไม่สามารถฟิลเตอร์ข้อมูลได้อย่างมีประสิทธิภาพ ซึ่งหมายความว่าการสืบค้นอาจส่งคืนเรคคอร์ดมากเกินความจำเป็น
ต่อไปนี้เป็นข้อจำกัดในการใช้ฟังก์ชันคำสั่ง CASE
:
CASE
ไม่รวมสมาชิกจำนวนมาก คอลัมน์ฐานที่ใช้ในคำสั่งต้องรวมอยู่ในการสืบค้นและวิวในลักษณะคอลัมน์แยกต่างหากที่ซ่อนไว้CASE
รวมสมาชิกจำนวนมาก คอลัมน์ฐานจะไม่สามารถรวมอยู่ในวิวโดยไม่มีผลกระทบต่อระดับของการสรุปรวม หากเป็นกรณีนี้:
SUM
, MAX
, MIN
) การดำเนินการนี้จะใช้ได้ ก็ต่อเมื่อมีการใช้กฎการสรุปรวมภายในเพื่อรวมสมาชิก และแสดงผลลัพธ์ที่ถูกต้องฟังก์ชัน FILTER
แตกต่างจากฟังก์ชันคำสั่ง CASE
ระบบสามารถส่งฟังก์ชัน FILTER
ไปยังฐานข้อมูลเพื่อการรันได้
ประโยชน์หลักของการใช้ฟังก์ชัน FILTER
ในสูตรรายงานก็คือ มีการใช้การเลือกในการสืบค้น MDX และปริมาณข้อมูลที่คำนวณและเรียกจากฐานข้อมูลจะลดลง
ข้อเสียหลักของการใช้ฟังก์ชัน FILTER
ก็คือ อาจเพิ่มจำนวนการสืบค้น MDX ที่รัน ตามค่าดีฟอลต์ ระบบจะรันการสืบค้นหนึ่งรายการสำหรับฟังก์ชัน FILTER
แต่ละรายการที่ใช้
ตัวอย่าง CASE เทียบกับ FILTER
ในตัวอย่างนี้ ผู้ใช้ขอรายงานที่แสดงผลกำไรแยกตามไตรมาสและ SKU ผลิตภัณฑ์ที่เลือก นอกจากนี้ SKU ยังได้รับการจัดกลุ่มเข้าด้วยกันเป็น 12 ชนิด ชนิด Other Cola มีผลิตภัณฑ์ของ LOB ที่ระบุไว้ดังต่อไปนี้: Cola, Diet Cola และ Shared Diet Cola
.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
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]
หรือคุณสามารถใช้ฟิลเตอร์กับเมตริคผลกำไรเพื่อดึงข้อมูลสมาชิก LOB ที่จำเป็นเท่านั้น ในสถานการณ์นี้ คุณสร้างเมตริค สามรายการที่มีการใช้ฟิลเตอร์ที่เกี่ยวข้อง
นี่คือการสืบค้นแบบลอจิคัลของคำสั่ง 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 เดียวด้วยแถวที่ฟิลเตอร์ และแม้ว่าจะมีการใช้คำสั่ง CASE
โดย Oracle Analytics แต่จะใช้เฉพาะสับเซ็ตของข้อมูลและไม่ใช่ข้อมูลทั้งหมด
นี่คือสถานการณ์อื่นโดยที่คำสั่ง CASE
ทำให้เกิดปัญหาด้านประสิทธิภาพ
ผู้พัฒนาใช้คำสั่ง CASE
ในการเปลี่ยนชื่อตราสินค้า และผู้ใช้สามารถใช้พรอมต์ของแผงข้อมูลในการเลือกตราสินค้าได้
.jpg
.jpg
เนื่องจากคำสั่ง CASE
ไม่ได้รับการรับรองใน MDX จึงไม่สามารถใช้การฟิลเตอร์ Brand2
ในการสืบค้น MDX ได้ เลือกตราสินค้าทั้งหมดแล้ว และไม่ได้รับการออปติไมซ์
.jpg
ในสถานการณ์นี้ Oracle แนะนำให้คุณย้ายคำสั่ง CASE
ออก และเปลี่ยนชื่อสมาชิกในฐานข้อมูล หรือสร้างชื่อแทน