Làm thế nào để bạn mô hình hiệu quả kế thừa trong cơ sở dữ liệu?


131

Các thực hành tốt nhất để mô hình kế thừa trong cơ sở dữ liệu là gì?

Sự đánh đổi (ví dụ như queritable) là gì?

(Tôi quan tâm nhất đến SQL Server và .NET, nhưng tôi cũng muốn hiểu cách các nền tảng khác giải quyết vấn đề này.)


14
Nếu bạn quan tâm đến "thực hành tốt nhất", hầu hết các câu trả lời đơn giản là không chính xác. Thực tiễn tốt nhất chỉ ra rằng RDb và ứng dụng là độc lập; họ có tiêu chí thiết kế hoàn toàn khác nhau. Do đó, "mô hình kế thừa" trong cơ sở dữ liệu (hoặc mô hình hóa RDb để phù hợp với một ứng dụng hoặc ngôn ngữ ứng dụng) là một thực tiễn rất xấu, không được thông tin và phá vỡ các quy tắc thiết kế RDb cơ bản và làm tê liệt nó.
PerformanceDBA


6
@PerformanceDBA Vậy đề xuất của bạn để tránh kế thừa trong mô hình DB là gì? Giả sử chúng tôi có 50 loại giáo viên khác nhau và chúng tôi muốn kết nối giáo viên cụ thể đó với lớp. Làm thế nào bạn sẽ đạt được điều đó mà không có thừa kế?
svlada

1
@svlada. Đó là cách đơn giản để thực hiện trong RDb, do đó cần phải có "sự kế thừa". Đặt một câu hỏi, bao gồm bảng defns và một ví dụ, và tôi sẽ trả lời chi tiết. Nếu bạn làm điều đó theo thuật ngữ OO, nó sẽ là một mớ hỗn độn của hoàng gia.
PerformanceDBA

Câu trả lời:


162

Có một số cách để mô hình kế thừa trong cơ sở dữ liệu. Mà bạn chọn phụ thuộc vào nhu cầu của bạn. Dưới đây là một vài lựa chọn:

Bảng mỗi loại (TPT)

Mỗi lớp có một bảng riêng. Lớp cơ sở có tất cả các thành phần lớp cơ sở trong nó và mỗi lớp xuất phát từ nó có bảng riêng, với khóa chính cũng là khóa ngoại đối với bảng lớp cơ sở; lớp của bảng dẫn xuất chỉ chứa các phần tử khác nhau.

Ví dụ:

class Person {
    public int ID;
    public string FirstName;
    public string LastName;
}

class Employee : Person {
    public DateTime StartDate;
}

Sẽ dẫn đến các bảng như:

table Person
------------
int id (PK)
string firstname
string lastname

table Employee
--------------
int id (PK, FK)
datetime startdate

Bảng theo thứ bậc (TPH)

Có một bảng duy nhất đại diện cho tất cả hệ thống phân cấp thừa kế, có nghĩa là một số cột có thể sẽ thưa thớt. Một cột phân biệt được thêm vào để cho hệ thống biết loại hàng này là gì.

Với các lớp ở trên, bạn kết thúc với bảng này:

table Person
------------
int id (PK)
int rowtype (0 = "Person", 1 = "Employee")
string firstname
string lastname
datetime startdate

Đối với bất kỳ hàng nào là rowtype 0 (Person), startdate sẽ luôn là null.

Bảng-Bê tông (TPC)

Mỗi lớp có bảng được tạo hoàn chỉnh riêng mà không có tham chiếu nào đến bất kỳ bảng nào khác.

Với các lớp ở trên, bạn kết thúc với các bảng sau:

table Person
------------
int id (PK)
string firstname
string lastname

table Employee
--------------
int id (PK)
string firstname
string lastname
datetime startdate

23
'Việc bạn chọn tùy thuộc vào nhu cầu của bạn' - vui lòng giải thích, vì tôi nghĩ lý do cho các lựa chọn là cốt lõi của câu hỏi.
Alex

12
Xem bình luận của tôi về câu hỏi. Sử dụng tên mới hài hước cho các thuật ngữ kỹ thuật của Rdb đã tồn tại dẫn đến nhầm lẫn. "TPT" là siêu kiểu phụ. "TPH" là không bình thường, một lỗi thô. "TPH" thậm chí còn ít hơn Bình thường hóa, một lỗi tổng thể khác.
PerformanceDBA

45
Chỉ có một DBA sẽ cho rằng sự không chuẩn hóa luôn luôn là một lỗi. :)
Brad Wilson

7
Mặc dù tôi sẽ thừa nhận rằng việc không chuẩn hóa dẫn đến tăng hiệu suất trong một số trường hợp, điều này hoàn toàn là do sự tách biệt không hoàn chỉnh (hoặc không tồn tại) giữa cấu trúc dữ liệu logic và vật lý trong DBMS. Thật không may, phần lớn DBMS thương mại bị vấn đề này. @PerformanceDBA là chính xác. Không chuẩn hóa là một lỗi phán xét, hy sinh tính nhất quán dữ liệu cho tốc độ. Đáng buồn thay, đó là một lựa chọn mà một DBA hoặc nhà phát triển sẽ không bao giờ cần phải thực hiện nếu DBMS được thiết kế đúng. Đối với hồ sơ tôi không phải là một DBA.
Kenneth Cochran

6
@Brad Wilson. Chỉ có một nhà phát triển sẽ không bình thường, "cho hiệu suất", hoặc nếu không. Thông thường, nó không bình thường hóa, sự thật là nó không bình thường. Việc không chuẩn hóa hoặc không chuẩn hóa là một lỗi, là một thực tế, được hỗ trợ bởi lý thuyết và được hàng triệu người trải nghiệm, nó không phải là một "giả định".
PerformanceDBA

133

Thiết kế cơ sở dữ liệu phù hợp là không có gì giống như thiết kế đối tượng thích hợp.

Nếu bạn đang dự định sử dụng cơ sở dữ liệu cho bất kỳ thứ gì ngoài việc đơn giản hóa việc sắp xếp các đối tượng của bạn (như báo cáo, truy vấn, sử dụng đa ứng dụng, kinh doanh thông minh, v.v.) thì tôi không khuyến nghị bất kỳ loại ánh xạ đơn giản nào từ các đối tượng vào bảng.

Nhiều người nghĩ về một hàng trong bảng cơ sở dữ liệu như một thực thể (tôi đã dành nhiều năm để suy nghĩ theo các thuật ngữ đó), nhưng một hàng không phải là một thực thể. Đó là một đề xuất. Một quan hệ cơ sở dữ liệu (nghĩa là bảng) đại diện cho một số tuyên bố thực tế về thế giới. Sự hiện diện của hàng chỉ ra thực tế là đúng (và ngược lại, sự vắng mặt của nó cho thấy thực tế là sai).

Với sự hiểu biết này, bạn có thể thấy rằng một loại duy nhất trong một chương trình hướng đối tượng có thể được lưu trữ trên một tá các mối quan hệ khác nhau. Và một loạt các loại (thống nhất bởi sự kế thừa, liên kết, tập hợp hoặc hoàn toàn không liên kết) có thể được lưu trữ một phần trong một mối quan hệ duy nhất.

Tốt nhất bạn nên tự hỏi mình, bạn muốn lưu trữ những sự thật nào, câu hỏi nào bạn muốn có câu trả lời, bạn muốn tạo báo cáo nào.

Khi thiết kế DB phù hợp được tạo, thì việc tạo truy vấn / khung nhìn cho phép bạn tuần tự hóa các đối tượng của mình theo các mối quan hệ đó là một vấn đề đơn giản.

Thí dụ:

Trong một hệ thống đặt phòng khách sạn, bạn có thể cần lưu trữ thực tế rằng Jane Doe có đặt phòng cho Seaview Inn cho ngày 10-12 tháng 4. Đó có phải là một thuộc tính của thực thể khách hàng? Nó có phải là một thuộc tính của thực thể khách sạn? Đây có phải là một thực thể đặt phòng với các tài sản bao gồm khách hàng và khách sạn? Nó có thể là bất kỳ hoặc tất cả những điều đó trong một hệ thống hướng đối tượng. Trong một cơ sở dữ liệu, nó không phải là một trong những điều đó. Nó chỉ đơn giản là một sự thật trần trụi.

Để thấy sự khác biệt, hãy xem xét hai truy vấn sau đây. (1) Jane Doe có bao nhiêu đặt phòng khách sạn cho năm tới? (2) Có bao nhiêu phòng được đặt cho ngày 10 tháng 4 tại Seaview Inn?

Trong một hệ thống hướng đối tượng, truy vấn (1) là một thuộc tính của thực thể khách hàng và truy vấn (2) là một thuộc tính của thực thể khách sạn. Đó là những đối tượng sẽ phơi bày các thuộc tính đó trong API của họ. (Mặc dù, rõ ràng các cơ chế bên trong mà các giá trị đó thu được có thể liên quan đến các tham chiếu đến các đối tượng khác.)

Trong một hệ thống cơ sở dữ liệu quan hệ, cả hai truy vấn sẽ kiểm tra mối quan hệ đặt trước để lấy số của chúng và về mặt khái niệm không cần phải bận tâm với bất kỳ "thực thể" nào khác.

Vì vậy, đó là bằng cách cố gắng lưu trữ các sự kiện về thế giới, thay vì cố gắng lưu trữ các thực thể với các thuộc tính, một cơ sở dữ liệu quan hệ phù hợp được xây dựng. Và một khi nó được thiết kế đúng, thì có thể dễ dàng xây dựng các truy vấn hữu ích trong giai đoạn thiết kế, vì tất cả các sự kiện cần thiết để thực hiện các truy vấn đó đều nằm ở vị trí thích hợp của chúng.


12
+1 Cuối cùng, một hòn đảo của kiến ​​thức chân chính trong một biển vô minh (và từ chối học bất cứ điều gì ngoài phạm vi của họ). Đồng ý, đó không phải là phép thuật: nếu RDb được thiết kế bằng cách sử dụng các dự đoán RDb, việc "lập bản đồ" hoặc "dự án" bất kỳ "lớp" nào là dễ dàng. Việc buộc RDb vào các yêu cầu dựa trên lớp đơn giản là không chính xác.
PerformanceDBA

2
Câu trả lời thú vị. Làm thế nào bạn có thể đề xuất mô hình hóa ví dụ Người-Nhân viên trong câu trả lời được chấp nhận?
bảy lực lượng

2
@ sevenforce - Thiết kế DB thực sự phụ thuộc vào các yêu cầu của hệ thống, không được đưa ra. Không có đủ thông tin cung cấp để quyết định. Trong nhiều trường hợp, một cái gì đó tương tự như thiết kế "bảng mỗi loại" có thể phù hợp, nếu không tuân theo một cách mù quáng. Ví dụ, ngày bắt đầu có lẽ là một tài sản tốt cho một đối tượng Nhân viên, nhưng trong cơ sở dữ liệu, nó thực sự phải là một trường trong bảng Việc làm, vì một người có thể được thuê nhiều lần với nhiều ngày bắt đầu. Điều này không quan trọng đối với các đối tượng (sẽ sử dụng gần đây nhất), nhưng nó rất quan trọng trong cơ sở dữ liệu.
Jeffrey L Whitledge

2
Chắc chắn, câu hỏi của tôi chủ yếu là về cách để mô hình thừa kế. Xin lỗi vì không đủ rõ ràng. Cảm ơn. Như bạn đã đề cập, rất có thể nên có một Employmentbảng, thu thập tất cả các việc làm với ngày bắt đầu của họ. Vì vậy, nếu biết ngày bắt đầu việc làm hiện tại của một Employerlà quan trọng, đó có thể là trường hợp sử dụng thích hợp cho một View, bao gồm tài sản đó bằng cách truy vấn? (lưu ý: dường như vì '-' ngay sau nick của tôi, tôi không nhận được bất kỳ thông báo nào về bình luận của bạn)
sevenforce

5
Đây là một viên ngọc thực sự của một câu trả lời. Sẽ cần một chút thời gian để thực sự chìm đắm và yêu cầu một số bài tập để làm đúng, nhưng nó đã ảnh hưởng đến quá trình suy nghĩ của tôi về thiết kế cơ sở dữ liệu quan hệ.
MarioDS

9

Câu trả lời ngắn gọn: bạn không.

Nếu bạn cần tuần tự hóa các đối tượng của mình, hãy sử dụng ORM hoặc thậm chí tốt hơn những thứ như Activerecord hoặc thịnh hành.

Nếu bạn cần lưu trữ dữ liệu, hãy lưu trữ dữ liệu theo cách liên quan (cẩn thận với những gì bạn đang lưu trữ và chú ý đến những gì Jeffrey L Whitledge vừa nói), không bị ảnh hưởng bởi thiết kế đối tượng của bạn.


3
+1 Cố gắng mô hình kế thừa trong cơ sở dữ liệu là một sự lãng phí tài nguyên quan hệ tốt.
Daniel Spiewak

7

Các mẫu TPT, TPH và TPC là những cách bạn đi, như Brad Wilson đã đề cập. Nhưng vài lưu ý:

  • các lớp con kế thừa từ một lớp cơ sở có thể được coi là các thực thể yếu đối với định nghĩa lớp cơ sở trong cơ sở dữ liệu, có nghĩa là chúng phụ thuộc vào lớp cơ sở của chúng và không thể tồn tại mà không có nó. Tôi đã thấy số lần, các ID duy nhất được lưu trữ cho mỗi bảng con trong khi vẫn giữ FK cho bảng cha. Một FK là vừa đủ và thậm chí còn tốt hơn khi bật tầng cho phép xóa mối quan hệ FK giữa bảng con và bảng cơ sở.

  • Trong TPT, bằng cách chỉ xem các bản ghi bảng cơ sở, bạn không thể tìm thấy lớp con nào mà bản ghi đang biểu diễn. Điều này đôi khi cần thiết, khi bạn muốn tải một danh sách tất cả các bản ghi (không thực hiện select trên mỗi bảng con). Một cách để xử lý việc này là có một cột biểu thị loại lớp con (tương tự như trường rowType trong TPH), do đó, trộn lẫn TPT và TPH bằng cách nào đó.

Giả sử chúng tôi muốn thiết kế một cơ sở dữ liệu chứa sơ đồ lớp hình dạng sau:

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;
}

Thiết kế cơ sở dữ liệu cho các lớp trên có thể như thế này:

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;

4

Có hai loại thừa kế chính mà bạn có thể thiết lập trong DB, bảng cho mỗi thực thể và bảng theo Phân cấp.

Bảng trên mỗi thực thể là nơi bạn có một bảng thực thể cơ sở có các thuộc tính chung của tất cả các lớp con. Sau đó, bạn có mỗi lớp con một bảng khác chỉ có các thuộc tính áp dụng cho lớp đó. Chúng được liên kết 1: 1 bởi PK của họ

văn bản thay thế

Bảng trên mỗi hệ thống phân cấp là nơi tất cả các lớp chia sẻ một bảng và các thuộc tính tùy chọn là không thể. Họ cũng là một trường phân biệt đối xử là một số biểu thị loại mà hồ sơ hiện đang nắm giữ

văn bản thay thế SessionTypeID là phân biệt đối xử

Mục tiêu trên mỗi phân cấp nhanh hơn để truy vấn vì bạn không cần tham gia (chỉ có giá trị phân biệt đối xử), trong khi mục tiêu cho mỗi thực thể bạn cần thực hiện các phép nối phức tạp để phát hiện loại gì cũng như lấy lại tất cả dữ liệu của nó ..

Chỉnh sửa: Hình ảnh tôi hiển thị ở đây là ảnh chụp màn hình của một dự án tôi đang thực hiện. Hình ảnh Tài sản không đầy đủ, do đó, nó trống rỗng, nhưng chủ yếu là để hiển thị cách thiết lập của nó, chứ không phải những gì để đặt trong các bảng của bạn. Điều đó tùy thuộc vào bạn ;). Bảng phiên chứa thông tin phiên cộng tác ảo và có thể có một số loại phiên tùy thuộc vào loại cộng tác nào có liên quan.


Tôi cũng sẽ xem xét Target mỗi lớp Concrete không thực sự mô hình kế thừa tốt và vì vậy tôi đã không hiển thị.
mattlant

Bạn có thể thêm một tài liệu tham khảo nơi minh họa là từ?
chryss

Đâu là những hình ảnh bạn đang nói về cuối câu trả lời của bạn?
Musa Haidari

1

Bạn sẽ bình thường hóa cơ sở dữ liệu của bạn và điều đó thực sự sẽ phản ánh sự kế thừa của bạn. Nó có thể có sự suy giảm hiệu suất, nhưng đó là cách nó được bình thường hóa. Bạn có thể sẽ phải sử dụng ý thức chung tốt để tìm sự cân bằng.


2
Tại sao mọi người tin rằng bình thường hóa một cơ sở dữ liệu làm giảm hiệu suất? mọi người cũng nghĩ rằng nguyên tắc DRY làm giảm hiệu suất mã? sự hiểu lầm này đến từ đâu?
Steven A. Lowe

1
Có thể bởi vì việc không chuẩn hóa có thể cải thiện hiệu suất, do đó bình thường hóa làm suy giảm nó, tương đối nói. Không thể nói tôi đồng ý với nó, nhưng đó có lẽ là cách nó diễn ra.
Matthew Scharley

2
Khi bắt đầu, chuẩn hóa có thể có ảnh hưởng nhỏ đến hiệu suất, nhưng theo thời gian, khi số lượng hàng tăng lên, THAM GIA hiệu quả sẽ bắt đầu vượt trội so với các bảng cồng kềnh. Tất nhiên, bình thường hóa có những lợi ích khác, lớn hơn - tính nhất quán và thiếu sự dư thừa, v.v.
Rob

1

lặp lại câu trả lời chủ đề tương tự

trong ánh xạ OR, ánh xạ kế thừa vào một bảng cha trong đó các bảng cha và con sử dụng cùng một mã định danh

ví dụ

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 có mối quan hệ khóa ngoài với Object. Khi bạn tạo một hàng SubObject, trước tiên bạn phải tạo một hàng Object và sử dụng Id trong cả hai hàng

EDIT: nếu bạn đang tìm cách mô hình hóa hành vi, bạn sẽ cần một bảng Loại liệt kê các mối quan hệ thừa kế giữa các bảng và chỉ định tên tập hợp và tên lớp thực hiện hành vi của mỗi bảng

Có vẻ như quá mức cần thiết, nhưng tất cả phụ thuộc vào những gì bạn muốn sử dụng nó cho!


Cuộc thảo luận đó cuối cùng là về việc thêm một vài cột vào mỗi bảng, không phải về mô hình kế thừa. Tôi nghĩ rằng tiêu đề của cuộc thảo luận đó nên được thay đổi để phản ánh tốt hơn bản chất của câu hỏi và thảo luận.
Ngay cả Miên

1

Sử dụng SQL ALchemy (Python ORM), bạn có thể thực hiện hai loại kế thừa.

Người mà tôi đã có kinh nghiệm là sử dụng bảng đơn và có một cột phân biệt đối xử. Chẳng hạn, cơ sở dữ liệu Sheep (không đùa!) Đã lưu trữ tất cả Sheep trong một bảng và Ram và Ewes được xử lý bằng cột giới tính trong bảng đó.

Vì vậy, bạn có thể truy vấn tất cả Cừu và lấy tất cả Cừu. Hoặc bạn chỉ có thể truy vấn bằng Ram và nó sẽ chỉ nhận được Ram. Bạn cũng có thể làm những việc như có một mối quan hệ chỉ có thể là Ram (tức là Sire of a Sheep), v.v.


1

Lưu ý rằng một số công cụ cơ sở dữ liệu đã cung cấp các cơ chế kế thừa thực sự giống như Postgres . Nhìn vào tài liệu .

Ví dụ: bạn sẽ truy vấn hệ thống Người / Nhân viên được mô tả trong phản hồi ở trên như sau:

  / * Điều này hiển thị tên của tất cả người hoặc nhân viên * /
  CHỌN tên đầu tiên từ người; 

  / * Điều này chỉ hiển thị ngày bắt đầu của tất cả nhân viên * /
  CHỌN ngày bắt đầu từ nhân viên;

Trong đó là lựa chọn cơ sở dữ liệu của bạn, bạn không cần phải đặc biệt thông minh!

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.