• 카테고리

    질문 & 답변
  • 세부 분야

    백엔드

  • 해결 여부

    해결됨

@OneToOne(mappedBy)의 쿼리 최적화 방법

23.08.18 23:11 작성 23.08.18 23:18 수정 조회수 252

1

안녕하세요!

OneToOne(mappedBy = ...)와 관련한 질문을 드립니다.

위와 같이 mappedBy로 되어있는 엔티티를 조회하게 되면, LAZY로 설정하여도 반드시 즉시로딩됩니다. 또한, default_batch_fetch_size도 적용되지 않아 반드시 N+1문제가 발생하는 것으로 알고있습니다.

여기서 생기는 고민이, 특정 엔티티의 목록을 조회하는 로직을 구현할 때 엔티티를 select절에 넣는것에 대해서 조금 조심스럽습니다. (단건 조회는 즉시로딩이 발생해도 상대적으로 문제의 심각도가 적음)

현재 목록을 조회하려는 엔티티에 OneToOne(mappedBy = ..)가 없다면, 엔티티의 목록을 조회해도 N+1 문제와 무관합니다. 하지만, 미래에 추가가 된다면 성능에 문제가 없던 것들도 N+1문제가 생길 수 있습니다.

이에 대한 한 가지 해결방법은 Querydsl의 Projection을 사용하는 방법이 있습니다. 이는 결국 select절을 입력해줘야하며 지연로딩과 @BatchSize을 통해 해결하는게 아니기 때문에, 더 복잡한 조인 쿼리를 작성해야할 수도 있습니다. 이로 인해 생산성도 낮아질 수도 있습니다.

 

정리하자면,

select 절에 entity --> 다른 필드를 지연로딩 처리하여 더 쉽게 데이터를 찾지만, 미래에 발생할 수 있는 N+1문제를 어쩔 수 없이 수용한다.

select절에 Dto Projection --> 조인 쿼리를 다 작성해야한다. Projection을 기입해야한다. 하지만, @OneToOne(mappedBy)가 추가되어도 쿼리 성능에는 문제가 없다.

양쪽의 트레이드 오프가 있는 것 같습니다. 현업에서는 어떠한 방법을 이용하나요?

 

(추가적으로, mappedBy를 이용하지 않거나 하이버네이트에서 제공하는 바이트코드 조작 방법도 있네요)

답변 2

·

답변을 작성해보세요.

0

y2gcoder님의 프로필

y2gcoder

2023.08.21

안녕하세요. 김선도님, 공식 서포터즈 y2gcoder입니다.

사실 말씀하신 부분은 프로젝트 상황, 요구사항 등에 영향을 받는다고 생각해 어떤 것이 정답이라고 딱 말씀드리기는 어려울 것 같습니다.

위에서 말씀드린 방법 이외에도 조회성 쿼리라면 CQRS의 방법을 통해 조회 쪽을 아예 분리해서 조회를 위한 쿼리를 짜는 방법도 있을 것 같습니다. 결국 생산성이라는 것도 개발자 개인 혹은 팀이 아는 지식의 정도가 다르기 때문에 어느 것이 생산성이 더 좋은 방법이라고 말씀드리기는 어려운 것 같습니다 :) 직접 해보시면서 해당 상황에서 본인 혹은 팀에게 더 생산적인 방법을 선택하는 것이 맞다고 생각합니다.

감사합니다.

0

인프런 AI 인턴님의 프로필

인프런 AI 인턴

2023.08.20

안녕하세요, 인프런 AI 인턴이에요. OneToOne(mappedBy)와 관련한 최적화 방법에 대해 질문하셨네요.

OneToOne(mappedBy) 관계에서 LAZY 설정으로 하더라도, 즉시로딩되는 문제와 default_batch_fetch_size가 적용되지 않아 N+1 문제가 발생할 수 있는 것은 맞습니다. 특히 엔티티의 목록을 조회하는 경우에는 성능 문제가 발생할 수 있습니다.

해당 문제를 해결하는 한 가지 방법은 Querydsl의 Projection을 사용하는 것입니다. Projection을 사용하면 select문에 원하는 필드만을 포함시켜서 데이터를 조회할 수 있습니다. 이를 통해 불필요한 연관 엔티티를 쿼리에서 제외시킬 수 있어서 N+1 문제를 방지할 수 있습니다. 다만, 이 방법은 좀 더 복잡한 조인 쿼리를 작성해야 할 수도 있어 생산성이 낮아질 수 있으므로 고려해야 할 사항입니다.

또 다른 방법으로는 fetch join을 사용하는 것입니다. fetch join을 사용하면 연관 엔티티를 한 번의 쿼리로 모두 로딩할 수 있습니다. 이를 통해 N+1 문제를 줄일 수 있습니다. 다만, fetch join은 모든 연관 엔티티를 로딩하기 때문에 데이터 양이 많을 경우에는 성능 문제가 발생할 수 있으니 주의해야 합니다.

두 가지 방법을 통해 OneToOne(mappedBy) 관계에서 발생하는 성능 문제를 해결할 수 있습니다. 하지만, 어떤 방법이 가장 적합한지는 실제 상황과 요구사항에 따라 결정되어야 합니다. 프로젝트의 성능 특성과 필요한 데이터를 고려하여 적절한 방법을 선택해보세요. 감사합니다.