아보카도 프로젝트를 진행하면서, 데이터베이스 설계 시에 고민했던 문제가 있었습니다.
당시 일부 요구사항 간단 요약
“회원
은 병원
에 진료를 예약
할 수 있다.”
“회원
은 병원
을 찜
할 수 있다.”
“회원
은 병원
에 대한 리뷰
를 작성할 수 있다.”
작성된 ERD 초안
이에 따른 엔티티 설계
회원
→ 병원 예약 리스트, 찜한 병원 리스트, 작성한 리뷰 리스트가 존재
리뷰
→ 작성한 회원, 타겟 병원이 존재
병원
→ 예약 리스트, 찜 리스트, 리뷰 리스트가 존재
위 경우, 계속해서 순환 참조가 일어날 수 있다.
또한 병원 리뷰 플랫폼인 만큼, 리뷰 데이터가 늘어날 경우 함께 조인되는 쿼리의 개수들이 많아질 수 있다.
이때, 순환 참조를 없애는 방법을 떠올릴 순 있지만 다른 방법도 있다! → 반정규화
⇒ 따라서 기존 엔티티에 있던 참조를 없애고, 직접 target_hospital 컬럼을 추가하여 관리하기
@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Review extends BaseEntity {
@Id @GeneratedValue
@Column(name = "review_id")
private Long id;
...
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "hospital_id")
private Hospital hospital;
...
}
@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Review extends BaseEntity {
@Id @GeneratedValue
@Column(name = "review_id")
private Long id;
...
@Column(name = "target_hospital", nullable = false)
private String targetHospital;
...
}
그렇다면 조회 방법에는 차이가 없을까?
: 아보카도 병원
의 리뷰를 검색하고 싶을 때
HospitalRepository
에서 findByName()
으로 “아보카도 병원” 검색hospital.getReviewList().getReview()
로 순회하며 별점 계산 (이때 지연 로딩이 발생)N+1
문제가 발생하기 쉬움!ReviewRepository
에서 findByName()
으로 “아보카도 병원” 검색reviewList.getReview()
로 바로 별점 필드로 접근!최종 ERD
멘트 탈락입니다. "그래서, 비정규화가 뭔데?"로 변경하세요.