Süpertip / Alt tür
Supertype / subtype modeline bakmaya ne dersiniz? Ortak sütunlar bir üst tabloya gider. Her farklı türün, kendi PK'si olarak üst öğenin kimliğiyle kendi tablosu vardır ve tüm alt türlerde ortak olmayan benzersiz sütunlar içerir. Her bir aygıtın birden fazla alt tür olmamasını sağlamak için hem üst hem de alt tablolara bir tür sütunu ekleyebilirsiniz. (ItemID, ItemTypeID) üzerinde çocuklar ve ebeveyn arasında bir FK yapın. FK'leri başka bir yerde istenen bütünlüğü korumak için süper tip veya alt tip tablolar için kullanabilirsiniz. Örneğin, herhangi bir türdeki ItemID'ye izin veriliyorsa, FK'yi üst tabloya oluşturun. Yalnızca SubItemType1'e başvurulabilirse, FK'yi bu tabloya oluşturun. TypeID referans tabloları dışında kalacaktı.
Adlandırma
Adlandırma söz konusu olduğunda, gördüğüm gibi iki seçeneğiniz var (çünkü sadece "ID" nin üçüncü seçimi aklımda güçlü bir anti-desen olduğu için). Üst tablodaki gibi ItemID alt tür anahtarını veya DoohickeyID gibi alt tür adını çağırın. Biraz düşünce ve bu deneyimden sonra, ona DoohickeyID demeyi savunuyorum. Bunun nedeni, alt tür tablo hakkında gerçekten Öğeleri (Doohickeys yerine) gizleyen bir karışıklık olsa da, bu Doohickey tablosuna bir FK oluşturduğunuzda ve sütun adlarının eşleşme!
EAV için veya değil EAV için - Bir EAV veritabanı ile deneyimim
EAV gerçekten yapmanız gereken şeyse, yapmanız gereken budur. Ama ya yapmanız gereken şey olmasaydı?
Bir işte kullanımda olan bir EAV veritabanı oluşturdum. Tanrıya şükür, veri kümesi küçüktür (düzinelerce öğe türü olmasına rağmen) performans kötü değildir. Ancak, veritabanında birkaç binden fazla öğe olması kötü olurdu! Ayrıca, tabloları sorgulamak çok zor. Bu deneyim beni gelecekte mümkünse EAV veritabanlarından uzak durma arzusuna yöneltti.
Şimdi, veritabanımda var olan her alt tip için otomatik olarak PIVOTed görünümleri oluşturan bir saklı yordam oluşturdum. Ben sadece AutoDoohickey sorgulayabilirsiniz. Alt türlerle ilgili meta verilerim, görünüm adlarında kullanılmaya uygun, nesne için güvenli bir ad içeren bir "KısaAd" sütununa sahip. Hatta görünümlerin güncellenebilir hale getirdim! Ne yazık ki, bunları bir birleştirmede güncelleyemezsiniz, ancak onlara mevcut bir satırı ekleyebilirsiniz; bu satır, bir GÜNCELLEME'ye dönüştürülür. Ne yazık ki, yalnızca birkaç sütunu güncelleyemezsiniz, çünkü VIEW'a INSERT-UPDATE dönüştürme işlemi ile hangi sütunları güncellemek istediğinizi belirtmenin bir yolu yoktur: NULL değeri "bu sütunu NULL olarak güncelle" gibi görünüyor "Bu sütunu hiç güncelleme" seçeneğini belirtmek istediniz.
EAV veritabanının kullanımını kolaylaştırmak için tüm bu dekorasyona rağmen, YAVAŞ olduğu için hala bu görünümleri çoğu normal sorgulamada kullanmıyorum. Sorgu koşulları, Value
tabloya kadar geriye doğru itilmiş değildir , bu nedenle filtrelemeden önce bu görünüm türündeki tüm öğelerin ara sonuç kümesini oluşturması gerekir. Ahh. Bu yüzden, her biri farklı bir değer elde etmek için dışarı çıkacak çok, çok birleştirmelerle birçok sorgularım var. Onlar nispeten iyi performans, ama ah! İşte bir örnek. Bunu yaratan SP (ve güncelleme tetikleyicisi) dev bir canavar ve bundan gurur duyuyorum, ancak korumak istediğiniz herhangi bir şey değil.
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;
Aralarında birden çok yolu olabilen öğeler arasındaki ilişkileri bulmaya yardımcı olmak için özel meta verilerden başka bir saklı yordam tarafından oluşturulan başka bir otomatik olarak oluşturulan görünüm türü (Özellikle: Modül-> Sunucu, Modül-> Küme-> Sunucu, Modül-> DBMS- > Server, Module-> DBMS-> Cluster-> Server) ile ilişkili olan kısmını dışarı aktarmak suretiyle yedek oluşturmanız gerekir:
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
Hibrit Yaklaşım
Bir EAV veritabanının dinamik özelliklerinden bazılarına sahip olmanız GEREKİRse, meta verileri böyle bir veritabanınız varmış gibi oluşturmayı düşünebilirsiniz, bunun yerine aslında supertype / subtype tasarım modelini kullanabilirsiniz. Evet, yeni tablolar oluşturmanız ve sütun eklemeniz ve kaldırmanız ve değiştirmeniz gerekir. Ancak uygun ön işleme ile (EAV veritabanımın Otomatik görünümlerinde yaptığım gibi) çalışmak için gerçek tablo benzeri nesneler olabilir. Sadece, benimki kadar gnarly olmazlardı ve sorgu optimize edici temel tablolara aşağı itmeyi tahmin edebilir (okuma: onlarla iyi performans gösterebilir). Üst tür tablo ile alt tür tablo arasında yalnızca bir birleştirme olur. Uygulamanız, ne yapması gerektiğini keşfetmek için meta verileri okuyacak şekilde ayarlanmış olabilir (veya bazı durumlarda otomatik olarak oluşturulan görünümleri kullanabilir).
Veya çok düzeyli bir alt tür kümeniz varsa, yalnızca birkaç birleşim vardır. Çok düzeyli derken, bazı alt türler ortak sütunları paylaştığında, ancak hepsini paylaşmadığında, diğer birkaç tablonun bir süper tipi olanlar için bir alt tür tablonuz olabilir. Örneğin, Sunucular, Yönlendiriciler ve Yazıcılar hakkında bilgi saklıyorsanız, "IP Aygıtı" ara alt türü anlamlı olabilir.
Henüz gerçek dünyada denemek için önerdiğim gibi henüz böyle bir hibrit süper tip / alt tip EAV-metatable dekore edilmiş veritabanı yapmadığım konusunda uyarı vereceğim. Ama EAV ile yaşadığım problemler küçük değil ve eğer veritabanınız büyük olacak ve çılgın pahalı dev bir donanım olmadan iyi bir performans istiyorsanız, bir şey yapmak muhtemelen mutlak bir zorunluluktur .
Kanımca, gerçek alt tip tabloların kullanımını / oluşturulmasını / değiştirilmesini otomatikleştirmek için harcanan zaman en iyisi olacaktır. Veri tarafından tahrik esneklik odaklanarak çekici (ve inanın bana bu yüzden EAV ses yapar aşk birisi bir eleman türüne yeni bir özellik için beni sorduğunda ben 18 hakkında saniyeler içinde ekleyebilirsiniz ve hemen web sitesinde veri girme başlayabilirsiniz nasıl ). Ancak esneklik birden fazla şekilde gerçekleştirilebilir! Ön işleme bunu yapmanın başka bir yoludur. Bu kadar güçlü bir yöntemdir ki, tamamen veriye dayalı olmanın avantajlarını ancak sabit kodlu olmanın performansını sağlar.
(Not: Evet, bu görünümler gerçekten bu şekilde biçimlendirilmiştir ve PIVOT olanlar gerçekten güncelleme tetikleyicilerine sahiptir. :) Birisi gerçekten uzun ve karmaşık GÜNCELLEME tetikleyicisinin korkunç acı verici ayrıntılarıyla ilgileniyorsa, bana bildirin ve ben gönderirim sizin için bir örnek.)
Ve Bir Fikir Daha
Tüm verilerinizi tek bir tabloya yerleştirin. Sütunlara genel adlar verin ve birden çok amaç için bunları yeniden kullanın / kötüye kullanın. Onlara mantıklı isimler vermek için bunlara bakışlar oluşturun Uygun veri türü kullanılmayan bir sütun olmadığında sütun ekleyin ve görünümlerinizi güncelleyin. Uzunluğum alt tip / süper tip hakkında olmasına rağmen, bu en iyi yol olabilir.