• 카테고리

    질문 & 답변
  • 세부 분야

    백엔드

  • 해결 여부

    미해결

one-to-may 의 관계에서 side effet 로 oom 의 발생가능성

21.02.18 07:24 작성 조회수 153

0

안녕하세요 김영한 개발자님

수업을 듣던중 one-to-may 의 관계에서 side effet 로 oom 의 발생가능성에 대해 고민을 하게되어 질문드립니다.

테이블이 category - product - display_info 순으로  one-to-may 관계를 맺고있을 때, 만약
category 가 10개, product 테이블의 데이터의 갯수가 10만개, display_info 의 테이블의 데이터가 100 만개일때,

각각의 category 가 가지고있는 product 의 display_info 의 갯수를 확인하고 싶은 need 가 있으면,
아래와 같이 entity 의 메서드를 통해 받아올수 있다는것을 이해를 했습니다.

List<Category> categories = categoryRepository.findAll();
List<CategoryResult> categoryResults = categories
.stream()
.map(category -> {
//데이터 커지면 통계쿼리 처리가 좋을수도 있음.
List<Product> products = category.getProducts();

int count = products
.stream()
.map(product -> product.getDisplayInfos().size())
.reduce(0, Integer::sum);

return new CategoryResult(category.getId(), category.getName(), count);
})
.collect(Collectors.toList());
return categoryResults;


그런데 걱정이 되는것은 실제 데이터가 많으면 많아질수록 batch size 를 설정한다 하여도 가져올수 있는 양은 한정적이고
결국 categorise 의 products 에 쌓인 데이터들로 인해 oom 이 발생할것 같은데 어떻게 처리를 하면 되나요??
( 보통의 webpage 를 생각해보면 이렇게 많은 데이터를 가져올 일이없고 paging 을 이용할것 같긴 합니다. )


제가 생각하기에는 아래의 2가지 정도 해결책이 있어보입니다.
(1) one-to-many 의 관계를 사용하지 않고 명시적으로 fk 를 이용해서 repository 에서  find 를 호출 하는 방법.
을 사용해 봤는데 이방법은 batch size 셋팅을 한다하여도 당연하겠지만 in query 로 sql 이 호출되지 않았습니다.
당연히 속도도 현저히 늘려서 엄청난 시간이 걸렸습니다. ( 3분 -> 50분 )
( ps. 아래의 코드에서도 inquery 셋팅하는 방법이 있을까요? )

List<Category> categories = categoryRepository.findAll();

List<CategoryResult> categoryResults = categories.stream()
.map(category -> {
long categoryId = category.getId();
List<Product> products = productRepository.findAllByCategoryId(categoryId);

int count = products
.stream()
.map(product -> {
Long productId = product.getId();
List<DisplayInfo> displayInfos = displayInfoRepository.findAllByProductId(productId);

return displayInfos.size();
})
.reduce(0, Integer::sum);
return new CategoryResult(category.getId(), category.getName(), count);
})
.collect(Collectors.toList());

(2) count query 를 설정하는 방법
위의 needs 의 경우 통계쿼리처리를 하면 되겠지만, 만약 통계 쿼리로 처리하지못하는 로직이 있으면 어떻게 처리를 할수있을까요?


마지막 질문으로 위와 같이 oom 의 위험에도 불구하고 one-to-many 관계를 써야하나요??
서비스에서의 가장큰 위험은 예상되지않은 에러라고 생각이 되는데 이경우 어떤 테이블이 어떻게 데이터가 많아질지 모르는 상황에서 위의 상황이 발생할수 있다고 생각이 됩니다.
그럼에도 불구하고 성능적인 측면에서 one-to-many 를 쓰지않으면 성능이 너무나도 좋지않아서 고민입니다.

긴글 읽어주셔서 감사합니다.

답변 1

답변을 작성해보세요.

0

안녕하세요. 오지훈님 좋은 질문입니다

결론을 말씀드리면 이렇게 데이터가 많은 경우에는 OneToMany 관계를 사용하는 것이 적절하지 않습니다.

특히 문제가 되는 부분이 category - product 관계인데요.

실무에서는 Product -> Category로 ManyToOne 관계만 있어도 충분히 문제를 잘 해결할 수 있습니다.

쿼리를 실행할 때도 특정 카테고리에 속한 Product 목록을 찾고 싶으면 다음과 같이 쿼리하면 됩니다.

select p from Product p where p.category = :category

감사합니다.