회사에서 Querydsl를 사용하던 중 DB결과가 느려 쿼리문을 확인해보니 Cross Join이 계속해서 발생하는 것을 확인하게 되었고 이를 해결하면서 얻은 정보를 작성한 글입니다.
JPA 기반의 환경에서 Querydsl을 사용하여 Join 쿼리 작성시 Cross Join이 발생할 수 있습니다.
Cross Join의 결과는 2개의 집합의생길 수 있는 모든 데이터의 조합 (M*N) 이 나오는 경우를 이야기 합니다.
해당 결과는 Inner Join보다 성능상 이슈가 발생하게 됩니다.
어떤 경우에 Cross Join이 발생하는지, 해결할 수 있는지 확인해보겠습니다.
1. 테스트 세팅
테스트를 위한 Entity
User
@Getter
@Entity
@Table(name = "member")
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "user_id")
private Long id;
@Column(nullable = false)
private String email;
@Column
private String password;
@Column
private String name;
@ManyToOne
@JoinColumn(name = "team_id")
private Team team;
}
Team
@Entity
@Getter
@NoArgsConstructor
public class Team {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column
private Long id;
@Column
private String name;
}
User와 Team은 ManyToOne 관계인 상황입니다.
2. 테스트
사용할 Querydsl 코드는 다음과 같습니다.
@Override
public List<User> getJoinTest() {
return queryFactory.selectFrom(user)
.where(user.name.eq(team.name))
.fetch();
}
해당 코드를 실행할 경우 Cross Join이 발생하는 것을 확인할 수 있습니다.
현재 코드에서는 별도의 join절이 선언되어 있지 않고 where 문에서 바로 연관관계를 사용했기 때문에 Cross Join이 발생합니다.
Querydsl-JPA에서 사용하는 Hibernate의 특징 때문에 발생합니다.
- Hibernate에서 암묵적인 Join은 Cross Join을 사용한다.
해당 이슈는 Querydsl를 사용하는 것이 아닌 @Query를 사용하는 경우에도 발생합니다.
해결책
해결방법은 암묵적 Join에서 명시적 Join으로 변경하는 것입니다.
@Override
public List<User> getJoinTest() {
return queryFactory.selectFrom(user)
.innerJoin(user.team, team)
.where(user.name.eq(team.name))
.fetch();
}
.innerJoin(user.team, team)을 추가하여 명시적으로 Join을 선언해줍니다.
명시적 Join을 사용했기 때문에 Cross Join이 아닌 Inner Join이 발생하였습니다.
'Spring' 카테고리의 다른 글
QueryDsl를 활용하여 DTO로 바로 만들기 (0) | 2023.08.02 |
---|---|
Spring Boot JPA 영속성 컨텍스트 (0) | 2023.07.27 |
Spring Boot에서 Redis 사용하기 (0) | 2023.06.26 |
[SpringBoot] Scheduler & 동적 Scheduler (0) | 2023.06.05 |
Intellij 네이버 Java 코딩 컨벤션 및 Checkstyle 적용 (1) | 2023.06.01 |