본문 바로가기
Spring

[Spring] Querydsl Join 성능 개선

by 가드 2022. 11. 21.
728x90

Querydsl exists 성능 개선에 이어서 Querydsl Join에 대한 글을 정리해보려고 한다.

일단 Cross Join에 대해서 간단하게 정리해보자

Cross Join은 상호 조인이라 불리며, 한 테이블의 모든 컬럼들과 다른 테이블의 모든 컬럼들을 조인되는 기능이며 성능상 잘 나오지 않는다. 두 테이블의 나올 수 있는 모든 경우의 수를 대상으로 하기 때문에 성능이 좋을 수 없다. 그래서 Cross Join은 피하는 게 좋다.

왜 Cross Join을 이야기하는가? 오늘 성능 개선에 대한 내용의 주인공이다.

테스트용 @OneToOne 세팅

Member Entity

public class Member {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    @OneToOne(mappedBy = "member")
    private Address address;
}

Address Entity

public class Address {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private Long cityNo;
    private String address1;
    private String address2;
    @OneToOne
    @JoinColumn(name = "member_id")
    private Member member;
}

Querydsl TestCode

public List<Member> test() {
    return jpaQueryFactory.selectFrom(member)
        .where(member.id.eq(member.address.cityNo))
        .fetch();
}

Member와 Address는 OneToOne 관계이고 FK는 Address가 가지고 있고 테스트 코드에서는 join이 없고 where 문으로 연관관계 객체로 조건을 설정했다.

하이버네이트 로그를 살펴보자.

Hibernate: 
    select
        member0_.id as id1_1_,
        member0_.name as name2_1_ 
    from
        member member0_ cross 
    join
        address address1_ 
    where
        member0_.id=address1_.member_id 
        and member0_.id=address1_.city_no

from 절을 보면 cross 가 발생되었다. JPQL에서는 명시적으로 join을 선언하지 않는 이상 Cross Join을 사용하게 되어있다.

연관관계에 대한 Join 조회를 해야 한다면 where에서 조건을 주기보다는 명시적으로 Join을 선언해서 사용하자.

public List<Member> joinTest() {
    return jpaQueryFactory.selectFrom(member)
        .innerJoin(member.address, address)
        .where(member.id.eq(member.address.cityNo))
        .fetch();
}
Hibernate: 
    select
        member0_.id as id1_1_,
        member0_.name as name2_1_ 
    from
        member member0_ 
    inner join
        address address1_ 
            on member0_.id=address1_.member_id 
    where
        member0_.id=address1_.city_no

 

Querydsl의 innerJoin을 명시하게 되면 문제가 해결된다. 

Querydsl에서 관계에 대한 데이터를 조회하려 할 때 꼭 join 함수를 이용하도록 하자.

 

참고사항

JPA Repository에서

@Query("SELECT m FROM Member m WHERE  m.id = m.address.cityNo")

이런 식으로 쿼리를 작성을 해서 조회했을 경우에도 동일하게 Cross Join 문제가 발생한다. Querydsl과 Jpa Repository에 문제가 아닌 하이버네이트 자체의 정의이기 때문에 어떤 방식으로든 명시적으로 Join을 선언하고 Cross Join은 발생되지 않도록 주의해야 한다.

300x250

댓글