JPA exists 외래키 최적화

Jang990·2023년 6월 24일
0
post-thumbnail

상황

Client 테이블과 Bundle 테이블은 1:N 관계이다.
Client 테이블에서 Bundle 테이블의 PK를 외래키로 가지고 있는 것이다.

Client(clinet_id(PK), ... , bundle_id(FK))
Bundle(bundle_id, ...)

클래스는 다음과 같이 만들어져있다.

@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Client extends BaseTimeEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "client_id")
    private Long id;
    
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "bundle_id")
    private Bundle bundle;
    
    ...
}
@Entity
@AllArgsConstructor
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Getter
public class Bundle extends BaseTimeEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "bundle_id")
    private Long id;
    
    ...
}

해당 상황에서 Client_IDBundle_Id 필드들의 값이 주어졌을 때
Client 테이블에 해당 데이터가 테이블에 있는지 확인해야 한다.

JpaRepository exists 쿼리 메소드 사용

다음 JpaRepository에서 기본적으로 제공해주는 쿼리 메소드를 사용해서 쿼리를 날려보겠다.

public interface ClientRepository extends JpaRepository<Client, Long> {
    boolean existsByIdAndBundle_Id(Long clientId, Long bundleId);
}

테스트

다음과 같이 left outer join을 써서 조회해오고 있다.

하지만 나는 Client 테이블 내에서 조인없이 해결하길 원한다. 다른 테이블을 매칭시켜야 하기 때문에 조인이 껴버리면 성능이 떨어질 수 밖에 없다.

QueryDSL로 구현

QueryDSL을 이용해서 exists 메소드를 직접 구현해보자.
JpaRepository에서 제공하는 exists 메소드도 결국 select로 id를 가져와서 값이 있으면 true를 반환하도록 되어있다. 또한 limit로 최적화를 하고 있다.
JpaRepository와 똑같이 구현해주고, 조인만 없애면 된다.

	@Autowired
    JPAQueryFactory query; // QueryDSL 관련 설정이 있어야 함.
    
    private boolean find(long bundleId, long clientId) {
    	// exists 메서드 구현
        Integer exists = query.selectOne()
                .from(client)
                .where(client.id.eq(clientId), client.bundle.id.eq(bundleId))
                .fetchFirst();

        return exists != null;
    }

테스트


이제 조인없이 조회해오는 것을 확인할 수 있다.

참고

https://jojoldu.tistory.com/516

profile
공부한 내용을 적지 말고 이해한 내용을 설명하자

0개의 댓글