상속 관계 매핑 전략
상속 관계 매핑이란
객체의 상속 구조와 DB의 슈퍼-서브타입 관계(아이템-영화/책/앨범 관계)를 매핑하는 것.
객체는 상속관계가 존재하지만 대부분의 RDB는 상속 관계가 없다. 이것을 슈퍼-서브타입 관계라는 모델링 기법으로 나타내 주는 것.
- 슈퍼-서브타입 자세히
- DB모델링 - 관계 (슈퍼-서브타입)
논리 모델 → 물리 모델 구현 세가지
- @Inheritance(strategy=InheritanceType.XXX) stategy 설정
- JOINED
- SINGLE_TABLE(=default) : 단일 테이블 전략
- TABLE_PER_CLASS
- @DiscriminatorColumn(name="DTYPE")
- 부모 클래스에 선언. 하위 클래스를 구분하는 용도의 컬럼을 생성함. (DTYPE 컬럼에 영화/책/앨범 을 구분하는 정보가 들어감)
- JOINED 전략에서는 어노테이션을 선언하지 않으면 dtype 컬럼이 생성되지 않는다.
- SINGLE_TABLE 전략에서는 어노테이션을 선언하지 않아도 dtype 컬럼이 생성된다.
- @DiscriminatorValue("XXX")
- 하위 클래스에 선언. 엔티티 저장시 슈퍼타입의 구분 컬럼에 저장할 값을 지정. 따로 지정하지 않으면 클래스 이름이 기본값으로 들어감.
Inheritance
- JOINED: 각각의 테이블로 변환
가장 정규화 된 방법.
NAME, PRICE는 ITEM 테이블에만. ALBUM, MOVIE, BOOK이 각자의 데이터만 저장. 사용할 때 조인해서 사용해야 함.
하위 클래스 객체 생성시 Item, Movie 둘 다 insert 쿼리가 생성된다.
- SINGLE_TABLE: 통합 테이블로 변환
서비스 규모가 크지 않고 굳이 조인 전략으로 복잡하게 갈 필요가 없을 때, 한 테이블에 다 저장하고 DTYPE으로 구분하는 단일 테이블 전략을 사용.
조인 연산 필요 없이 insert, select 1회에 다 끝난다.
- TABLE_PER_CLASS: 서브타입 테이블로 변환하는 구현 클래스마다 테이블을 생성
슈퍼 타입의 컬럼들을 서브 타입으로 내려서 각각의 테이블을 생성한다.
주의
- @Id 생성 전략 GenerationType.AUTO를 사용하는 경우 strategy를 TABLE_PER_CLASS로 변경하고 ITEM 엔티티를 abstract 클래스로 변환한다. @DiscriminatorColumn도 필요가 없어진다.
- @Id 생성 전략 GenerationType.IDENTITY를 사용하는 경우 에러가 발생한다.
- 상위 객체 타입으로 하위 객체 참조시, 삽입은 간단하지만 조회의 경우 union all로 하위 객체 전체 테이블을 다 조회해서 찾기 때문에 비효율적이다.
정리
조인 전략
- 장점
- 테이블 정규화가 되어있고 외래키 참조 무결성 제약조건 활용 가능
- 저장공간 효율화
- 단점
- 조회시 조인을 많이 사용한다. 조회 쿼리가 복잡하다.
- 데이터 저장시 insert 쿼리가 상위, 하위 테이블 두 번 발생한다.
- 정리
- 사실 실제로는 성능 영향이 크지 않고, 저장공간이 효율적이라 장점이 더 크다.
- 기본적으로 조인이 정석이다.
단일 테이블 전략
- 장점
- 조인이 필요 없어 일반적인 조회 성능이 빠르고 쿼리가 단순하다.
- 단점
- 자식 엔티티가 매핑한 컬럼은 모두 NULL을 허용해야 한다.
- 단일 테이블에 모든 것을 저장하므로 테이블이 커진다.
- 상황에 따라 조인 전략보다 성능이 느려질 수 있다.
구현 클래스마다 테이블 생성 전략
- 장점
- 서브 타입을 명확하게 구분해서 처리할 때 효과적이다.
- NOT NULL 제약 조건을 사용할 수 있다.
- 단점
- 여러 자식 테이블을 함꼐 조회할 때 성능이 느리다. (union all)
- 자식 테이블을 통합해서 쿼리하기 어렵다.
참고