Tasarım deseni - birçok üst tablolardan biri


13

Belirli bir tablonun birkaç farklı üst tablolardan birine FK yapabileceği oldukça sık veritabanında bir durumla karşılaşıyorum. Sorun için iki çözüm gördüm, ama ikisi de kişisel olarak tatmin edici değil. Orada başka hangi desenleri gördüğünüzü merak ediyorum. Bunu yapmanın daha iyi bir yolu var mı?

Düzenlenmiş Bir Örnek
Diyelim ki sistemim var Alerts. Çeşitli nesneler için uyarılar alınabilir - Müşteriler, Haberler ve Ürünler. Belirli bir uyarı yalnızca bir öğe için olabilir. Hangi nedenle olursa olsun, Müşteriler, Makaleler ve Ürünler hızlı hareket eder (veya yerelleştirilir), bu nedenle gerekli metin / veriler bir Uyarı oluşturulduktan sonra Uyarılara alınamaz. Bu kurulum göz önüne alındığında iki çözüm gördüm.

Not: Aşağıda DDL SQL Server içindir, ancak sorum herhangi bir DBMS için geçerli olmalıdır.

Çözüm 1 - Birden Çok Sıfırlanabilir FKey

Bu çözümde, çok sayıda tablodan birine bağlanan tabloda birden fazla FK Sütunu vardır (kısaca, aşağıdaki DDL, FK oluşturma işlemini göstermez). İYİ - Bu çözümde yabancı anahtarları olması güzel. FK'lerin boş olması, doğru veri eklemek için bu kullanışlı ve nispeten kolay hale getirir. KÖTÜ Sorgulama harika değildir, çünkü ilişkili verileri almak için N LEFT JOINS veya N UNION deyimi gerektirir . SQL Server'da, özellikle LEFT JOINS dizinlenmiş bir görünüm oluşturmayı engeller.

CREATE TABLE Product (
    ProductID    int identity(1,1) not null,
    CreateUTC    datetime2(7) not null,
     Name        varchar(100) not null
    CONSTRAINT   PK_Product Primary Key CLUSTERED (ProductID)
)
CREATE TABLE Customer (
    CustomerID  int identity(1,1) not null,
    CreateUTC   datetime2(7) not null,
     Name       varchar(100) not null
    CONSTRAINT  PK_Customer Primary Key CLUSTERED (CustomerID)
)
CREATE TABLE News (
    NewsID      int identity(1,1) not null,
    CreateUTC   datetime2(7) not null,
    Name        varchar(100) not null
    CONSTRAINT  PK_News Primary Key CLUSTERED (NewsID)
)

CREATE TABLE Alert (
    AlertID     int identity(1,1) not null,
    CreateUTC   datetime2(7) not null,
    ProductID   int null,
    NewsID      int null,
    CustomerID  int null,
    CONSTRAINT  PK_Alert Primary Key CLUSTERED (AlertID)
)

ALTER TABLE Alert WITH CHECK ADD CONSTRAINT CK_OnlyOneFKAllowed 
CHECK ( 
    (ProductID is not null AND NewsID is     null and CustomerID is     null) OR 
    (ProductID is     null AND NewsID is not null and CustomerID is     null) OR 
    (ProductID is     null AND NewsID is     null and CustomerID is not null) 
)

Çözüm 2 - Her Ebeveyn Tablosunda
bir FK Bu çözümde her 'üst' tablonun Uyarı tablosunda bir FK vardır. Bir ebeveynle ilişkili uyarıları almayı kolaylaştırır. Aşağı tarafta, Alert'ten kimin referans aldığı için gerçek bir zincir yoktur. Ayrıca, veri modeli, bir uyarının bir Ürün, Haberler veya Müşteri ile ilişkili olmadığı, artık Uyarılara izin verir. Yine, ilişkiyi anlamak için birden fazla SOL BİRLEŞME.

CREATE TABLE Product (
    ProductID    int identity(1,1) not null,
    CreateUTC    datetime2(7) not null,
     Name        varchar(100) not null
    AlertID     int null,
    CONSTRAINT   PK_Product Primary Key CLUSTERED (ProductID)
)
CREATE TABLE Customer (
    CustomerID  int identity(1,1) not null,
    CreateUTC   datetime2(7) not null,
     Name       varchar(100) not null
    AlertID     int null,
    CONSTRAINT  PK_Customer Primary Key CLUSTERED (CustomerID)
)
CREATE TABLE News (
    NewsID      int identity(1,1) not null,
    CreateUTC   datetime2(7) not null,
    Name        varchar(100) not null
    AlertID     int null,
    CONSTRAINT  PK_News Primary Key CLUSTERED (NewsID)
)

CREATE TABLE Alert (
    AlertID     int identity(1,1) not null,
    CreateUTC   datetime2(7) not null,
    CONSTRAINT  PK_Alert Primary Key CLUSTERED (AlertID)
)

Bu bir ilişki veri tabanındaki hayat mı? Daha tatmin edici bulduğunuz alternatif çözümler var mı?


1
Şu sütunlarla bir üst tablo oluşturabilir, Uyarılabilir: Kimlik, CreateDate, Ad, Tür. Üç çocuk masanızın FK'sine sahip olabilirsiniz ve ALert'iniz sadece bir masaya FK, Uyarılabilir olacaktır.
AK

Bazı durumlarda iyi bir noktaya dikkat çekersiniz - etkili bir çözüm # 3. Veriler hızlı hareket ettiğinde veya yerelleştirildiğinde, çalışmaz. Örneğin, Ürün, Müşteri ve Haberler'in her birinin Ad'ı çeşitli dillerde desteklemek için karşılık gelen bir "Lang" tablosuna sahip olduğunu varsayalım. Eğer kullanıcıların 'anadilinde' isim 'vermek zorunda kalırsam onu ​​saklayamıyorum Alertable. Bu bir anlam ifade ediyor mu?
EBarr

1
@EBarr: "Kullanıcıların ana dilinde 'name' iletmem gerekiyorsa onu Alertable'da saklayamıyorum. Bu bir anlam ifade ediyor mu?" Hayır. Mevcut şemanızla, kullanıcıların ana dilinde 'ad' iletmeniz gerekiyorsa, bunu Ürün, Müşteri veya Haberler tablosunda saklayabilir misiniz?
ypercubeᵀᴹ

@ypercube Bu tabloların her birinin ilişkili bir dil tablosu olduğunu ekledim. "Ad" metninin istek başına değişebileceği ve bu nedenle Alertable'da saklanamayacağı bir senaryo oluşturmaya çalışıyordum.
EBarr

Kabul edilmiş bir adı olmadığı sürece, tüm uyarıları ve ilişkili ebeveynlerini görmek için yapacağınız sorgu için "ahtapot birleştirme" terimini öneriyorum. :)
Nathan Long

Yanıtlar:


4

İkinci çözümü bir (nesne) -çok (uyarı) ilişkisi sunmadığından uygulanamaz olarak anlıyorum.

Katı 3NF uyumluluğu nedeniyle sadece iki çözüme bağlı kaldınız.

Daha az bir bağlantı şeması tasarlıyorum:

CREATE TABLE Product  (ProductID  int identity(1,1) not null, ...)
CREATE TABLE Customer (CustomerID int identity(1,1) not null, ...)
CREATE TABLE News     (NewsID     int identity(1,1) not null, ...)

CREATE TABLE Alert (
  -- See (1)
  -- AlertID     int identity(1,1) not null,

  AlertClass char(1) not null, -- 'P' - Product, 'C' - Customer, 'N' - News
  ForeignKey int not null,
  CreateUTC  datetime2(7) not null,

  -- See (2)
  CONSTRAINT  PK_Alert Primary Key CLUSTERED (AlertClass, ForeignKey)
)

-- (1) you don't need to specify an ID 'just because'. If it's meaningless, just don't.
-- (2) I do believe in composite keys

Veya, bütünlük ilişkisi zorunlu olacaksa, şunu tasarlayabilirim:

CREATE TABLE Product  (ProductID  int identity(1,1) not null, ...)
CREATE TABLE Customer (CustomerID int identity(1,1) not null, ...)
CREATE TABLE News     (NewsID     int identity(1,1) not null, ...)

CREATE TABLE Alert (
  AlertID     int identity(1,1) not null,
  AlertClass char(1) not null, /* 'P' - Product, 'C' - Customer, 'N' - News */
  CreateUTC  datetime2(7) not null,
  CONSTRAINT  PK_Alert Primary Key CLUSTERED (AlertID)
)

CREATE TABLE AlertProduct  (AlertID..., ProductID...,  CONSTRAINT FK_AlertProduct_X_Product(ProductID)    REFERENCES Product)
CREATE TABLE AlertCustomer (AlertID..., CustomerID..., CONSTRAINT FK_AlertCustomer_X_Customer(CustomerID) REFERENCES Customer)
CREATE TABLE AlertNews     (AlertID..., NewsID...,     CONSTRAINT FK_AlertNews_X_News(NewsID)             REFERENCES News)

Neyse ...

Üç geçerli çözüm artı birçok (nesneler) bire bir (uyarı) ilişki için dikkate alınacak başka bir çözüm ...

Bunlar sundu, ahlaki nedir?

İnce bir şekilde farklıdırlar ve kriterler üzerinde aynıdırlar:

  • ekleme ve güncelleme performans
  • sorgulamadaki karmaşıklık
  • depolama alanı

Yani, bu comfier'i sana seç


1
Giriş için teşekkürler; Yorumlarınızın çoğuna katılıyorum. Muhtemelen bir ilişki olduğu için gerekli ilişkiyi (gözünüzdeki çözüm 2 hariç) tanımladım. fn1 - anlaşıldı, ben sadece masaya sorunu odaklanmak için çok basitleştiriyordu. fn2 - kompozit anahtarlar ve geri dönüyorum! Daha az kuplaj şemasını basitleştiriyorum, ancak kişisel olarak mümkün olan her yerde DRI ile tasarım yapmaya çalışıyorum.
EBarr

Bunu gözden geçirdiğimde, çözümümün doğruluğundan şüphe etmeye başladım ... neyse, iki kez oy verildi, teşekkür ederim. Her ne kadar tasarımımın geçerli olduğuna ancak verilen probleme uygun olmadığına inansam da, 'n' sendikaları / birleşimleri ele alınmadığından ...
Marcus Vinicius Pompeu

DRI kısaltması beni yakaladı. Hepiniz için, genel olarak ... (bateri rulosu) ... DDL YABANCI ANAHTAR ifadeleri olarak uygulanan referans veri bütünlüğünün arkasındaki teknik olan Bildirici Referans Bütünlüğü anlamına gelir. En.wikipedia.org/wiki/Declarative_Referential_Integrity ve msdn.microsoft.com/en-us/library/… hakkında
Marcus Vinicius Pompeu

1

Tetikle tutulan birleştirme tabloları kullandım. db'nin yeniden düzenlenmesi mümkün veya istenmiyorsa çözüm son çare olarak iyi çalışır. Fikir, sadece UR sorunlarını ele almak için orada bir tablonuz var ve tüm DRI buna karşı çıkıyor.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.