티스토리 뷰
7장 다형성 연관
여러 개의 부모테이블로부터 하나의 자식테이블을 공유할 수 있다.
이에 대해 오류가 발생할 상황이 만들어진다.
#1. 자식 테이블을 여러 개의 자식 테이블을 참조하는 FK를 생성할 수 없다. 결국 아래와 같은 DDL은 성립되지 않는다.
CREATE TABLE Comment (
Comment_id number PRIMARY KEY,
Bug_id number NOT NULL,
author_id number NOT NULL,
comment_date date NOT NULL,
comment varchar2(4000) number NOT NULL
FOREIGN KEY (issue_id)
REFFERNCES Bugs(issue_id) OR FeatureRequests(issue_id)
);
@2. 여러 테이블을 조회하기 위하여 다음과 같이 잘못된 SQL을 작성할 수 있다.
이렇게 사용한 이유는 데이터베이스에서 사용되는 "테이블명"이란 메타정보를 문자열로 관리하고 있기 때문에 SQL바로 적용할 수 있다고 오해할 수 있기 때문이다.
SELECT c.*, i.summary, i.status
FROM Comments as c
JOIN c.issue_type AS I USING (isuue_id);
7.1 목표 : 여러 부모 참조
Comments테이블은 Bugs테이블의 행이나 FeatureRequests테이블의 행 중 하나와만 대응한다.
이를 ERD로 표기하면 아래와 같다. (Exclusive 관계)
7.2 안티패턴 : 이중 목적의 FK사용
이중 목적의 FK사용에 대한 해법을 일컬어 다형성 연관(Polymorphic Associations) 또는 난잡한 연관(Promiscuous Association)이라고 한다.
다형성 연관 정의
다형성 연관을 작동하게 하려면 FK컬럼인 issue_id컬럼에 들어가는 값에 대응하여 참조하는 테이블정보를 추가적으로 관리하여야 한다.
CREATE TABLE Comment ( Comment_id number PRIMARY KEY, Issue_type VARCHAR2(20), -- bugs 또는 featureRequests 입력 Issue_id number NOT NULL, Bug_id number NOT NULL, author_id number NOT NULL, comment_date date NOT NULL, comment varchar2(4000) number NOT NULL );
FK는 하나의 테이블만 참조할 수 있기 때문에 다형성 연관을 사용할 경우에는 이 연관을 메타데이터에 선언할 수 없기 때문에 FK선언을 할 수 없다.
그 결과로 다음과 같은 단점이 드러나게 된다.
- Comments테이블의 issue_id는 부모테이블의 값과 대응되도록 강제할 수 없게 된다.
- 정합성 보장도 DB레벨에서는 할 수 없게 된다.
- 그렇기 때문에 값에 테이블명인지 아닌지도 알 수 없다.
다형성 연관에서의 조회
예제에서 사용되는 Comments테이블의 issue_id값은 Bugs테이블이나 FeatureRequests테이블 중 한 쪽에만 있을 수도 있고 양쪽 모두 있을 수도 있고 양쪽 모두 없을 수도 있다.
SELECT * FROM Bugs AS b JOIN Comments AS c ON (b.issue_id = c.issue_id AND c.issue_type = 'Bugs') WHERE b.issue_id = 1234;
위와 같이 되어 있다면 Bugs테이블의 내용은 잘 동작한다.
그러나 FeatureRequests테이블의 내용은 나오지 않는다. SQL수행 시 관련된 테이블과의 관계를 다음처럼 명시해야 한다.
SELECT * FROM Comments AS c LEFT OUTER JOIN Bugs AS b ON (b.issue_id = c.issue_id AND c.issue_type = 'Bugs') LEFT OUTER JOIN FeatureRequests AS f ON (f.issue_id = c.issue_id AND c.issue_type = 'FeatureRequests') WHERE b.issue_id = 1234;
비 객체지향 예제
부모테이블에 따라 구분되어 사용되는 값이 많아진다면 점점 컬럼이 2개씩(부모가 2개라면..)로 증가하게 되고 복잡하게 될 것이다.
7.3 안티패턴 인식 방법
테이블 설계 시 아래와 같은 말이 들린다면 안티패턴인지 식별할 필요가 있다.
- 이 태깅 스키마는 데이터베이스 내의 어떤 리소스에도 태그(또는 다른 속성)을 달 수 있다.
: 무제한적인 유연성을 주장할 때 - 우리 데이터베이스 설계에서는 FK를 선언할 수 없다.
: 안 하는 것이 아니라 못한다 이다. - entity_type 컬럼의 용도가 모지?
: 각 행의 부모 테이블이 무엇인지 알려주는 컬럼
7.4 안티패턴 사용이 합당한 경우
합당한 경우가 없다. 단 특정 객체관계 프로그래밍 프레임워크를 사용하는 경우 이 안티패턴사용이 불가피한 경우가 있다. 이 경우 애플리케이션 로직을 캡슐화하여 참조정합성 유지에 도움을 줄 수 있다.
7.5 해법 : 관계단순화
다형성 연관의 단점을 피하면서 필요한 데이터 모델을 지원하기 위해서는 데이터베이스를 다시 설계하는 것이 낫다.
역참조
교차테이블 생성
자식테이블 Comments는 여러 부모테이블을 참조할 수 없으므로 Comments테이블과 각 부모테이블과의 교차 테이블을 생성하여 각 부모테이블의 FK뿐아니라 Comments테이블의 FK도 포함 시킨다.
CREATE TABLE BugsComment ( Issue_id number NOT NULL, Comment_id number NOT NULL, PRIMARY KEY (Issue_id, Comment_id) FOREIGN KEY (issue_id) REFERENCES Bugs(issue_id), FOREIGN KEY (Comment_id) REFERENCES Comments(Comment_id), ); CREATE TABLE FeaturesComment ( Issue_id number NOT NULL, Comment_id number NOT NULL, PRIMARY KEY (Issue_id, Comment_id) FOREIGN KEY (issue_id) REFERENCES FeatureRequests(issue_id), FOREIGN KEY (Comment_id) REFERENCES Comments(Comment_id) );
신호등설치
하나의 덧글이 한 번만 참조됨을 보장받아야 하는 경우 다음처럼 UNIQUE키를 설정할 수 있다.
CREATE TABLE BugsComment (
Issue_id number NOT NULL,
Comment_id number NOT NULL,
UNIQUE KEY (comment_id),
PRIMARY KEY (Issue_id, Comment_id)
FOREIGN KEY (issue_id) REFERENCES Bugs(issue_id),
FOREIGN KEY (Comment_id) REFERENCES Comments(Comment_id),
);
공통 수퍼테이블 생성
Issue와 같은 조상 테이블을 사용한다면 FK를 통해 데이터베이스 정합성을 강제할 수 있다.
문서정보
- 이 문서는 구루비에서 작성하였습니다.
- 이 문서를 다른 블로그나 홈페이지에 게재하실 경우에는 출처를 꼭 밝혀 주시면 고맙겠습니다.~^^
- 출처 : http://wiki.gurubee.net/pages/viewpage.action?pageId=15630363&
- 구루비 지식창고의 모든 문서는 크리에이티브 커먼즈의 저작자표시-비영리-동일조건변경허락(BY-NC-SA) 라이선스에 따라 자유롭게 사용할 수 있습니다