แนวทางปฏิบัติที่ดีที่สุดสำหรับการสร้างแบบจำลองการสืบทอดในฐานข้อมูลคืออะไร?
อะไรคือการแลกเปลี่ยน (เช่นความสามารถในการตอบสนอง)?
(ฉันสนใจ SQL Server และ. NET มากที่สุด แต่ฉันก็อยากเข้าใจว่าแพลตฟอร์มอื่น ๆ แก้ไขปัญหานี้อย่างไร)
แนวทางปฏิบัติที่ดีที่สุดสำหรับการสร้างแบบจำลองการสืบทอดในฐานข้อมูลคืออะไร?
อะไรคือการแลกเปลี่ยน (เช่นความสามารถในการตอบสนอง)?
(ฉันสนใจ SQL Server และ. NET มากที่สุด แต่ฉันก็อยากเข้าใจว่าแพลตฟอร์มอื่น ๆ แก้ไขปัญหานี้อย่างไร)
คำตอบ:
มีหลายวิธีในการจำลองการสืบทอดในฐานข้อมูล ที่คุณเลือกขึ้นอยู่กับความต้องการของคุณ นี่คือตัวเลือกบางส่วน:
ตารางต่อประเภท (TPT)
แต่ละชั้นมีตารางของตัวเอง คลาสฐานมีองค์ประกอบคลาสพื้นฐานทั้งหมดอยู่ในนั้นและแต่ละคลาสที่ได้มาจากคลาสนั้นจะมีตารางของตัวเองโดยมีคีย์หลักซึ่งเป็นคีย์ต่างประเทศของตารางคลาสฐานด้วย คลาสของตารางที่ได้รับมีเฉพาะองค์ประกอบที่แตกต่างกัน
ตัวอย่างเช่น:
class Person {
public int ID;
public string FirstName;
public string LastName;
}
class Employee : Person {
public DateTime StartDate;
}
จะส่งผลให้ตารางเช่น:
table Person
------------
int id (PK)
string firstname
string lastname
table Employee
--------------
int id (PK, FK)
datetime startdate
ตารางต่อลำดับชั้น (TPH)
มีตารางเดียวซึ่งแสดงถึงลำดับชั้นการสืบทอดทั้งหมดซึ่งหมายความว่าหลายคอลัมน์อาจจะกระจัดกระจาย มีการเพิ่มคอลัมน์ตัวเลือกซึ่งจะบอกระบบว่านี่คือประเภทของแถวใด
จากชั้นเรียนข้างต้นคุณจะได้รับตารางนี้:
table Person
------------
int id (PK)
int rowtype (0 = "Person", 1 = "Employee")
string firstname
string lastname
datetime startdate
สำหรับแถวใด ๆ ที่เป็น rowtype 0 (Person) วันที่เริ่มต้นจะเป็นโมฆะเสมอ
ตารางต่อคอนกรีต (TPC)
แต่ละคลาสมีตารางที่สร้างขึ้นอย่างสมบูรณ์โดยไม่มีการอ้างอิงถึงตารางอื่น ๆ
จากชั้นเรียนข้างต้นคุณจะได้รับตารางเหล่านี้:
table Person
------------
int id (PK)
string firstname
string lastname
table Employee
--------------
int id (PK)
string firstname
string lastname
datetime startdate
การออกแบบฐานข้อมูลที่เหมาะสมไม่เหมือนกับการออกแบบวัตถุที่เหมาะสม
หากคุณกำลังวางแผนที่จะใช้ฐานข้อมูลสำหรับสิ่งอื่นที่ไม่ใช่เพียงแค่การทำให้เป็นอนุกรมวัตถุของคุณ (เช่นรายงานการสืบค้นการใช้งานหลายแอปพลิเคชันระบบธุรกิจอัจฉริยะเป็นต้น) ฉันไม่แนะนำให้ใช้การทำแผนที่แบบง่ายๆจากวัตถุไปยังตาราง
หลายคนคิดว่าแถวในตารางฐานข้อมูลเป็นเอนทิตี (ฉันใช้เวลาหลายปีในการคิดคำเหล่านั้น) แต่แถวไม่ใช่เอนทิตี มันเป็นเรื่อง ความสัมพันธ์ของฐานข้อมูล (เช่นตาราง) แสดงถึงข้อเท็จจริงบางประการเกี่ยวกับโลก การมีอยู่ของแถวบ่งชี้ว่าข้อเท็จจริงเป็นจริง (และในทางกลับกันการไม่มีแสดงว่าข้อเท็จจริงเป็นเท็จ)
ด้วยความเข้าใจนี้คุณจะเห็นว่าประเภทเดียวในโปรแกรมเชิงวัตถุอาจถูกจัดเก็บไว้ในความสัมพันธ์ที่แตกต่างกันโหล และความหลากหลายของประเภท (รวมกันโดยการสืบทอดการเชื่อมโยงการรวมตัวหรือไม่เป็นพันธมิตรโดยสมบูรณ์) อาจถูกเก็บไว้บางส่วนในความสัมพันธ์เดียว
ที่ดีที่สุดคือถามตัวเองว่าคุณต้องการจัดเก็บข้อเท็จจริงอะไรคำถามใดที่คุณต้องการคำตอบคุณต้องการสร้างรายงานใด
เมื่อสร้างการออกแบบฐานข้อมูลที่เหมาะสมแล้วการสร้างแบบสอบถาม / มุมมองที่ช่วยให้คุณสามารถจัดลำดับวัตถุของคุณกับความสัมพันธ์เหล่านั้นได้เป็นเรื่องง่าย
ตัวอย่าง:
ในระบบการจองโรงแรมคุณอาจต้องจัดเก็บข้อเท็จจริงที่ว่า Jane Doe มีการจองห้องพักที่ Seaview Inn ในวันที่ 10-12 เมษายน นั่นเป็นแอตทริบิวต์ของเอนทิตีลูกค้าหรือไม่? เป็นแอตทริบิวต์ขององค์กรโรงแรมหรือไม่ เป็นหน่วยงานการจองที่มีคุณสมบัติที่รวมลูกค้าและโรงแรมหรือไม่ อาจเป็นสิ่งใดสิ่งหนึ่งหรือทั้งหมดในระบบเชิงวัตถุ ในฐานข้อมูลไม่ใช่สิ่งเหล่านั้น มันเป็นเพียงความจริงที่ว่างเปล่า
หากต้องการดูความแตกต่างให้พิจารณาสองคำค้นหาต่อไปนี้ (1) Jane Doe มีการจองโรงแรมจำนวนเท่าใดในปีหน้า? (2) จำนวนห้องที่จองไว้สำหรับวันที่ 10 เมษายนที่ Seaview Inn?
ในระบบเชิงวัตถุแบบสอบถาม (1) เป็นแอตทริบิวต์ของเอนทิตีลูกค้าและแบบสอบถาม (2) เป็นแอตทริบิวต์ของเอนทิตีโรงแรม สิ่งเหล่านี้คือวัตถุที่จะเปิดเผยคุณสมบัติเหล่านั้นใน API (แม้ว่ากลไกภายในที่ได้รับค่าเหล่านั้นอาจเกี่ยวข้องกับการอ้างอิงถึงวัตถุอื่นอย่างชัดเจน)
ในระบบฐานข้อมูลเชิงสัมพันธ์การสืบค้นทั้งสองจะตรวจสอบความสัมพันธ์ของการจองเพื่อให้ได้ตัวเลขและไม่จำเป็นต้องกังวลกับ "เอนทิตี" อื่นใด
ดังนั้นจึงเป็นการพยายามจัดเก็บข้อเท็จจริงเกี่ยวกับโลกแทนที่จะพยายามจัดเก็บเอนทิตีที่มีคุณลักษณะ - ฐานข้อมูลเชิงสัมพันธ์ที่ถูกสร้างขึ้นอย่างเหมาะสม และเมื่อได้รับการออกแบบอย่างถูกต้องแล้วก็สามารถสร้างข้อความค้นหาที่เป็นประโยชน์ซึ่งไม่ได้รับความฝันในระหว่างขั้นตอนการออกแบบได้อย่างง่ายดายเนื่องจากข้อเท็จจริงทั้งหมดที่จำเป็นในการตอบสนองการสืบค้นเหล่านั้นอยู่ในตำแหน่งที่เหมาะสม
Employment
ตารางซึ่งรวบรวมการจ้างงานทั้งหมดพร้อมวันเริ่มงาน ดังนั้นหากการทราบวันที่เริ่มต้นการจ้างงานในปัจจุบันของ an Employer
เป็นสิ่งสำคัญนั่นอาจเป็นกรณีการใช้งานที่เหมาะสมสำหรับ a View
ซึ่งรวมถึงคุณสมบัตินั้นโดยการสอบถาม? (หมายเหตุ: ดูเหมือนว่าเป็นเพราะ '-' ทันทีหลังจากที่ฉันเรียกฉันไม่ได้รับการแจ้งเตือนใด ๆ ในความคิดเห็นของคุณ)
คำตอบสั้น ๆ : คุณทำไม่ได้
หากคุณต้องการจัดลำดับวัตถุของคุณให้ใช้ ORM หรือสิ่งที่ดีกว่านั้นเช่น activerecord หรือ prevaylence
หากคุณต้องการจัดเก็บข้อมูลให้จัดเก็บในลักษณะเชิงสัมพันธ์ (ระมัดระวังเกี่ยวกับสิ่งที่คุณจัดเก็บและใส่ใจกับสิ่งที่เจฟฟรีย์แอลไวท์เลดจ์พูด) ไม่ใช่สิ่งที่ได้รับผลกระทบจากการออกแบบวัตถุของคุณ
รูปแบบ TPT, TPH และ TPC เป็นวิธีที่คุณจะไปตามที่กล่าวโดย Brad Wilson แต่สองข้อสังเกต:
คลาสย่อยที่สืบทอดมาจากคลาสฐานสามารถถูกมองว่าเป็นเอนทิตีที่อ่อนแอไปยังนิยามคลาสพื้นฐานในฐานข้อมูลซึ่งหมายความว่าพวกมันขึ้นอยู่กับคลาสพื้นฐานและไม่สามารถดำรงอยู่ได้หากปราศจากมัน ฉันเคยเห็นหลายครั้ง ID ที่ไม่ซ้ำกันจะถูกเก็บไว้สำหรับแต่ละตารางย่อยในขณะที่เก็บ FK ไว้ที่ตารางหลัก FK หนึ่งตัวนั้นเพียงพอและดีกว่าที่จะเปิดใช้งานการเรียงซ้อนแบบ on-delete สำหรับความสัมพันธ์ FK ระหว่างตารางลูกและฐาน
ใน TPT โดยการดูเฉพาะระเบียนตารางฐานคุณจะไม่พบคลาสย่อยที่ระเบียนแสดงอยู่ บางครั้งจำเป็นต้องใช้เมื่อคุณต้องการโหลดรายการระเบียนทั้งหมด (โดยไม่ต้องทำ select
ในตารางย่อยแต่ละตาราง) วิธีหนึ่งในการจัดการสิ่งนี้คือการมีคอลัมน์หนึ่งคอลัมน์ที่แสดงประเภทของคลาสลูก (คล้ายกับฟิลด์ rowType ใน TPH) ดังนั้นการผสม TPT และ TPH อย่างใดอย่างหนึ่ง
สมมติว่าเราต้องการออกแบบฐานข้อมูลที่มีแผนภาพคลาสรูปร่างต่อไปนี้:
public class Shape {
int id;
Color color;
Thickness thickness;
//other fields
}
public class Rectangle : Shape {
Point topLeft;
Point bottomRight;
}
public class Circle : Shape {
Point center;
int radius;
}
การออกแบบฐานข้อมูลสำหรับคลาสข้างต้นสามารถเป็นดังนี้:
table Shape
-----------
int id; (PK)
int color;
int thichkness;
int rowType; (0 = Rectangle, 1 = Circle, 2 = ...)
table Rectangle
----------
int ShapeID; (FK on delete cascade)
int topLeftX;
int topLeftY;
int bottomRightX;
int bottomRightY;
table Circle
----------
int ShapeID; (FK on delete cascade)
int centerX;
int center;
int radius;
การสืบทอดมีสองประเภทหลักที่คุณสามารถตั้งค่าในฐานข้อมูลตารางต่อเอนทิตีและตารางต่อลำดับชั้น
ตารางต่อเอนทิตีคือที่ที่คุณมีตารางเอนทิตีพื้นฐานที่มีคุณสมบัติร่วมกันของคลาสลูกทั้งหมด จากนั้นคุณมีต่อคลาสย่อยอีกตารางหนึ่งซึ่งมีคุณสมบัติที่ใช้ได้กับคลาสนั้นเท่านั้น พวกเขาเชื่อมโยง 1: 1 โดย PK ของพวกเขา
ตารางต่อลำดับชั้นคือที่ที่คลาสทั้งหมดแชร์ตารางและคุณสมบัติทางเลือกเป็นโมฆะ พวกเขายังเป็นฟิลด์ผู้แยกแยะซึ่งเป็นตัวเลขที่แสดงถึงประเภทที่บันทึกนั้นมีอยู่ในปัจจุบัน
SessionTypeID เป็นตัวแยกแยะ
เป้าหมายต่อลำดับชั้นจะค้นหาได้เร็วขึ้นเนื่องจากคุณไม่จำเป็นต้องมีการรวม (เฉพาะค่าตัวเลือก) ในขณะที่เป้าหมายต่อเอนทิตีคุณต้องทำการรวมที่ซับซ้อนเพื่อตรวจจับว่าบางสิ่งบางอย่างเป็นประเภทใดรวมทั้งดึงข้อมูลทั้งหมดกลับคืนมา
แก้ไข: ภาพที่ฉันแสดงที่นี่เป็นภาพหน้าจอของโครงการที่ฉันกำลังทำอยู่ อิมเมจเนื้อหายังไม่สมบูรณ์ดังนั้นจึงว่างเปล่า แต่ส่วนใหญ่เป็นการแสดงวิธีการตั้งค่าไม่ใช่สิ่งที่จะใส่ในตารางของคุณ ขึ้นอยู่กับคุณ;). ตารางเซสชันเก็บข้อมูลเซสชันการทำงานร่วมกันเสมือนและอาจมีหลายประเภทของเซสชันขึ้นอยู่กับประเภทของการทำงานร่วมกันที่เกี่ยวข้อง
คุณจะทำให้ฐานข้อมูลของคุณเป็นปกติและนั่นจะสะท้อนถึงมรดกของคุณ อาจมีการลดประสิทธิภาพ แต่นั่นเป็นวิธีที่ทำให้เป็นปกติ คุณอาจจะต้องใช้สามัญสำนึกที่ดีเพื่อหาจุดสมดุล
ในการแมปหรือการแมปมรดกจะแมปกับตารางหลักที่ตารางพาเรนต์และตารางรองใช้ตัวระบุเดียวกัน
ตัวอย่างเช่น
create table Object (
Id int NOT NULL --primary key, auto-increment
Name varchar(32)
)
create table SubObject (
Id int NOT NULL --primary key and also foreign key to Object
Description varchar(32)
)
SubObject มีความสัมพันธ์คีย์ต่างประเทศกับ Object เมื่อคุณสร้างแถว SubObject ก่อนอื่นคุณต้องสร้างแถว Object และใช้ Id ในทั้งสองแถว
แก้ไข: หากคุณต้องการสร้างแบบจำลองพฤติกรรมด้วยคุณจะต้องมีตาราง Type ที่แสดงรายการความสัมพันธ์การสืบทอดระหว่างตารางและระบุแอสเซมบลีและชื่อคลาสที่ใช้พฤติกรรมของแต่ละตาราง
ดูเหมือนจะ overkill แต่ทั้งหมดนี้ขึ้นอยู่กับว่าคุณต้องการใช้มันเพื่ออะไร!
การใช้ SQL ALchemy (Python ORM) คุณสามารถสืบทอดได้สองประเภท
สิ่งที่ฉันเคยมีประสบการณ์คือการใช้ singe-table และมีคอลัมน์ที่เลือกปฏิบัติ สำหรับอินสแตนซ์ฐานข้อมูล Sheep (ไม่ใช่เรื่องตลก!) เก็บ Sheep ทั้งหมดไว้ในตารางเดียวและ Rams และ Ewes ได้รับการจัดการโดยใช้คอลัมน์เพศในตารางนั้น
ดังนั้นคุณสามารถค้นหาแกะทั้งหมดและรับแกะทั้งหมดได้ หรือคุณสามารถค้นหาโดย Ram เท่านั้นและจะได้รับ Rams เท่านั้น นอกจากนี้คุณยังสามารถทำสิ่งต่างๆเช่นมีความสัมพันธ์ที่เป็นได้เฉพาะ Ram (เช่น Sire of a Sheep) เป็นต้น
โปรดทราบว่าบางระบบฐานข้อมูลแล้วให้กลไกมรดกกำเนิดเช่นPostgres ดูที่เอกสาร
ตัวอย่างเช่นคุณจะสอบถามระบบบุคคล / พนักงานที่อธิบายไว้ในคำตอบข้างต้นดังนี้:
/ * แสดงชื่อของบุคคลหรือพนักงานทั้งหมด * / เลือกชื่อจากบุคคล / * แสดงวันที่เริ่มต้นของพนักงานทั้งหมดเท่านั้น * / เลือกวันที่เริ่มต้นจากพนักงาน
ในนั้นคือตัวเลือกฐานข้อมูลของคุณคุณไม่จำเป็นต้องฉลาดเป็นพิเศษ!