관리 메뉴

피터의 개발이야기

[MySQL] 중복체크를 위한 Count vs Limit vs Exists 본문

Database/MySQL

[MySQL] 중복체크를 위한 Count vs Limit vs Exists

기록하는 백앤드개발자 2024. 6. 30. 10:10
반응형

ㅁ 들어가며

ㅇ JPA를 사용 중인 프로젝트에서 중복체크 기능을 구현하면서 Exists와 Count의 성능차이를 고민하였다.

[QueryDSL] fetchFirst()와 fetchOne()의 차이을 정리하면서 Count vs Limit vs Exists 성능 차이에 대해서 정리하였다.

JPA exists 쿼리 성능 개선을 보고, 이해한 부분을 정리하였다.

 

ㅁ성능 비교

ㅇ 대량의 데이터(약 5600만 건)가 있는 테이블에서 COUNT와 EXISTS의 성능을 비교해보면 2배에 가까운 성능 차이가 나타났다.

ㅇ 데이터가 1억 건 이상으로 늘어나면 이 차이는 더욱 벌어질 것이다.

  • COUNT: 9.079초
  • EXISTS: 5.278초

 

ㅁ 원인분석

ㅇ 이러한 성능 차이의 원인은 각 쿼리의 동작 방식에 있다

- EXISTS: 첫 번째 결과에서 바로 TRUE를 반환
- COUNT: 총 레코드 수를 확인하기 위해 전체 테이블을 스캔

 

ㅇ 따라서 EXISTS가 COUNT보다 더 효율적으로 동작한다.

 

ㅁ JPA와 Querydsl에서의 문제점

ㅇ 그러나 JPA의 @Query 어노테이션과 Querydsl에서는 SELECT EXISTS 구문을 직접 사용할 수 없는 문제가 있다. 

ㅇ 이로 인해 개발자들은 주로 COUNT 쿼리를 사용하게 되는데, 이는 앞서 언급한 성능 이슈를 야기한다.

 

ㅁ LIMIT 1을 이용한 해결책

ㅇ EXISTS의 성능 이점을 활용하기 위해 LIMIT 1을 사용하는 방법이 있다. 

ㅇ 이 방법은 전체 테이블을 스캔하지 않고 첫 번째 결과만 확인하므로 EXISTS와 유사한 성능을 낼 수 있다.

ㅇ Querydsl에서는 다음과 같이 구현할 수 있다

public Boolean exist(Long bookId) { 
	Integer fetchOne = queryFactory.selectOne()
    	.from(book) 
        .where(book.id.eq(bookId)) 
        .fetchFirst(); // LIMIT 1 return fetchOne != null; 
}

ㅇ 이 방법을 사용하면 EXISTS와 동일한 성능 효과를 얻을 수 있다.

 

ㅁ 마무리

- COUNT는 EXISTS에 비해 성능 이슈가 있다.
- JPA의 @Query와 Querydsl에서는 SELECT EXISTS를 직접 사용할 수 없다.
- LIMIT 1을 사용하여 SELECT EXISTS를 대체할 수 있으며, 이는 비슷한 성능을 제공한다.
- JpaRepository의 메소드 쿼리는 내부적으로 LIMIT 1을 사용하므로 성능상 문제가 없다.

 

중복 체크 시 이러한 차이점을 고려하여 적절한 방법을 선택하면 효율적인 쿼리 성능을 얻을 수 있다.

 

ㅁ 함께 보면 좋은 사이트

[MySQL 튜닝] EXISTS를 이용한 SQL 튜닝

JPA exists 쿼리 성능 개선

DB 데이터 존재 확인 Count vs Limit vs Exists

 

반응형
Comments