T_era
상속매핑 전략과 선택 가이드 본문
1. JOINED 전략
JOINED 전략은 부모 엔티티와 자식 엔티티를 각각 별도의 테이블로 매핑하고, 두 테이블을 조인하여 엔티티를 조회하는 방식이다.
구현 예시
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn(name = "DTYPE")
public abstract class Item {
@Id
@GeneratedValue
private Long id;
private String name;
private int price;
}
@Entity
@DiscriminatorValue("A")
public class Album extends Item {
private String artist;
private String etc;
}
@Entity
@DiscriminatorValue("M")
public class Movie extends Item {
private String director;
private String actor;
}
장점
- 정규화된 테이블 구조: 데이터 중복이 없어 저장 공간이 효율적이다.
- 외래 키 참조 무결성: 부모 테이블의 ID를 참조하여 데이터 일관성을 유지한다.
- 데이터 일관성: 각 테이블이 자신의 데이터만 관리하므로 일관성이 높다.
단점
- 조회 시 조인 발생: 엔티티 조회 시 여러 테이블을 조인해야 하므로 성능 저하 가능성이 있다.
- 복잡한 쿼리: 여러 테이블 조인으로 인해 쿼리가 복잡해진다.
- 저장 시 여러 테이블에 INSERT: 데이터를 저장할 때 여러 테이블에 INSERT 작업을 수행한다.
2. SINGLE_TABLE 전략
SINGLE_TABLE 전략은 부모 엔티티와 모든 자식 엔티티를 하나의 테이블에 매핑하는 방식이다. DTYPE과 같은 구분 컬럼을 사용하여 어떤 자식 엔티티인지 구분한다.
구현 예시
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "DTYPE")
public abstract class Item {
@Id
@GeneratedValue
private Long id;
private String name;
private int price;
}
@Entity
@DiscriminatorValue("A")
public class Album extends Item {
private String artist;
private String etc;
}
@Entity
@DiscriminatorValue("M")
public class Movie extends Item {
private String director;
private String actor;
}
장점
- 조회 성능이 좋음: 조인 없이 단일 테이블에서 데이터를 조회하므로 성능이 뛰어나다.
- 단순한 쿼리: 복잡한 조인이 필요 없어 쿼리가 단순하다.
- 저장 시 단일 INSERT: 데이터를 저장할 때 하나의 테이블에만 INSERT 작업을 수행한다.
단점
- 컬럼 수 증가: 모든 자식 엔티티의 컬럼이 하나의 테이블에 존재하여 컬럼 수가 많아진다.
- NULL 값이 많음: 특정 자식 엔티티에서 사용하지 않는 컬럼에는 NULL 값이 저장된다.
- 테이블 크기 증가: 모든 데이터가 하나의 테이블에 저장되므로 테이블 크기가 커진다.
3. TABLE_PER_CLASS 전략
TABLE_PER_CLASS 전략은 각 자식 엔티티를 별도의 테이블로 매핑하고, 부모 엔티티의 필드까지 각 자식 테이블에 포함하는 방식이다. 부모 엔티티 자체는 테이블로 생성되지 않는다.
구현 예시
@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class Item {
@Id
@GeneratedValue
private Long id;
private String name;
private int price;
}
@Entity
public class Album extends Item {
private String artist;
private String etc;
}
@Entity
public class Movie extends Item {
private String director;
private String actor;
}
장점
- 자식 엔티티별 독립적인 테이블: 각 테이블이 자신의 데이터만 포함하여 명확성을 높인다.
- 조회 시 단일 테이블 접근: 특정 자식 엔티티 조회 시 조인이 불필요하여 빠르다.
단점
- 부모 엔티티 조회 시 UNION: 부모 엔티티 타입으로 조회할 경우 모든 자식 테이블을 UNION으로 조회해야 하므로 성능이 저하될 수 있다.
- 외래 키 참조 어려움: 부모 엔티티의 ID를 참조하기 어려워 외래 키 관계 설정이 복잡해진다.
- 데이터 중복: 부모 엔티티의 공통 컬럼이 각 자식 테이블에 중복 저장된다.
4. 전략 선택 가이드
각 전략의 특성을 고려하여 프로젝트의 요구사항에 맞는 전략을 선택해야 한다.
- JOINED 전략 선택 시: 정규화가 중요하고 조회 성능이 덜 중요한 경우에 적합하다.
// 정규화가 중요하고 조회 성능이 덜 중요한 경우 @Entity @Inheritance(strategy = InheritanceType.JOINED) public abstract class Payment { @Id @GeneratedValue private Long id; private int amount; } @Entity public class CardPayment extends Payment { private String cardNumber; } - SINGLE_TABLE 전략 선택 시: 조회 성능이 중요하고 자식 엔티티의 종류가 적은 경우에 적합하다.
// 조회 성능이 중요하고 자식 엔티티가 적은 경우 @Entity @Inheritance(strategy = InheritanceType.SINGLE_TABLE) public abstract class Content { @Id @GeneratedValue private Long id; private String title; } @Entity public class Article extends Content { private String content; } - TABLE_PER_CLASS 전략 선택 시: 자식 엔티티별로 독립적인 테이블이 필요하고 부모 엔티티 조회가 적은 경우에 적합하다.
// 자식 엔티티별로 독립적인 테이블이 필요한 경우 @Entity @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) public abstract class Document { @Id @GeneratedValue private Long id; private String name; } @Entity public class PDFDocument extends Document { private String pdfContent; }
5. 성능 비교
각 전략의 성능은 다음과 같이 비교된다.
- 조회 성능: SINGLE_TABLE > TABLE_PER_CLASS > JOINED
- SINGLE_TABLE: 단일 테이블 조회로 가장 빠르다.
- TABLE_PER_CLASS: 특정 자식 엔티티 조회 시 빠르지만, 부모 엔티티 조회 시 UNION 발생으로 성능 저하가 있다.
- JOINED: 항상 조인이 발생하여 조회 성능이 가장 낮다.
- 저장 성능: SINGLE_TABLE > TABLE_PER_CLASS > JOINED
- SINGLE_TABLE: 단일 INSERT로 가장 빠르다.
- TABLE_PER_CLASS: 단일 INSERT로 효율적이다.
- JOINED: 여러 테이블에 INSERT가 발생하여 성능이 저하된다.
- 공간 효율성: JOINED > TABLE_PER_CLASS > SINGLE_TABLE
- JOINED: 정규화된 구조로 데이터 중복이 없어 가장 효율적이다.
- TABLE_PER_CLASS: 데이터 중복이 발생한다.
- SINGLE_TABLE: NULL 값이 많아 비효율적일 수 있다.
6. 결론
JPA 상속 매핑 전략은 각기 다른 장단점을 가지고 있으므로, 프로젝트의 정규화 요구사항, 조회 및 저장 성능, 데이터 중복 허용 여부 등을 고려하여 최적의 전략을 선택해야 한다.
'Programing > Spring' 카테고리의 다른 글
| Bean Scope의 특징과 사용처 (0) | 2025.06.11 |
|---|---|
| 트랜잭션 전파는 상황마다 어떤 속성을 써야할까? (0) | 2025.06.10 |
| 테스트 코드 mock()과 ReflectionTestUtils (0) | 2025.06.09 |
| 테스트 코드 어노테이션 및 메서드 정리 (0) | 2025.06.09 |
| API 로깅 Interceptor VS AOP (1) | 2025.06.05 |