เอนทิตีที่ซ้อนกันและการคำนวณเกี่ยวกับคุณสมบัติของเอนทิตีใบไม้ - วิธี SQL หรือ NoSQL


10

ฉันกำลังทำงานในโครงการงานอดิเรกที่เรียกว่าการจัดการเมนู / สูตร

นี่คือลักษณะที่หน่วยงานของฉันและความสัมพันธ์ของพวกเขามีลักษณะ

NutrientมีคุณสมบัติCodeและValue

IngredientมีคอลเลกชันของNutrients

A Recipeมีคอลเล็กชันIngredientsและบางครั้งสามารถมีคอลเล็กชันอื่นได้recipes

A Mealได้รวบรวมRecipesและIngredients

A Menuมีคอลเล็กชันของMeals

ความสัมพันธ์สามารถอธิบายได้ว่า

รายการเมนูและความสัมพันธ์

ในหน้าใดหน้าหนึ่งสำหรับเมนูที่เลือกฉันจำเป็นต้องแสดงข้อมูลสารอาหารที่มีประสิทธิภาพซึ่งคำนวณจากส่วนประกอบ (อาหารสูตรอาหารส่วนผสมและสารอาหารที่เกี่ยวข้อง)

ณ ตอนนี้ฉันกำลังใช้ SQL Server เพื่อจัดเก็บข้อมูลและฉันกำลังนำทางลูกโซ่จากรหัส C # ของฉันเริ่มจากอาหารแต่ละมื้อของเมนูแล้วรวบรวมค่าสารอาหาร

ฉันคิดว่านี่ไม่ใช่วิธีที่มีประสิทธิภาพเนื่องจากการคำนวณนี้กำลังทำทุกครั้งที่มีการร้องขอหน้าเว็บและมีการเปลี่ยนแปลงองค์ประกอบในบางครั้ง

ฉันคิดเกี่ยวกับการให้บริการพื้นหลังที่รักษาตารางที่เรียกว่า MenuNutrients ( {MenuId, NutrientId, Value}) และจะเติม / อัปเดตตารางนี้ด้วยสารอาหารที่มีประสิทธิภาพเมื่อมีองค์ประกอบใด ๆ (Meal, Recipe, Ingredient) เปลี่ยนแปลง

ฉันรู้สึกว่า GraphDB เหมาะสำหรับความต้องการนี้ แต่การได้รับ NoSQL ของฉันมี จำกัด

ฉันต้องการที่จะรู้ว่าสิ่งที่เป็นทางเลือกวิธีการแก้ปัญหา / แนวทางในการแสดงสารอาหารของเมนูที่กำหนด

หวังว่าคำอธิบายของฉันเกี่ยวกับสถานการณ์จะชัดเจน


เราพูดถึงวัตถุกี่ชิ้น? ประสิทธิภาพจะเป็นปัญหาหรือไม่
flup

@flup โดยเฉลี่ยเมนูสามารถมี 8 มื้อแต่ละมื้อสามารถมี 2 สูตรและ 2 ส่วนผสมแต่ละสูตรสามารถมี 6-8 ส่วนผสม
Chandu

ลูกศรของคุณไม่ได้ไปผิดทางใช่ไหม
Branko Dimitrijevic

คุณเคยเห็นตัวอย่าง Nerd Dinner Entity Framework หรือไม่
Akash Kava

คำตอบ:


8

ขึ้นอยู่กับข้อกำหนดและสถาปัตยกรรมอาจมีตัวเลือกการปรับปรุงประสิทธิภาพ:

  • คุณสามารถใช้มุมมองที่จัดทำดัชนีไว้ (ปรับให้เป็นระดับ) เพื่อปรับปรุงประสิทธิภาพการอ่านในระดับ RDBMS (เซิร์ฟเวอร์ Sql)
    โดยทั่วไปสิ่งที่คุณต้องทำคือ
    สร้างมุมมองปกติ
    สร้างดัชนีคลัสเตอร์ในมุมมองนั้น

  • การใช้กลไกการ cashing ในระดับแอปพลิเคชันจะปรับปรุงประสิทธิภาพ
    หากเป็นไปได้และเป็นไปได้ที่จะใช้ cashing การมีกลยุทธ์เงินสดเช่นsingleton cashing ขี้เกียจจะช่วยคุณได้

NoSql:
มีบทความดีๆมากมายเกี่ยวกับ Sql vs NoSql เช่นนี้และส่วนนี้

สนใจฉัน:

จะใช้ NoSql ได้ที่ไหน:

หากฐานข้อมูลของคุณคือ3NF และคุณไม่ได้ทำการเชื่อมต่อใด ๆ (คุณเพียงแค่เลือกกลุ่มของตารางและวางวัตถุทั้งหมดเข้าด้วยกัน AKA เป็นสิ่งที่คนส่วนใหญ่ทำในเว็บแอป

เมื่อใช้พร้อมที่จะ:

  • คุณต้องเขียนงานเพื่อทำสิ่งต่าง ๆ เช่นการเข้าร่วมข้อมูลจากตาราง / คอลเลกชันที่แตกต่างกันสิ่งที่ RDBMS จะทำเพื่อคุณโดยอัตโนมัติ
  • ความสามารถในการสืบค้นของคุณด้วย NoSQL นั้นพิการอย่างมาก MongoDb อาจเป็นสิ่งที่ใกล้เคียงกับ SQL มากที่สุด แต่ก็ยังห่างไกลกันมาก เชื่อฉัน. แบบสอบถาม SQL นั้นใช้งานง่ายยืดหยุ่นและทรงพลังอย่างยิ่ง แบบสอบถาม NoSql ไม่ใช่
  • คำสั่ง MongoDb สามารถดึงข้อมูลจากการรวบรวมเพียงครั้งเดียวและใช้ประโยชน์จากดัชนีเพียงอันเดียว และ MongoDb น่าจะเป็นหนึ่งในฐานข้อมูล NoSQL ที่ยืดหยุ่นที่สุด ในหลายสถานการณ์สิ่งนี้หมายถึงการไปกลับไปยังเซิร์ฟเวอร์เพื่อค้นหาระเบียนที่เกี่ยวข้อง และจากนั้นคุณก็เริ่มทำการลดขนาดข้อมูลลงซึ่งหมายถึงงานพื้นหลัง
  • ความจริงที่ว่ามันไม่ใช่ฐานข้อมูลเชิงสัมพันธ์หมายความว่าคุณจะไม่ได้รับข้อ จำกัด ที่สำคัญในต่างประเทศเพื่อให้แน่ใจว่าข้อมูลของคุณสอดคล้องกัน ฉันมั่นใจว่านี่จะเป็นการสร้างความไม่สอดคล้องของข้อมูลในฐานข้อมูลของคุณ เตรียมตัว. เป็นไปได้ว่าคุณจะเริ่มเขียนกระบวนการหรือตรวจสอบเพื่อให้ฐานข้อมูลของคุณสอดคล้องกันซึ่งอาจจะทำงานได้ไม่ดีไปกว่าการปล่อยให้ RDBMS ทำเพื่อคุณ
  • ลืมเกี่ยวกับกรอบผู้ใหญ่เช่นจำศีล

นอกจากการตัดสินใจที่จะใช้หรือไม่ใช้ NoSql บทความที่เป็นประโยชน์เกี่ยวกับการเปรียบเทียบ NOSQL DBMS และความตั้งใจของพวกเขาสามารถพบได้ที่นี่เนื่องจากบางส่วนของพวกเขาเน้นที่การอ่านสูงเขียนต่ำแผนที่ลดฮา ...
ดู ที่การจัดอันดับและความนิยมของพวกเขาตามหมวดหมู่อาจมีประโยชน์


ขอบคุณสำหรับรายละเอียด จะตรวจสอบลิงก์และกลับไปหาคุณ
Chandu

3

ฉันจริงคุณไม่จำเป็นต้องใช้กราฟ db เพียงเก็บค่าที่ต้องการในระดับบน มันก็เหมือนกับการจัดเก็บและOrder OrderItemsคุณไม่จำเป็นต้องคำนวณผลรวมในแต่ละครั้งที่คำสั่งซื้อกำลังจะปรากฏ แต่คุณเพียงคำนวณผลรวมภาษีมูลค่าเพิ่มและสิ่งอื่น ๆ Orderและเก็บไว้กับคุณ

order.Subtotal = order.Items.Sum(item => item.Price);
order.Tax = order.Subtotal * 0.25m; // just a value
order.Total = order.Subtotal + order.Tax;

// fast forward time
var subTotal = order.Items.Sum(item => item.Price);
var tax = subTotal * 0.25m;
var total = subTotal + tax;

if (toal == order.Total) {
   Console.Log("Why the hell I've just re-calculated total?");
}

3

ผมขอแนะนำให้ไปดูที่คำสั่ง Query รูปแบบความรับผิดชอบต่อการแยกจากกัน

โดยทั่วไปแทนที่จะสร้างแบบจำลองเดียวเพื่ออ่านและเขียนคุณสามารถสร้างแบบจำลองได้ 2 แบบ หนึ่งที่เหมาะสำหรับการอัปเดตและอื่น ๆ ที่เหมาะสำหรับการค้นหา (อ่าน, การรายงาน, ... ) โมเดล 2 แบบจะถูกซิงโครไนซ์ (โดยทั่วไปจะมีความสอดคล้องในที่สุด) โดยใช้กิจกรรมโดเมน (ดู DDD)

ฉันเริ่มศึกษารูปแบบนี้เมื่อหลายเดือนก่อนและมันเปลี่ยนวิธีการทำแบบจำลองซอฟต์แวร์ของฉันจริงๆ ไม่ใช่เรื่องง่ายเพราะเป็นการเปลี่ยนแปลงครั้งใหญ่โดยเฉพาะเมื่อใช้กับเทคนิคอื่นเช่น DDD และ Event Sourcing แต่มันก็คุ้มค่า

มีทรัพยากรมากมายในเน็ตค้นหา CQRS และ DDD (และท้ายที่สุดการจัดหากิจกรรม)

รูปแบบนี้สามารถใช้กับทั้ง SQL และ noSql

ในกรณีของคุณคุณสามารถยิงเหตุการณ์ได้ทุกครั้งที่มีการเปลี่ยนแปลงสารอาหารเพื่ออัปเดตโมเดลการอ่านที่ไม่เหมาะสมสำหรับการอ่าน โมเดลการอ่านสามารถยกตัวอย่างเช่นมุมมองที่ผิดปกติของสารอาหารของเมนู (ทำไมไม่ใช้ nosql db เพื่อการอ่านที่มีประสิทธิภาพ) คุณสามารถมีรูปแบบการอ่านหลายแบบตามแบบสอบถามที่คุณต้องดำเนินการ

มีความหมายบางอย่างที่ใช้วิธีนี้ แต่มันสามารถขยายและขยายได้มาก


นี่เป็นวิธีการที่ฉันไตร่ตรองไว้ แต่ไม่แน่ใจว่าจะรับข้อมูลสำหรับโมเดลการอ่านได้อย่างไร (โดยทั่วไปกระบวนการบางอย่างควรทำให้ฉันได้รับข้อมูลสำหรับโมเดลการอ่าน)
Chandu

โดยปกติแล้วโมเดลการอ่านจะได้รับการอัพเดตทุกครั้งที่มีการเปลี่ยนแปลง คุณควรใช้ UI ด้วยคำสั่ง (ตามภารกิจ) แทนที่จะใช้การดำเนินการ crud ด้วยวิธีนี้ทุกคำสั่งเดียวจะสะท้อนให้เห็นถึงรูปแบบการอ่าน คุณไม่จำเป็นต้องดำเนินการค้นหาอื่น ๆ การออกแบบคำสั่งอนุญาตให้ระบบจับเจตนาที่แท้จริงของผู้ใช้

2

มันขึ้นอยู่กับว่าคุณทำอย่างไรเพื่อให้ได้เมนูและสารอาหารในตอนแรก ทำไมคุณคิดว่ามันจะไม่มีประสิทธิภาพ?

จากสิ่งที่ฉันเข้าใจคุณไปที่ DB รับเมนูจากนั้นไปอีกครั้งรับสูตรแต่ละสูตรจากนั้นไปอีกครั้งและรับส่วนผสมแต่ละชนิดและอื่น ๆ สิ่งนี้ไม่มีประสิทธิภาพจริง ๆ เนื่องจากมีการสอบถามและการไปกลับไปยังเซิร์ฟเวอร์จำนวนมากซึ่งเป็นสาเหตุหลักของความล่าช้า สิ่งนี้เรียกว่าปัญหา SELECT N + 1

สิ่งที่คุณควรทำคือดึงข้อมูลทั้งหมดในแบบสอบถามเดียวโดยใช้JOINs สำหรับตารางทั้งหมดจากเมนูจนถึงสารอาหารดังนั้นเซิร์ฟเวอร์ DB สามารถใช้ความสัมพันธ์และดัชนีทั้งหมดเพื่อรับข้อมูลทั้งหมดในครั้งเดียว แอป C # ไคลเอ็นต์จะประมวลผลและแสดงผลลัพธ์สุดท้ายเท่านั้น การทำเช่นนั้นมีประสิทธิภาพมากกว่าการทำทีละอย่าง

โดยทั่วไปการใช้เทคนิคการสืบค้นที่เหมาะสมและดัชนีที่เหมาะสมสำหรับการสืบค้นที่สำคัญฐานข้อมูลเชิงสัมพันธ์สามารถทำงานได้ดีมากในตารางขนาดใหญ่ภายใต้โหลด


ขอบคุณฉันเข้าใจว่าขึ้นอยู่กับการเข้าร่วม เนื่องจากองค์ประกอบของเมนูเปลี่ยนไปในบางครั้งฉันไม่ต้องการเรียกใช้การคำนวณทุกครั้งที่มีคนเข้าชมหน้าเว็บ แต่ฉันต้องการให้บริการพื้นหลังทำการคำนวณและฉันสามารถอ่านมันออกจากตารางเมื่อจำเป็น ปัญหาเกี่ยวกับการคำนวณกำลังระบุถึงห่วงโซ่ทั้งหมดเมื่อมีการเปลี่ยนแปลงองค์ประกอบอย่างใดอย่างหนึ่ง
Chandu

การค้นหาความสัมพันธ์เพียงเล็กน้อยไม่ได้เกิดขึ้นในการคำนวณใด ๆ เลยแม้ว่าจะมี 5 หรือ 6 JOINวินาทีที่ไม่ควรเป็นภาระบนเซิร์ฟเวอร์ (เว้นแต่ว่าเรากำลังพูดถึงการดึงข้อมูลหลายร้อยหรือหลายแถว) หากการทำดัชนีที่เหมาะสม อยู่ในสถานที่ แม้จะมีชุดข้อมูลขนาดใหญ่คุณสามารถสร้างมุมมองบนผลลัพธ์ทั้งหมดและแม้แต่จัดทำดัชนีมุมมองเพื่อให้คำนวณผลลัพธ์ล่วงหน้าหากประสิทธิภาพเคยเป็นปัญหา

2

ดูเหมือนว่าคุณใช้เวลาคิดเกี่ยวกับวิธีที่ดีที่สุดในการสร้างแบบจำลองข้อมูลเพื่อให้สามารถอัปเดตและสอบถามได้ง่าย อย่างไรก็ตามตอนนี้คุณอยู่ในจุดที่คุณต้องการให้การเข้าถึงข้อมูล สองสิ่งนี้แยกจากกัน

คุณพูดถึงการโหลดหน้านี้เป็นสาเหตุของแบบสอบถามใหม่ไปยังฐานข้อมูล นอกจากนี้คุณยังพูดถึงว่าฐานข้อมูลจะได้รับการปรับปรุงเป็นครั้งคราวและเมื่อใดก็ตามที่คุณต้องการให้มีการแสดงการปรับปรุงเหล่านั้นบนหน้าเว็บในเวลาที่เหมาะสม วิธีที่ดีที่สุดของคุณในการลดค่าใช้จ่ายในการสืบค้นไม่ได้ทำ หากคุณใช้คำสั่งเดียวกันซ้ำแล้วซ้ำอีกและได้ผลลัพธ์เดียวกันทำไมไม่ลองแคชสักครู่? คุณควรจะสามารถใช้การแคชต้นน้ำโดยไม่ต้องแก้ไขส่วนที่เหลือของโครงการ ฉันอยากจะแนะนำให้อ่านเกี่ยวกับการพักผ่อน. ไม่ว่าคุณจะใช้โครงการในปัญหา rdbms หรือ nosql กับประสิทธิภาพของประเภทนี้จะได้รับการจัดการที่ดีที่สุดโดยการลดจำนวนครั้งที่คุณต้องไปที่ฐานข้อมูล สมมติว่าคุณมี 100 คำขอสำหรับสูตรอาหารเดียวกันใน 60 วินาที หากคุณแคชเป็นเวลา 60 วินาทีจากนั้นคุณจะตีฐานข้อมูลเพียงครั้งเดียวนั่นคือการปรับปรุงประสิทธิภาพ 100x หากต้องการดูว่าการปรับปรุงในระดับเดียวกันโดยเปลี่ยนเป็น nosql จะต้องใช้งานมากขึ้น

ระบบประเภท Nosql อาจเป็นโซลูชันที่ยอดเยี่ยมเมื่อคุณมีข้อมูลจำนวนมากหรือต้องการความเร็วในการอ่านหรือเขียนสูง อย่างไรก็ตามประสิทธิภาพที่เพิ่มขึ้นนั้นมาจากการทิ้งสิ่งต่าง ๆ เช่น Referential Integrity


1

ดูเหมือนว่าสำหรับการทดสอบหรือความรู้ที่คุณต้องการลอง Graph-DB แต่ตัวอย่างของคุณเป็นตัวอย่างของข้อมูลลำดับชั้นที่เราสามารถเจาะลึก / ขึ้นผ่านโหนด ฉันไม่เชี่ยวชาญใน Graph / Neo DB แต่ฉันเห็นได้ว่ามีความซับซ้อนไม่มากนักในวิธีที่ผู้ใช้ / คุณสามารถขอข้อมูลจากสคีมานี้ ฉันเห็นตัวเลือกของการออกแบบฐานข้อมูล / สคีมานั้นขึ้นอยู่กับว่าข้อมูลประเภทใดที่จะถูกสอบถาม ในขณะที่คุณใช้ SQLSERVER "HierarchyI" D เป็นตัวเลือกที่ดีที่สุดจากมุมมองของฉันเพื่อทำให้โหนดนี้เป็นส่วนหนึ่งของ Tree


1

คำแนะนำของฉันคือการคิดเหมือนเครื่องจักรและไม่เหมือนมนุษย์ ดูเหมือนว่าจะซ้ำไปซ้ำมา แต่สิ่งที่เครื่องดี สิ่งหนึ่งที่คุณต้องถามตัวเองคือ "ฉันต้องดึงวัตถุทุกอันแล้วไปแสดงบนหน้าของฉันหรือไม่" ถ้าใช่ให้ทำสิ่งที่คุณกำลังทำต่อไปเมื่อเปรียบเทียบกับการดึงข้อมูล cpu cycles จะไม่สำคัญเมื่อทำคณิตศาสตร์อย่างง่าย

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.