@Bill Karwin mô tả ba mô hình thừa kế trong cuốn sách SQL Antipotypes của mình , khi đề xuất các giải pháp cho Thực thể-Thuộc tính-Giá trị SQL . Đây là một tổng quan ngắn gọn:
Kế thừa bảng đơn (hay còn gọi là Bảng kế thừa phân cấp):
Sử dụng một bảng duy nhất như trong tùy chọn đầu tiên của bạn có lẽ là thiết kế đơn giản nhất. Như bạn đã đề cập, nhiều thuộc tính dành riêng cho kiểu con sẽ phải được cung cấp một NULL
giá trị trên các hàng nơi các thuộc tính này không áp dụng. Với mô hình này, bạn sẽ có một bảng chính sách, trông giống như thế này:
+------+---------------------+----------+----------------+------------------+
| id | date_issued | type | vehicle_reg_no | property_address |
+------+---------------------+----------+----------------+------------------+
| 1 | 2010-08-20 12:00:00 | MOTOR | 01-A-04004 | NULL |
| 2 | 2010-08-20 13:00:00 | MOTOR | 02-B-01010 | NULL |
| 3 | 2010-08-20 14:00:00 | PROPERTY | NULL | Oxford Street |
| 4 | 2010-08-20 15:00:00 | MOTOR | 03-C-02020 | NULL |
+------+---------------------+----------+----------------+------------------+
\------ COMMON FIELDS -------/ \----- SUBTYPE SPECIFIC FIELDS -----/
Giữ cho thiết kế đơn giản là một lợi thế, nhưng vấn đề chính của phương pháp này là:
Khi nói đến việc thêm các kiểu con mới, bạn sẽ phải thay đổi bảng để chứa các thuộc tính mô tả các đối tượng mới này. Điều này có thể nhanh chóng trở thành vấn đề khi bạn có nhiều kiểu con hoặc nếu bạn có kế hoạch thêm các kiểu con một cách thường xuyên.
Cơ sở dữ liệu sẽ không thể thực thi các thuộc tính nào được áp dụng và không thuộc tính nào, vì không có siêu dữ liệu để xác định thuộc tính nào thuộc về các kiểu con.
Bạn cũng không thể thực thi các NOT NULL
thuộc tính của một kiểu con nên là bắt buộc. Bạn sẽ phải xử lý điều này trong ứng dụng của bạn, nói chung là không lý tưởng.
Kế thừa bảng bê tông:
Một cách tiếp cận khác để giải quyết sự kế thừa là tạo một bảng mới cho mỗi kiểu con, lặp lại tất cả các thuộc tính phổ biến trong mỗi bảng. Ví dụ:
--// Table: policies_motor
+------+---------------------+----------------+
| id | date_issued | vehicle_reg_no |
+------+---------------------+----------------+
| 1 | 2010-08-20 12:00:00 | 01-A-04004 |
| 2 | 2010-08-20 13:00:00 | 02-B-01010 |
| 3 | 2010-08-20 15:00:00 | 03-C-02020 |
+------+---------------------+----------------+
--// Table: policies_property
+------+---------------------+------------------+
| id | date_issued | property_address |
+------+---------------------+------------------+
| 1 | 2010-08-20 14:00:00 | Oxford Street |
+------+---------------------+------------------+
Thiết kế này về cơ bản sẽ giải quyết các vấn đề được xác định cho phương pháp bảng đơn:
Các thuộc tính bắt buộc có thể được thi hành bằng NOT NULL
.
Thêm một kiểu con mới yêu cầu thêm một bảng mới thay vì thêm các cột vào một bảng hiện có.
Cũng không có rủi ro rằng một thuộc tính không phù hợp được đặt cho một kiểu con cụ thể, chẳng hạn như vehicle_reg_no
trường cho chính sách thuộc tính.
Không cần type
thuộc tính như trong phương thức bảng đơn. Loại hiện được xác định bởi siêu dữ liệu: tên bảng.
Tuy nhiên mô hình này cũng đi kèm với một vài nhược điểm:
Các thuộc tính phổ biến được trộn lẫn với các thuộc tính cụ thể của kiểu con và không có cách nào dễ dàng để xác định chúng. Cơ sở dữ liệu cũng sẽ không biết.
Khi xác định các bảng, bạn sẽ phải lặp lại các thuộc tính chung cho mỗi bảng phụ. Đó chắc chắn không phải là KHÔ .
Tìm kiếm tất cả các chính sách bất kể loại phụ trở nên khó khăn và sẽ cần một loạt các chính sách UNION
.
Đây là cách bạn sẽ phải truy vấn tất cả các chính sách bất kể loại:
SELECT date_issued, other_common_fields, 'MOTOR' AS type
FROM policies_motor
UNION ALL
SELECT date_issued, other_common_fields, 'PROPERTY' AS type
FROM policies_property;
Lưu ý cách thêm các kiểu con mới sẽ yêu cầu sửa đổi truy vấn ở trên với phần bổ sung UNION ALL
cho mỗi kiểu con. Điều này có thể dễ dàng dẫn đến lỗi trong ứng dụng của bạn nếu thao tác này bị quên.
Kế thừa bảng lớp (hay còn gọi là kế thừa bảng theo loại):
Đây là giải pháp mà @David đề cập trong câu trả lời khác . Bạn tạo một bảng duy nhất cho lớp cơ sở của bạn, bao gồm tất cả các thuộc tính phổ biến. Sau đó, bạn sẽ tạo các bảng cụ thể cho từng kiểu con, có khóa chính cũng đóng vai trò là khóa ngoại đối với bảng cơ sở. Thí dụ:
CREATE TABLE policies (
policy_id int,
date_issued datetime,
-- // other common attributes ...
);
CREATE TABLE policy_motor (
policy_id int,
vehicle_reg_no varchar(20),
-- // other attributes specific to motor insurance ...
FOREIGN KEY (policy_id) REFERENCES policies (policy_id)
);
CREATE TABLE policy_property (
policy_id int,
property_address varchar(20),
-- // other attributes specific to property insurance ...
FOREIGN KEY (policy_id) REFERENCES policies (policy_id)
);
Giải pháp này giải quyết các vấn đề được xác định trong hai thiết kế khác:
Các thuộc tính bắt buộc có thể được thi hành với NOT NULL
.
Thêm một kiểu con mới yêu cầu thêm một bảng mới thay vì thêm các cột vào một bảng hiện có.
Không có rủi ro rằng một thuộc tính không phù hợp được đặt cho một kiểu con cụ thể.
Không cần type
thuộc tính.
Bây giờ các thuộc tính phổ biến không được trộn lẫn với các thuộc tính cụ thể của kiểu con nữa.
Chúng ta có thể ở lại KHÔ, cuối cùng. Không cần lặp lại các thuộc tính chung cho mỗi bảng phụ khi tạo các bảng.
Việc quản lý tăng tự động id
cho các chính sách trở nên dễ dàng hơn, bởi vì điều này có thể được xử lý bởi bảng cơ sở, thay vì mỗi bảng phụ tạo ra chúng một cách độc lập.
Tìm kiếm tất cả các chính sách bất kể loại phụ bây giờ trở nên rất dễ dàng: Không UNION
cần thiết - chỉ cần a SELECT * FROM policies
.
Tôi coi cách tiếp cận bảng lớp là phù hợp nhất trong hầu hết các tình huống.
Tên của ba mô hình này xuất phát từ cuốn sách Các mô hình kiến trúc ứng dụng doanh nghiệp của Martin Fowler .