• 카테고리

    질문 & 답변
  • 세부 분야

    백엔드

  • 해결 여부

    미해결

엔티티 조회 질문

20.07.30 15:42 작성 조회수 254

0

강사님, 안녕하세요.
카테고리와 같은 제가 개발 중인 엔티티 조회탐색에 관해 질문이 있습니다.

현재, 저는 쇼핑몰처럼 카테고리와 제품으로 나누어진 구조의 엔티티를 개발하고 있습니다.
다음과 같은 데이터가 있으면,

예를들어, 대분류 'HW'를 통해서 검색하면 Product 1~5 까지의 모든 제품이 조회되어야하고,
중분류 '서버'를 통해서 검색하면 Product 1~2의 제품이 조회되어야하고,
소분류 'L3 스위치'를 통해서 검색하면 Product 3~4 제품이 조회되어야합니다.

위와 같은 구조로 데이터를 저장하기 위해, 다음과 같은 엔티티 클래스를 만들었습니다.

@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Category extends BaseEntity {

	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	Long id;

	@Column(nullable = false)
	String categoryName;

	@Builder
	public Category(String categoryName) {
		this.categoryName = categoryName;
	}

	@ManyToOne(fetch = FetchType.LAZY)
	@JoinColumn(name = "parent_id")
	@Setter
	private Category parent;

	@OneToMany(mappedBy = "parent")
	private List<Category> child = new ArrayList<>();

	public void addChildCategory(Category child) {
		this.child.add(child);
		child.setParent(this);
	}
}
=================================================================================================================
@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Product extends BaseEntity{
	
	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	private Long id;
	
	@Column(nullable = false)
	private String productName;
	
	private String specDescription;
	
	private String description;
	
	@Builder
	public Product(String productName, String specDescription, String description) {
		this.productName = productName;
		this.specDescription = specDescription;
		this.description = description;
	}
}
=================================================================================================================
@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class ProductCategory extends BaseEntity{
	
	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	Long id;
	
	@ManyToOne(fetch = FetchType.LAZY)
	@JoinColumn(name = "product_id")
	private Product product;
	
	@ManyToOne(fetch = FetchType.LAZY)
	@JoinColumn(name = "category_id")
	private Category category;

	@Builder
	public ProductCategory(Product product, Category category) {
		this.product = product;
		this.category = category;
	}
}
=================================================================================================================

이러한 엔티티구조에서 상위 카테고리를 통해 하위에 존재하는 모든 카테고리에 등록된 Product 데이터를 어떻게 가져와야할지 고민입니다.

당장 2가지 방법이 떠오르는데요, 
첫째로. Product를 저장시 최하위부터 최상위까지 모든 Category들과 Product와의 관계데이터(ProductCategory)를 생성 후 productCategoryRepostiory.findByCategoryId(categoryId)와 같은 메소드를 만들어 특정 카테고리에 등록된 모든 프로젝트를 조회하는 방법.

둘째로, Product를 저장시, 최하위 Category 하나와 Prdouct와 관계 데이터(ProductCategory)를 생성 후, 상위 카테고리를 통해 조회시, bfs, dfs와 같은 알고리즘을 통해 하위 카테고리를 순회하여서 각 카테고리마다 productCategoryRepository.findByCategoryId(categoryId)와 같은 메소드를 호출해 모든 Product를 가져오는 방법입니다.

동시에, 첫번째 방법은 불필요한 데이터가 저장되는 것 같아 맘에 걸리고, 두번째 방법은 하위 카테고리를 순회할때마다 쿼리를 날려줘야해서 성능상 이슈가 있을 것 같아 고민이 됩니다.

강사님께서는, 어떤 방법이 괜찮을지 조언을 구하고자 이렇게 질문을 드립니다. 제가 생각한 방법외에도 다른 좋은 방법이나 실무에서 쓰이는 케이스를 알려주시면 감사하겠습니다.

여담으로, 개발을 하면서 강사님의 강의가 큰 도움이 되고있습니다.
좋은 지식 공유해주셔서 정말 감사합니다.

답변 2

·

답변을 작성해보세요.

3

안녕하세요. wxxsox lee님

DB 차원에서 성능을 올리려면 어느정도 역정규화가 필요합니다.

정말 단순한게 이야기하면 만약 3depth까지만이라고 하면

depth1Code, depth2Code, depth3Code 같은 필드를 만들어서 저장을 해두면 됩니다.

그러면 쿼리를 할 때 depth1Code로 쿼리하면 depth1과 관련된 모든 하위 카테고리를 한번에 조회할 수 있습니다.

여기서 조금 더 나가면 필드를 각각 만들지 않고, 코드이름을 잘 정해서 하나로 저장할 수 도 있습니다.

예를 들어서 카테고리 코드를 다음과 같이 사용하는 것이지요.

A01B001C0001

A01(최상위), B001(2단계) C0001 (3단계)

이렇게 하고 DB에 인덱스를 잡고 like 검색을 A01% 처럼 하면 인덱스도 태울 수 있습니다.

1. A01B001C0001

2. A01B001C0002

3. A02B002C0019

이렇게 되어 있다면 A01만 조회하고 싶으면 like 'A01%'로 조회하면 1,2를 조회할 수 있지요.

추가로 카테고리에 현재 depth가 얼마인지 정보도 넣어두시면 운영하기 편리합니다.

DB 설계에 대한 부분은 카테고리 최적화 설계로 검색해보시면 정말 많은 정보를 얻으실 수 있을꺼에요^^

추가로 저는 카테고리를 운영할 때 가급적이면 애플리케이션 로딩 시점에 메모리에 다 올려버립니다. (캐시 사용)

카테고리는 사실 거의 잘 변경되지 않고, 또 데이터도 많지 않거든요. 그래서 캐시를 잘 사용하면 다 메모리에서 처리해버릴 수 있기 때문에 복잡한 조회도 아주빠르게 처리할 수 있습니다. (그리고 캐시 갱신 주기를 5분 정도로 가지고 가는 것이지요.)

특히 적어주신 두번째 방법을 선택하면 사실 메모리에 캐시하면 큰 효과를 볼 수 있습니다^^

도움이 되셨길 바래요.

1

wxxsox lee님의 프로필

wxxsox lee

질문자

2020.07.31

늦은시간임에도 상세한 설명 감사합니다ㅎㅎ
업무에 많은 도움이 될 것 같습니다!