본문 바로가기
Spring

[Spring] Querydsl exists 성능 개선

by 가드 2022. 11. 20.
728x90

테스트용 테이블 test1 생성하고 Date 값을 300만건 생성하였다. 조회 대한 테스트는 test1 테이블로 진행해보겠다.

조건에 대한 데이터가 존재하는지에 대한 쿼리

1. count로 조회하여 count > 0 조건으로 존재 여부를 파악할 때

select COUNT(*) > 0 from test1 where create_at > '2022-11-01';

실행시간 : 331 ms

2. exist로 존재 여부를 파악할 때

select exists(select * from test1 where create_at > '2022-11-01');

실행시간 : 10ms

두 가지 방식은 실행시간 차이가 많이 난다. 데이터양이 많아질수록 실행시간에 대한 차이는 더 커질 것이다. 이유는 정말 간단하다.

1번 방식은 모두 데이터 읽은 후 조건에 대한 데이터가 수로 존재 여부를 파악하는 것이고

2번 방식은 조건에 맞는 데이터 찾게 되면 쿼리를 종료하고 결과를 리턴하기 때문이다.

물론 2번 방식도 최악의 상황으로 조건의 데이터가 300만 번째에 있으면 동일한 조회 성능이 나오겠지만 1번 방식은 항상 모든 데이터를 읽어 들이기 때문에 2번 방식이 1번 방식보다 성능적인 면에서 더 좋다고 말할 수 있다.

 

Querydsl 버전에 따른 코드 차이

spring-data-jpa version이 2.7.0 이후 버전인지 2.6.X 버전을 사용하는 건지에 따라 QuerydslJpaPredicateExecutor 클래스 exists() 메서드의 쿼리 방식이 달라지니 버전 확인을 잘해야 한다. #2333 수정 코드 참고

1. 과거 버전 ~ 2.6.X

@Override
public boolean exists(Predicate predicate) {
   return createQuery(predicate).fetchCount() > 0;
}

2. 2.7.0 ~ 현재 버전

@Override
public boolean exists(Predicate predicate) {
	return createQuery(predicate).select(Expressions.ONE).fetchFirst() != null;
}

2.6.X 버전까지는 실제로는 count() > 0를 사용하기 때문에 전체 조회가 일어나고 2.7.0부터는 동일 조건 데이터가 조회되면 쿼리 종료하는 방식으로 변경되었다.

1번에 해당되는 버전을 사용 중이라면 2번 버전으로 업데이트하는 것을 권고하고 내부 디펜던시에 의해서 버전 변경이 어렵다면 코드를 우회해야 조회 성능을 올릴 수 있다.

 

JPQL에서 공식으로 exists 함수를 지원하지 않는다. 그래서 조건의 해당하는 row 1개만 찾으면 쿼리를 종료하게 만들면 된다.

public Boolean exist(String nickName) {
	Integer fetchOne = jpaQueryFactory.selectOne()
                        .from(player)
                        .where(eqName(nickName))
                        .fetchFirst();
	return fetchOne != null;
}

조회 결과가 없을 수도 있으니 fetchOne 객체를 null체크 해야한다.

JpaQueryFactory를 이용하여 exists 함수를 구현했다.

300x250

'Spring' 카테고리의 다른 글

[Spring] Querydsl Select 성능 개선  (0) 2022.11.22
[Spring] Querydsl Join 성능 개선  (0) 2022.11.21
[Spring] Querydsl Repository 구현  (0) 2022.11.19
[Spring] Querydsl Gradle 설정 (Gradle 7.X)  (0) 2022.11.18
[Spring] Dispatcher Servlet  (0) 2022.11.13

댓글