JPQL의 count 성능 이슈 및 exist 사용 방법

박진형·2021년 12월 28일
1

JPA

목록 보기
4/7
post-custom-banner

JPQL의 count 성능 이슈

Spring의 JPA 사용 중 데이터가 존재하는지 확인하는 방법으로 count 함수를 사용할 때가 있다.
단순히 하나의 데이터가 존재하는지 확인하는 경우(아이디 중복확인 등) count 함수를 사용하면 성능상에 문제가 발생할 수 있다.

성능에 실제로 문제가 발생하는지 알고싶어 검색 중 어떤 분이 작성하신 글에 해답이 나와 있었다.
Avoid Using COUNT() in SQL When You Could Use EXISTS()

요약하자면 SQL의 count함수를 사용할 때 보다 exists를 사용할 때가 성능이 1.3배 더 좋았다는 얘기다. 데이터가 훨씬 많은 상황에서는 더 많은 격차가 발생할 수 있을거로 예상됐다.

성능이 왜 다른가?

exists는 데이터가 존재하는지 확인만하면 되므로 데이터를 찾으면 쿼리를 종료하지만
count는 "총 몇개인지"를 확인한다 그러므로 모든 데이터를 스캔한다.
그 차이가 성능의 차이를 낸다.

JPQL에서 exists 사용법?

그렇다면 JPQL에서 exists를 사용하면 된다는 것을 알았는데 어떻게 사용하는가?
JPQL은 select절에 exists를 지원하지 않는다.

exist를 대체할 수 있는 방법

Spring Data JPA의 메소드 쿼리

Spring Data JPA에서는 메소드 쿼리라는게 존재하는데 메소드 이름을 적절히 설정을 하면 쿼리를 자동으로 만들어주는 기능이다.
메소드 쿼리에서는 exist를 사용 할 수 있다.

void existsById(String id);

Querydsl 사용

public boolean existsById(String id) {
    return from(Member)
        .where(Member.id.eq(id))
        .select(Member.id)
        .fetchFirst() != null;
}

이렇게하면 내부적으로 하나의 데이터만 찾도록 쿼리에 limit 절이 들어간다.

JPQL에서 maxResult 설정

jpql의 쿼리에 setMaxResult로 limit을 걸어주면 위 방법들과 같은 효과를 낸다.

public boolean existsById(String id) {
	return em.createQuery("select m from Member m where m.id = :id")
.setParameter("id", id)
.setMaxResults(1)
.getSingleResult() != 0;

count 함수는 null을 반환하지 않는다.

jpql에서 count를 사용할 시 찾은 데이터의 개수를 반환한다. 조건에 맞는 데이터가 전혀 존재하지 않는 경우에는 null을 반환하는 것이아닌, 0을 반환한다.
그러므로 getResultList()를 사용할 것이아닌 getSingleResult()를 사용하면 된다.

post-custom-banner

0개의 댓글