bảng tự tham khảo, tốt hay xấu? [đóng cửa]


37

Thể hiện các vị trí địa lý trong một ứng dụng, thiết kế mô hình dữ liệu cơ bản gợi ý hai tùy chọn rõ ràng (hoặc có thể nhiều hơn?).

Một bảng có cột Parent_id tự tham chiếu uk - london (london cha id = UK id)

hoặc hai bảng, với mối quan hệ một đến nhiều bằng cách sử dụng khóa ngoại.

Sở thích của tôi là dành cho một bảng tự ép vì nó dễ dàng cho phép mở rộng ra nhiều vùng phụ theo yêu cầu.

Ở chung, mọi người có tránh xa các bảng tự tham chiếu hay họ A-OK?

Câu trả lời:


40

Không có gì sai với bảng tự tham khảo.

Đây là mẫu thiết kế cơ sở dữ liệu phổ biến cho các hệ thống phân cấp lồng nhau sâu (vô cực?).


@NimChimpsky - Giống như khái niệm đệ quy, ý tưởng này rất khó đối với một số người.
Oded

2
(Ít nhất) Oracle thậm chí còn có một điều khoản SQL đặc biệt, mệnh đề "BẮT ĐẦU VỚI - KẾT NỐI B" NG, để đối phó với các bảng tự tham chiếu.
dùng281377

1
@ user281377 - Và SQL Server đã giới thiệu hierarchyidloại.
Oded

cho phép ngủ đông để nó có nước sốt đặc biệt của riêng mình
NimChimpsky

4
@NimChimpsky - Hãy xem xét việc xem "Mô hình tập hợp lồng nhau" như là một thay thế cho cột "Parent_id" đó - nó cung cấp cùng chức năng, nhưng hiệu suất tốt hơn và truy vấn dễ dàng hơn để trích xuất phân cấp. vi.wikipedia.org/wiki/Nested_set_model Bộ sách "SQL dành cho người thông minh" của Joe Celko có một số mẫu SQL tuyệt vời liên quan đến các bộ lồng nhau.
Keith Palmer Jr.

7

Necromance.
Câu trả lời đúng là: nó phụ thuộc vào công cụ cơ sở dữ liệu nào và công cụ quản lý nào.

Hãy lấy một ví dụ:
Chúng tôi có một bảng báo cáo
và một báo cáo có thể có cha mẹ (menupoint, giống như thể loại)
và chính cha mẹ đó có thể có cha mẹ (ví dụ: Trung tâm lợi nhuận),
v.v.

Ví dụ đơn giản nhất về mối quan hệ đệ quy tiêu chuẩn, như với bất kỳ thực thể / hệ thống phân cấp tự tham chiếu nào.

Bảng SQL-Server kết quả là:

IF  EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'dbo.FK_T_FMS_Reports_T_FMS_Reports') AND parent_object_id = OBJECT_ID(N'dbo.T_FMS_Reports'))
ALTER TABLE dbo.T_FMS_Reports DROP CONSTRAINT FK_T_FMS_Reports_T_FMS_Reports
GO

IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'dbo.T_FMS_Reports') AND type in (N'U'))
DROP TABLE dbo.T_FMS_Reports 
GO



CREATE TABLE dbo.T_FMS_Reports 
( 
     RE_UID uniqueidentifier NOT NULL 
    ,RE_RE_UID uniqueidentifier NULL 
    ,RE_Text nvarchar(255) NULL 
    ,RE_Link nvarchar(400) NULL 
    ,RE_Sort int NOT NULL 
    ,RE_Status int NOT NULL 
    ,PRIMARY KEY CLUSTERED ( RE_UID ) 
); 

GO

ALTER TABLE dbo.T_FMS_Reports  WITH CHECK ADD  CONSTRAINT FK_T_FMS_Reports_T_FMS_Reports FOREIGN KEY(RE_RE_UID) 
REFERENCES dbo.T_FMS_Reports (RE_UID) 
-- ON DELETE CASCADE -- here, MS-SQL has a problem 
GO

ALTER TABLE dbo.T_FMS_Reports CHECK CONSTRAINT FK_T_FMS_Reports_T_FMS_Reports 
GO

Nhưng bạn gặp phải một vấn đề:
Khi bạn cần xóa một menupoint với tất cả các menu con của nó, bạn KHÔNG THỂ thiết lập xóa tầng, bởi vì Microsoft SQL-Server không hỗ trợ xóa tầng đệ quy (mặt khác, PostGreQuery không [nhưng chỉ khi đồ thị không theo chu kỳ], trong khi MySQL hoàn toàn không thích loại cấu trúc bảng này, vì nó không hỗ trợ các CTE đệ quy).

Vì vậy, bạn sẽ loại bỏ tính toàn vẹn / chức năng xóa với nó, khiến nó bắt buộc phải thực hiện chức năng đó trong mã của riêng bạn hoặc trong một thủ tục được lưu trữ (nếu RDBMS của bạn hỗ trợ các thủ tục được lưu trữ).

Điều này chắc chắn sẽ làm nổ tung bất kỳ loại nhập / xuất dữ liệu động hoàn toàn tự động nào, bởi vì bạn không thể đơn giản chạy một câu lệnh xóa cho tất cả các bảng theo các mối quan hệ khóa ngoài (không tự tham chiếu), cũng như bạn không thể thực hiện một lựa chọn đơn giản * và tạo một chèn cho mỗi hàng theo thứ tự tùy ý.

Ví dụ: khi bạn tạo tập lệnh INSERT bằng SSMS, thì SSMS sẽ không nhận được khóa ngoại và do đó, thực sự tạo ra các câu lệnh chèn sẽ chèn các mục nhập với các phụ thuộc, trước khi nó chèn cha mẹ của phụ thuộc, sẽ không có lỗi , bởi vì khóa ngoại được đặt đúng chỗ.

Tuy nhiên, trên các hệ thống quản lý cơ sở dữ liệu phù hợp (như PostgreSQL), với công cụ thích hợp, đây không phải là vấn đề. Chỉ cần hủy bỏ rằng chỉ vì bạn trả nhiều tiền cho RDBMS của bạn (Tôi đang nhìn bạn, Microsoft; Oracle =?) Và / hoặc vành đai công cụ của nó, điều đó không có nghĩa là nó được lập trình đúng. Và OpenSource cũng không (ví dụ như MySQL) khiến bạn miễn nhiễm với những chi tiết vụn vặt tuyệt vời như vậy.

Ma quỷ là trong các chi tiết, như người xưa nói.

Bây giờ, không phải là bạn không thể giải quyết các vấn đề như vậy, nhưng tôi thực sự không khuyến nghị điều đó, nếu hệ thống của bạn sẽ phức tạp (ví dụ: hơn 200 bảng).
Ngoài ra, trong một bối cảnh thương mại thông thường (như được miêu tả bởi Dilbert), bạn sẽ không được cho thời gian đó.

Một cách tiếp cận tốt hơn nhiều, mặc dù khó khăn hơn, sẽ là một bảng đóng cửa.
Điều đó sẽ có thêm phần thưởng mà nó cũng hoạt động trên MySQL.
Khi bạn triển khai chức năng đóng một lần, bạn sẽ có chức năng này ở những nơi khác mà hầu như không có thời gian.


3
+1 về việc đưa các bảng đóng cửa chú ý đến tôi (ít nhất là thuật ngữ, đã biết khái niệm này). Đây là một bài viết tốt về nó cho những người khác có thể quan tâm. coderwall.com/p/latte/clenses-tables-for-browsing-trees-in-sql
Nguồn nhanh nhất

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.