본문 바로가기
프로젝트

QueryDsl Fetch Join Query문 비교

by Dr.섭도 2024. 5. 30.

Spring Data JPA

사용

List<Follow> findFollow = followerRepository.findByFollowerId(member1.getId());

for (Follow follow : findFollow) {
    log.info("follower name = {}", follow.getFollower().getName());
}

 

결과

Hibernate: 
    select
        f1_0.follow_id,
        f1_0.created_by,
        f1_0.created_time,
        f1_0.follower_id,
        f1_0.following_id,
        f1_0.updated_by,
        f1_0.updated_time 
    from
        follow f1_0 
    where
        f1_0.follower_id=?
Hibernate: 
    select
        m1_0.member_id,
        m1_0.age,
        m1_0.created_by,
        m1_0.created_time,
        m1_0.email,
        m1_0.name,
        m1_0.picture,
        m1_0.updated_by,
        m1_0.updated_time 
    from
        member m1_0 
    where
        m1_0.member_id=?
2024-05-27T17:56:40.763+09:00  INFO 16664 --- [devplanner] [    Test worker] c.u.d.domain.member.entity.FollowTest    : follower name = Test2
Hibernate: 
    select
        m1_0.member_id,
        m1_0.age,
        m1_0.created_by,
        m1_0.created_time,
        m1_0.email,
        m1_0.name,
        m1_0.picture,
        m1_0.updated_by,
        m1_0.updated_time 
    from
        member m1_0 
    where
        m1_0.member_id=?
2024-05-27T17:56:40.763+09:00  INFO 16664 --- [devplanner] [    Test worker] c.u.d.domain.member.entity.FollowTest    : follower name = Test3
Hibernate: 
    select
        m1_0.member_id,
        m1_0.age,
        m1_0.created_by,
        m1_0.created_time,
        m1_0.email,
        m1_0.name,
        m1_0.picture,
        m1_0.updated_by,
        m1_0.updated_time 
    from
        member m1_0 
    where
        m1_0.member_id=?
2024-05-27T17:56:40.766+09:00  INFO 16664 --- [devplanner] [    Test worker] c.u.d.domain.member.entity.FollowTest    : follower name = Test4
Hibernate: 
    select
        m1_0.member_id,
        m1_0.age,
        m1_0.created_by,
        m1_0.created_time,
        m1_0.email,
        m1_0.name,
        m1_0.picture,
        m1_0.updated_by,
        m1_0.updated_time 
    from
        member m1_0 
    where
        m1_0.member_id=?
2024-05-27T17:56:40.767+09:00  INFO 16664 --- [devplanner] [    Test worker] c.u.d.domain.member.entity.FollowTest    : follower name = Test5
Hibernate: 
    select
        m1_0.member_id,
        m1_0.age,
        m1_0.created_by,
        m1_0.created_time,
        m1_0.email,
        m1_0.name,
        m1_0.picture,
        m1_0.updated_by,
        m1_0.updated_time 
    from
        member m1_0 
    where
        m1_0.member_id=?
2024-05-27T17:56:40.767+09:00  INFO 16664 --- [devplanner] [    Test worker] c.u.d.domain.member.entity.FollowTest    : follower name = Test6
Hibernate: 
    select
        m1_0.member_id,
        m1_0.age,
        m1_0.created_by,
        m1_0.created_time,
        m1_0.email,
        m1_0.name,
        m1_0.picture,
        m1_0.updated_by,
        m1_0.updated_time 
    from
        member m1_0 
    where
        m1_0.member_id=?
2024-05-27T17:56:40.770+09:00  INFO 16664 --- [devplanner] [    Test worker] c.u.d.domain.member.entity.FollowTest    : follower name = Test7
Hibernate: 
    select
        m1_0.member_id,
        m1_0.age,
        m1_0.created_by,
        m1_0.created_time,
        m1_0.email,
        m1_0.name,
        m1_0.picture,
        m1_0.updated_by,
        m1_0.updated_time 
    from
        member m1_0 
    where
        m1_0.member_id=?
2024-05-27T17:56:40.770+09:00  INFO 16664 --- [devplanner] [    Test worker] c.u.d.domain.member.entity.FollowTest    : follower name = Test8
Hibernate: 
    select
        m1_0.member_id,
        m1_0.age,
        m1_0.created_by,
        m1_0.created_time,
        m1_0.email,
        m1_0.name,
        m1_0.picture,
        m1_0.updated_by,
        m1_0.updated_time 
    from
        member m1_0 
    where
        m1_0.member_id=?
2024-05-27T17:56:40.770+09:00  INFO 16664 --- [devplanner] [    Test worker] c.u.d.domain.member.entity.FollowTest    : follower name = Test9
Hibernate: 
    select
        m1_0.member_id,
        m1_0.age,
        m1_0.created_by,
        m1_0.created_time,
        m1_0.email,
        m1_0.name,
        m1_0.picture,
        m1_0.updated_by,
        m1_0.updated_time 
    from
        member m1_0 
    where
        m1_0.member_id=?
2024-05-27T17:56:40.773+09:00  INFO 16664 --- [devplanner] [    Test worker] c.u.d.domain.member.entity.FollowTest    : follower name = Test10
Hibernate: 
    select
        m1_0.member_id,
        m1_0.age,
        m1_0.created_by,
        m1_0.created_time,
        m1_0.email,
        m1_0.name,
        m1_0.picture,
        m1_0.updated_by,
        m1_0.updated_time 
    from
        member m1_0 
    where
        m1_0.member_id=?
2024-05-27T17:56:40.773+09:00  INFO 16664 --- [devplanner] [    Test worker] c.u.d.domain.member.entity.FollowTest    : follower name = Test11

 

처음 Find를 하기 위한 쿼리문 이후 10명의 멤버를 팔로우로 등록했기에, 해당 멤버를 모두 가져오는 10번의 쿼리문이 나갔다(N + 1 문제가 생겼다)

 

Querydsl

Fetch Join 사용

List<Follow> findFollow = queryFactory
        .selectFrom(follow)
        .join(follow.following, member).fetchJoin()
        .where(follow.follower.id.eq(member1.getId()))
        .fetch();

for (Follow follow : findFollow) {
    log.info("following name = {}", follow.getFollowing().getName());
}

 

결과

Hibernate: 
    select
        f1_0.follow_id,
        f1_0.created_by,
        f1_0.created_time,
        f1_0.follower_id,
        f1_0.following_id,
        f2_0.member_id,
        f2_0.age,
        f2_0.created_by,
        f2_0.created_time,
        f2_0.email,
        f2_0.name,
        f2_0.picture,
        f2_0.updated_by,
        f2_0.updated_time,
        f1_0.updated_by,
        f1_0.updated_time 
    from
        follow f1_0 
    join
        member f2_0 
            on f2_0.member_id=f1_0.following_id 
    where
        f1_0.follower_id=?
2024-05-27T17:59:20.275+09:00  INFO 16592 --- [devplanner] [    Test worker] c.u.d.domain.member.entity.FollowTest    : following name = Test2
2024-05-27T17:59:20.276+09:00  INFO 16592 --- [devplanner] [    Test worker] c.u.d.domain.member.entity.FollowTest    : following name = Test3
2024-05-27T17:59:20.276+09:00  INFO 16592 --- [devplanner] [    Test worker] c.u.d.domain.member.entity.FollowTest    : following name = Test4
2024-05-27T17:59:20.276+09:00  INFO 16592 --- [devplanner] [    Test worker] c.u.d.domain.member.entity.FollowTest    : following name = Test5
2024-05-27T17:59:20.276+09:00  INFO 16592 --- [devplanner] [    Test worker] c.u.d.domain.member.entity.FollowTest    : following name = Test6
2024-05-27T17:59:20.276+09:00  INFO 16592 --- [devplanner] [    Test worker] c.u.d.domain.member.entity.FollowTest    : following name = Test7
2024-05-27T17:59:20.276+09:00  INFO 16592 --- [devplanner] [    Test worker] c.u.d.domain.member.entity.FollowTest    : following name = Test8
2024-05-27T17:59:20.276+09:00  INFO 16592 --- [devplanner] [    Test worker] c.u.d.domain.member.entity.FollowTest    : following name = Test9
2024-05-27T17:59:20.276+09:00  INFO 16592 --- [devplanner] [    Test worker] c.u.d.domain.member.entity.FollowTest    : following name = Test10
2024-05-27T17:59:20.276+09:00  INFO 16592 --- [devplanner] [    Test worker] c.u.d.domain.member.entity.FollowTest    : following name = Test11

 

쿼리 하나로 전체 연결된 멤버를 다 가져온다

Fetch Join을 할 때에는 몇 가지 주의점을 신경써야 한다

 

컬렉션 Fetch Join에서 중복 데이터가 나오는 경우가 생긴다

별칭을 줄 수 없다

둘 이상의 컬렉션은 Fetch Join 할 수 없다

페이징에 문제가 생긴다

관계 매핑에 LazyLoading 전략을 사용하자

 

Fetch Join이 만능은 아니다

-> BatchSize 사용도 고려해 보아야 한다

 

프로젝트 중 테스트 해보았으며, 추후에 Fetch Join에 대해 상세히 작성 해야겠다