inflearn logo
강의

강의

N
챌린지

챌린지

멘토링

멘토링

N
클립

클립

로드맵

로드맵

지식공유

실전! 스프링 데이터 JPA

컬렉션 페치조인 batch size 활용 후 두개이상의 depth의 toOne 관계 lazy loading 시 join 이나 한방쿼리 활용방법 질문

506

득윤

작성한 질문수 5

1

안녕하세요!

개인 프로젝트 중 만난 상황에 대해 질문이 있습니다!

 

컬렉션 페치조인, 페이징 처리시, batch size 를 활용하여 최적화를 진행 중입니다.

위와 같은 erd 에서 아티클을 페이징 조회 하면서 프로필, 태그 목록 까지 조회하고 싶습니다.

이때 아티클당 작성자의 프로필은 toOne 관계 이기 때문에 fetch join을 활용 하여 진행할 수 있었습니다.

 

이후에 프록시로 조회된 아티클 태그를 batch Size 를 이용해 n+1 문제 없이 조회하고

아티클 태그 에서는 태그를 조회해서 아티클->아티클태그->태그의 연관을 땡겨 올 수 있습니다.

결국 총 3회의 쿼리가 발생하는데 아티클 태그, 태그를 조회하는 추가 쿼리를 join 이나 where 절을 사용해 한방 쿼리로 묶을 수 있는 방법이 있는지 궁금합니다.

 

@Override
    public List<ArticleJpaEntity> searchArticle(long offset, long limit) {

       //쿼리 1 
        List<ArticleJpaEntity> articles = query
                .selectFrom(articleJpaEntity)
                .distinct()
                .join(articleJpaEntity.authorProfile, profileJpaEntity).fetchJoin()
                .offset(offset)
                .limit(limit)
                .fetch();

        //아티클 -> 아티클 태그 -> 태그의 lazy loading : 쿼리 2, 쿼리 3
        /*
              ArticlJpaEntity 의 메서드
              public List<String> getTagList() {

                  //쿼리 2: 아티클 -> 아티클 태그 레이지 로딩 발생 
                  return articleTags.stream()
                        //쿼리 3 : 아티클 태그 -> 태그의 레이지 로딩 발생
                        .map(ArticleTagJpaEntity::getTagName).collect(toList());
              }
         */

       //조회된 아티클을 돌며 수동 레이지 로딩 - batch size 로 n+1 방지
        for (ArticleJpaEntity article : articles) {
            article.getTagList();
        }

        return articles;
    }

 

querydsl 을 활용하였고 활용한 코드는 위와 같습니다.

 

발생한 쿼리를 요약하면 아래와 같습니다.

쿼리 1

select 
  distinct a.*, 
  p.* 
from 
  article a 
  inner join profile p on a.author_profile_id = p.id 
limit 
  20

쿼리 2

select 
  at.* 
from 
  article_tag at 
where 
  at.article_id in (7, 8, 9)

 

쿼리 3

select 
  t.* 
from 
  tag t 
where 
  t.id in (16, 17, 18)

 

참고로 전체 데이터는 아래와 같습니다.

insert into profile (bio, image, user_id, username, id) values ('user1bio', 'user1image', 1, 'user1', 4);
insert into profile (bio, image, user_id, username, id) values ('user2bio', 'user2image', 2, 'user2', 5);
insert into profile (bio, image, user_id, username, id) values ('user3bio', 'user3image', 3, 'user3', 6);

insert into article (author_profile_id, body, created_at, description, slug, title, updated_at, id)
values (4, 'article7body', '2022-07-11 22:42:43', 'article7desc', 'article7slug', 'article7title', NULL, 7);

insert into article (author_profile_id, body, created_at, description, slug, title, updated_at, id)
values (5, 'article8body', '2022-07-11 22:42:43', 'article8desc', 'article8slug', 'article8title', NULL, 8);

insert into article (author_profile_id, body, created_at, description, slug, title, updated_at, id)
values (6, 'article9body', '2022-07-11 22:42:43', 'article9desc', 'article9slug', 'article9title', NULL, 9);

-- 태그 16, 17, 18
insert into tag (name, id) values ('tag16', 16);
insert into tag (name, id) values ('tag17', 17);
insert into tag (name, id) values ('tag18', 18);


-- 아티클 7 -> 아티클 태그 19 -> 태그 16 - tag16

-- 아티클 8 -> 아티클 태그 20 -> 태그 16 - tag16
-- 아티클 8 -> 아티클 태그 21 -> 태그 17 - tag17

-- 아티클 9 -> 아티클 태그 22 -> 태그 16 - tag16
-- 아티클 9 -> 아티클 태그 23 -> 태그 17 - tag17
-- 아티클 9 -> 아티클 태그 24 -> 태그 18 - tag18
insert into article_tag (article_id, tag_id, id) values (7, 16, 19);

insert into article_tag (article_id, tag_id, id) values (8, 16, 20);
insert into article_tag (article_id, tag_id, id) values (8, 17, 21);

insert into article_tag (article_id, tag_id, id) values (9, 16, 22);
insert into article_tag (article_id, tag_id, id) values (9, 17, 23);
insert into article_tag (article_id, tag_id, id) values (9, 18, 24);

 

===

요약 - 쿼리 2와 쿼리 3을 한방 처리 할 수 있나요??

lazyloading batchsize JPA fetchjoin spring-boot spring java

답변 1

1

김영한

안녕하세요. 득윤님

정리하자면 시작점을 기준으로 toOne으로 연결되는 부분은 모두 한방 쿼리가 가능하고, 중간에 컬렉션이 나오게 되면 그 부분 부터는 어렵습니다.

활용2편에서 설명드린 내용이어서, 자세한 내용은 활용2편 강의를 참고해주세요.

감사합니다.

changeTeam 메서드 질문

0

20

1

existsByUserIdAndProjectId vs existsByUserAndProject 중 어떤 방식이 적절할까요?

0

78

1

existsByUserIdAndProjectId vs existsByUserAndProject 중 어떤 방식이 적절할까요?

0

112

3

MemberRepository 구현체

0

64

1

pdf 표현 질문드립니다.

0

66

1

로그가 남지 않는 문제.

0

90

1

테스트 라이브러리가 강의는 junit4가 맞나요??

0

73

2

pdf 파일과 차이점이 있는 것같은데 문제 없나요?

0

73

2

@PrePersist, @PreUpdate 호출 시점 질문드립니다.

0

96

2

Sort 인터페이스는 잘 사용 안하나요?

0

52

1

스캔대상 질문드립니다.

0

46

1

하이버네이트6에서의 최적화에 이은 질문

0

88

1

save() vs saveAndFlush DB 통신 횟수

0

55

1

순수 JPA 리포지토리 코드 수정부분

0

87

2

bulk연산 후 flush하는 이유를 모르겠어요

0

153

3

bulk insert 질문입니다.

0

186

2

교만했던 것 같아요.

0

147

1

RESTful 강의는 안하시는 건지 궁금합니다.

0

151

2

동적 테이블에 대한 질문

0

87

1

영속성 전이와 연관관계

0

134

2

강의 10:25 질문

0

75

1

단건 update 질문

0

99

2

엔티티 와 도메인의 경계

0

129

1

UsernameOnlyDto 타입 type mismatch 오류

0

122

1