디자인 패턴-많은 부모 테이블 중 하나


13

주어진 테이블이 여러 다른 부모 테이블 중 하나에 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)
)

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


1
ID, CreateDate, Name, Type 열을 사용하여 Alertable이라는 하나의 부모 테이블을 만들 수 있습니다. 세 개의 자식 테이블 FK를 가질 수 있고 ALert는 경고 가능한 하나의 테이블에만 FK를 갖습니다.
AK

어떤 경우에는 효과적인 해결책 # 3을 지적합니다. 그러나 데이터가 빠르게 이동하거나 현지화 될 때마다 작동하지 않습니다. 예를 들어, 제품, 고객 및 뉴스에는 각각 여러 언어로 이름을 지원하는 해당 "Lang"테이블이 있습니다. 사용자 모국어로 '이름'을 제공해야하는 경우에 저장할 수 없습니다 Alertable. 말이 되나요?
EBarr

1
@EBarr : "사용자 이름으로 '이름'을 전달해야하는 경우 Alertable에 저장할 수 없습니다. 어떤 의미가 있습니까?" 아닙니다. 현재 스키마를 사용하여 사용자 이름으로 '이름'을 제공해야하는 경우 제품, 고객 또는 뉴스 테이블에 저장할 수 있습니까?
ypercubeᵀᴹ

@ypercube 나는 각 테이블에 관련 언어 테이블이 있다고 덧붙였다. 요청에 따라 "이름"텍스트가 달라질 수 있으므로 Alertable에 저장할 수없는 시나리오를 만들려고했습니다.
EBarr

이미 허용 된 이름이 없으면 모든 경보와 관련 상위 항목을보기 위해 수행 할 쿼리에 대해 "문어 조인"이라는 용어를 제안합니다. :)
Nathan Long

답변:


4

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

엄격한 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를 선택하십시오.


1
입력 해 주셔서 감사합니다. 귀하의 의견 대부분에 동의합니다. 필자는 아마도 예를 들어 필요한 관계 (눈에 솔루션 2 제외)를 교묘하게 설명했습니다. fn1- 이해 했으므로 문제에 집중하기 위해 테이블을 단순화했습니다. fn2- 복합 키와 나는 되돌아갑니다! 더 적은 커플 링 스키마로 단순성을 이해하지만 가능한 한 개인적으로 DRI를 사용하여 디자인하려고합니다.
EBarr

이것을 검토하면서 솔루션의 정확성을 의심하기 시작했습니다. 어쨌든 두 번 투표되었습니다. 감사합니다. 내 디자인은 유효하지만 주어진 문제에 적합하지 않다고 생각하지만 'n'노조 / 조인은 다루지 않기 때문에 ...
Marcus Vinicius Pompeu

DRI 약어가 나를 얻었다. 여러분 모두에게 이것은 선언적 참조 무결성 (Declarative Referential Integrity)의 약자이며, 일반적으로 ... (드럼 롤) ... DDL FOREIGN KEY 문으로 구현되는 참조 데이터 무결성의 기술입니다. 더에 en.wikipedia.org/wiki/Declarative_Referential_Integritymsdn.microsoft.com/en-us/library/...
마커스 비니 시우스 Pompeu

1

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

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.