Siêu kiểu / Subtype
Làm thế nào về việc nhìn vào mô hình supertype / subtype? Các cột phổ biến đi trong một bảng cha. Mỗi loại riêng biệt có bảng riêng với ID của cha mẹ là PK riêng và nó chứa các cột duy nhất không phổ biến cho tất cả các kiểu con. Bạn có thể bao gồm một cột loại trong cả bảng cha và con để đảm bảo mỗi thiết bị không thể có nhiều hơn một kiểu con. Tạo một FK giữa trẻ em và cha mẹ trên (ItemID, ItemTypeID). Bạn có thể sử dụng FK cho các bảng siêu kiểu hoặc bảng phụ để duy trì tính toàn vẹn mong muốn ở nơi khác. Ví dụ: nếu ItemID của bất kỳ loại nào được cho phép, hãy tạo FK cho bảng cha. Nếu chỉ có thể tham chiếu SubItemType1, hãy tạo FK cho bảng đó. Tôi sẽ loại TypeID ra khỏi các bảng tham chiếu.
Đặt tên
Khi nói đến việc đặt tên, bạn có hai lựa chọn như tôi thấy (vì lựa chọn thứ ba chỉ là "ID" trong suy nghĩ của tôi là một kiểu chống đối mạnh mẽ). Hoặc gọi khóa phụ là ItemID giống như trong bảng cha hoặc gọi nó là tên kiểu con như DoohickeyID. Sau một số suy nghĩ và một số kinh nghiệm với điều này, tôi ủng hộ việc gọi nó là DoohickeyID. Lý do cho điều này là mặc dù có thể có sự nhầm lẫn về bảng phụ thực sự ngụy trang có chứa Vật phẩm (chứ không phải là Doohickeys), đó là một tiêu cực nhỏ so với khi bạn tạo FK cho bảng Doohickey và tên cột không trận đấu!
Đến EAV hay không EAV - Trải nghiệm của tôi với cơ sở dữ liệu EAV
Nếu EAV là những gì bạn thực sự phải làm, thì đó là những gì bạn phải làm. Nhưng nếu đó không phải là những gì bạn phải làm thì sao?
Tôi đã xây dựng một cơ sở dữ liệu EAV được sử dụng trong một doanh nghiệp. Ơn trời, bộ dữ liệu nhỏ (mặc dù có hàng tá loại vật phẩm) nên hiệu suất không tệ. Nhưng sẽ thật tệ nếu cơ sở dữ liệu có hơn vài nghìn mục trong đó! Ngoài ra, các bảng rất khó truy vấn. Kinh nghiệm này đã khiến tôi thực sự mong muốn tránh các cơ sở dữ liệu EAV trong tương lai nếu có thể.
Bây giờ, trong cơ sở dữ liệu của tôi, tôi đã tạo một thủ tục được lưu trữ để tự động xây dựng các chế độ xem PIVOTed cho mỗi và mọi kiểu con tồn tại. Tôi chỉ có thể truy vấn từ AutoDoohickey. Siêu dữ liệu của tôi về các kiểu con có cột "Tên ngắn" chứa tên an toàn đối tượng phù hợp để sử dụng trong tên xem. Tôi thậm chí đã làm cho các lượt xem cập nhật! Thật không may, bạn không thể cập nhật chúng khi tham gia, nhưng bạn CÓ THỂ chèn cho chúng một hàng đã tồn tại, sẽ được chuyển đổi thành CẬP NHẬT. Thật không may, bạn không thể chỉ cập nhật một vài cột, vì không có cách nào để chỉ ra VIEW mà cột bạn muốn cập nhật với quy trình chuyển đổi INSERT-to-UPDATE: giá trị NULL trông giống như "cập nhật cột này thành NULL" ngay cả khi bạn muốn chỉ ra "Đừng cập nhật cột này."
Mặc dù tất cả các trang trí này để làm cho cơ sở dữ liệu EAV dễ sử dụng hơn, tôi vẫn không sử dụng các chế độ xem này trong hầu hết các truy vấn thông thường vì nó là SLOW. Các điều kiện truy vấn không phải là vị ngữ được đẩy trở lại Value
bảng, do đó, nó phải xây dựng một tập kết quả trung gian của tất cả các mục thuộc loại của chế độ xem đó trước khi lọc. Ôi. Vì vậy, tôi có rất nhiều, rất nhiều truy vấn với nhiều, nhiều tham gia, mỗi lần truy cập để nhận được một giá trị khác nhau, v.v. Họ thực hiện tương đối tốt, nhưng ouch! Đây là một ví dụ. SP tạo ra thứ này (và kích hoạt cập nhật của nó) là một con quái vật khổng lồ và tôi tự hào về nó, nhưng nó không phải là thứ bạn muốn cố gắng duy trì.
CREATE VIEW [dbo].[AutoModule]
AS
--This view is automatically generated by the stored procedure AutoViewCreate
SELECT
ElementID,
ElementTypeID,
Convert(nvarchar(160), [3]) [FullName],
Convert(nvarchar(1024), [435]) [Descr],
Convert(nvarchar(255), [439]) [Comment],
Convert(bit, [438]) [MissionCritical],
Convert(int, [464]) [SupportGroup],
Convert(int, [461]) [SupportHours],
Convert(nvarchar(40), [4]) [Ver],
Convert(bit, [28744]) [UsesJava],
Convert(nvarchar(256), [28745]) [JavaVersions],
Convert(bit, [28746]) [UsesIE],
Convert(nvarchar(256), [28747]) [IEVersions],
Convert(bit, [28748]) [UsesAcrobat],
Convert(nvarchar(256), [28749]) [AcrobatVersions],
Convert(bit, [28794]) [UsesDotNet],
Convert(nvarchar(256), [28795]) [DotNetVersions],
Convert(bit, [512]) [WebApplication],
Convert(nvarchar(10), [433]) [IFAbbrev],
Convert(int, [437]) [DataID],
Convert(nvarchar(1000), [463]) [Notes],
Convert(nvarchar(512), [523]) [DataDescription],
Convert(nvarchar(256), [27991]) [SpecialNote],
Convert(bit, [28932]) [Inactive],
Convert(int, [29992]) [PatchTestedBy]
FROM (
SELECT
E.ElementID + 0 ElementID,
E.ElementTypeID,
V.AttrID,
V.Value
FROM
dbo.Element E
LEFT JOIN dbo.Value V ON E.ElementID = V.ElementID
WHERE
EXISTS (
SELECT *
FROM dbo.LayoutUsage L
WHERE
E.ElementTypeID = L.ElementTypeID
AND L.AttrLayoutID = 7
)
) X
PIVOT (
Max(Value)
FOR AttrID IN ([3], [435], [439], [438], [464], [461], [4], [28744], [28745], [28746], [28747], [28748], [28749], [28794], [28795], [512], [433], [437], [463], [523], [27991], [28932], [29992])
) P;
Đây là một loại chế độ xem được tạo tự động khác được tạo bởi một thủ tục được lưu trữ khác từ siêu dữ liệu đặc biệt để giúp tìm mối quan hệ giữa các mục có thể có nhiều đường dẫn giữa chúng (Cụ thể: Module-> Server, Module-> Cluster-> Server, Module-> DBMS- > Máy chủ, Mô-đun-> DBMS-> Cụm-> Máy chủ):
CREATE VIEW [dbo].[Link_Module_Server]
AS
-- This view is automatically generated by the stored procedure LinkViewCreate
SELECT
ModuleID = A.ElementID,
ServerID = B.ElementID
FROM
Element A
INNER JOIN Element B
ON EXISTS (
SELECT *
FROM
dbo.Element R1
WHERE
A.ElementID = R1.ElementID1
AND B.ElementID = R1.ElementID2
AND R1.ElementTypeID = 38
) OR EXISTS (
SELECT *
FROM
dbo.Element R1
INNER JOIN dbo.Element R2 ON R1.ElementID2 = R2.ElementID1
WHERE
A.ElementID = R1.ElementID1
AND R1.ElementTypeID = 40
AND B.ElementID = R2.ElementID2
AND R2.ElementTypeID = 38
) OR EXISTS (
SELECT *
FROM
dbo.Element R1
INNER JOIN dbo.Element R2 ON R1.ElementID2 = R2.ElementID1
WHERE
A.ElementID = R1.ElementID1
AND R1.ElementTypeID = 38
AND B.ElementID = R2.ElementID2
AND R2.ElementTypeID = 3122
) OR EXISTS (
SELECT *
FROM
dbo.Element R1
INNER JOIN dbo.Element R2 ON R1.ElementID2 = R2.ElementID1
INNER JOIN dbo.Element C2 ON R2.ElementID2 = C2.ElementID
INNER JOIN dbo.Element R3 ON R2.ElementID2 = R3.ElementID1
WHERE
A.ElementID = R1.ElementID1
AND R1.ElementTypeID = 40
AND C2.ElementTypeID = 3080
AND R2.ElementTypeID = 38
AND B.ElementID = R3.ElementID2
AND R3.ElementTypeID = 3122
)
WHERE
A.ElementTypeID = 9
AND B.ElementTypeID = 17
Phương pháp lai
Nếu bạn PHẢI có một số khía cạnh động của cơ sở dữ liệu EAV, bạn có thể xem xét việc tạo siêu dữ liệu như thể bạn có một cơ sở dữ liệu như vậy, nhưng thay vào đó thực sự sử dụng mẫu thiết kế siêu kiểu / kiểu con. Có, bạn sẽ phải tạo các bảng mới, thêm và xóa và sửa đổi các cột. Nhưng với quá trình tiền xử lý thích hợp (như tôi đã làm với chế độ xem Tự động của cơ sở dữ liệu EAV của tôi), bạn có thể có các đối tượng giống như bảng thực sự để làm việc. Chỉ có điều, chúng sẽ không sởn gai ốc như của tôi và trình tối ưu hóa truy vấn có thể dự đoán được đẩy xuống các bảng cơ sở (đọc: thực hiện tốt với chúng). Sẽ chỉ có một liên kết giữa bảng supertype và bảng subtype. Ứng dụng của bạn có thể được thiết lập để đọc siêu dữ liệu để khám phá những gì nó phải làm (hoặc nó có thể sử dụng các chế độ xem được tạo tự động trong một số trường hợp).
Hoặc, nếu bạn đã có một bộ các kiểu con đa cấp, chỉ cần một vài phép nối. Theo đa cấp, ý tôi là khi một số kiểu con chia sẻ các cột chung, nhưng không phải tất cả, bạn có thể có một bảng kiểu con cho những bảng mà chính nó là siêu kiểu của một vài bảng khác. Ví dụ: nếu bạn đang lưu trữ thông tin về Máy chủ, Bộ định tuyến và Máy in, một kiểu con trung gian của "Thiết bị IP" có thể có ý nghĩa.
Tôi sẽ đưa ra lời cảnh báo rằng tôi chưa tạo ra một cơ sở dữ liệu siêu trang trí / siêu mẫu lai EAV như tôi đang đề nghị ở đây để thử trong thế giới thực. Nhưng những vấn đề tôi gặp phải với EAV không hề nhỏ và việc làm một cái gì đó có lẽ là điều bắt buộc nếu cơ sở dữ liệu của bạn sẽ lớn và bạn muốn có hiệu năng tốt mà không cần một số phần cứng khổng lồ đắt tiền.
Theo tôi, thời gian tự động hóa việc sử dụng / tạo / sửa đổi các bảng phụ thực sự cuối cùng sẽ là tốt nhất. Tập trung vào tính linh hoạt được điều khiển bởi dữ liệu làm cho âm thanh EAV trở nên hấp dẫn (và tin tôi đi, tôi thích làm thế nào khi ai đó hỏi tôi một thuộc tính mới trên loại phần tử tôi có thể thêm nó trong khoảng 18 giây và họ có thể bắt đầu nhập dữ liệu ngay trên trang web ). Nhưng sự linh hoạt có thể được thực hiện theo nhiều cách! Tiền xử lý là một cách khác để làm điều đó. Đó là một phương pháp mạnh mẽ mà rất ít người sử dụng, mang lại lợi ích của việc hoàn toàn dựa trên dữ liệu nhưng hiệu suất của việc được mã hóa cứng.
(Lưu ý: Có, các chế độ xem thực sự được định dạng như vậy và các chế độ xem PIVOT thực sự có trình kích hoạt cập nhật. :) Nếu ai đó thực sự quan tâm đến các chi tiết đau đớn khủng khiếp của trình kích hoạt CẬP NHẬT dài và phức tạp, hãy cho tôi biết và tôi sẽ đăng một mẫu cho bạn.)
Và thêm một ý tưởng
Đặt tất cả dữ liệu của bạn vào một bảng. Đặt tên chung cho các cột và sau đó sử dụng lại / lạm dụng chúng cho nhiều mục đích. Tạo quan điểm về những điều này để cung cấp cho họ tên hợp lý. Thêm các cột khi cột không sử dụng loại dữ liệu phù hợp không có sẵn và cập nhật chế độ xem của bạn. Mặc dù chiều dài của tôi đang diễn ra về subtype / supertype, đây có thể là cách tốt nhất.