디자인 패턴-많은 부모 테이블 중 하나 두 가지 솔루션을 보았습니다. 참고 : 아래

주어진 테이블이 여러 다른 부모 테이블 중 하나에 FK 할 수있는 상황이 데이터베이스에서 자주 발생합니다. 문제에 대한 두 가지 해결책을 보았지만 개인적으로 만족 스럽지는 않습니다. 다른 패턴이 궁금하십니까? 더 좋은 방법이 있습니까?

고안된 예
내 시스템에 있다고 가정 해 봅시다 Alerts. 고객, 뉴스 및 제품과 같은 다양한 개체에 대해 경고를받을 수 있습니다. 주어진 경고는 단 하나의 항목에 대한 것일 수 있습니다. 어떤 이유로 든 고객, 기사 및 제품은 빠르게 이동하거나 현지화되어 있으므로 경고를 생성 할 때 필요한 텍스트 / 데이터를 경고로 가져올 수 없습니다. 이 설정을 통해 두 가지 솔루션을 보았습니다.

참고 : 아래 DDL은 SQL Server 용이지만 내 질문은 모든 DBMS에 적용 가능해야합니다.

해결 방법 1-다중 널 입력 가능 FKey

이 솔루션에서 일대 다 테이블에 연결되는 테이블에는 여러 개의 FK 열이 있습니다 (간단하게하기 위해 아래 DDL에는 FK 생성이 표시되지 않음). 좋은 -이 솔루션에서는 외래 키가 있다는 것이 좋습니다. FK의 Null-optinality는 정확한 데이터를 편리하고 쉽게 추가 할 수있게 해줍니다. BAD 쿼리는 관련 데이터를 가져 오기 위해 N LEFT JOINS 또는 N UNION 문이 필요하기 때문에 좋지 않습니다 . SQL Server에서 특히 LEFT JOINS는 인덱싱 된 뷰를 만드는 것을 금지합니다.

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)
)

해결 방법 2-각 상위 테이블에서 하나의 FK
이 솔루션에서 각 ‘상위’테이블에는 경고 테이블에 대한 FK가 있습니다. 부모와 관련된 경고를 쉽게 검색 할 수 있습니다. 아래쪽에는 경고에서 참조하는 사람에 대한 실제 체인이 없습니다. 또한 데이터 모델을 통해 경보가 제품, 뉴스 또는 고객과 연관되지 않은 고아 경보를 사용할 수 있습니다. 다시 한 번, 여러 개의 LEFT JOIN이 연결을 파악합니다.

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)
)

이것이 관계 데이터베이스의 유일한 삶입니까? 더 만족스러운 대체 솔루션이 있습니까?



답변

나는 두 번째 솔루션이 하나의 (개체) 대 다 (경고) 관계를 제공하지 않기 때문에 적용 할 수없는 것으로 이해합니다.

엄격한 3NF 준수로 인해 두 가지 솔루션 만 고수하고 있습니다.

더 적은 커플 링 스키마를 디자인합니다.

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

또는 무결성 관계가 필수 인 경우 다음을 설계 할 수 있습니다.

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)

어쨌든…

많은 (개체) 대 일 (경고) 관계에 대해 고려할 세 가지 유효한 솔루션과 다른 솔루션 …

이것들은 도덕이란 무엇입니까?

그것들은 미묘하게 다르며 기준에 따라 동일합니다.

  • 삽입 및 업데이트 성능
  • 쿼리 복잡성
  • 저장 공간

그래서, 당신에게 그 comfier를 선택하십시오.


답변

트리거 유지 조인 테이블을 사용했습니다. DB 리팩토링이 불가능하거나 바람직하지 않은 경우 솔루션은 최후의 수단으로 잘 작동합니다. 아이디어는 RI 문제를 처리 할 수있는 테이블이 있고 모든 DRI가 이에 반대한다는 것입니다.