조회 성능 개선을 위한 @Transactional (3)

2025. 8. 25. 16:23·트러블 슈팅

조회 성능 개선을 위한 쿼리 최적화 (2)

 

조회 성능 개선을 위한 쿼리 최적화 (2)

조회 성능 개선을 위한 쿼리 최적화 (1) 조회 성능 개선을 위한 쿼리 최적화 (1)개요 프로젝트를 되짚어보면서 개선할 수 있는 부분을 찾고 있습니다. 진행 중인 프로젝트는 콘서트 티켓팅 프로젝

taetae99.tistory.com

 

개요


지난 시간에는 인덱스를 사용하여 조회 성능을 개선했습니다.

 

이번 게시글에서는 @Transactional에 따른 성능 개선 효과를 다루어보고자 합니다.

 

 

JPA를 학습하다 보면 @Transactional(readOnly = true)를 사용하면 조회 성능을 최적화할 수 있다는 말을 들은 적이 있을 겁니다.

 

하지만, 데이터를 변경하지 않고 읽기만 할 때에는 트랜잭션을 제거해도 되지 않을까?라는 고민을 하게 되었습니다.


트랜잭션을 사용하면 불필요한 JDBC 호출이 추가로 발생하여 성능에 영향을 미칠 것으로 생각했기 때문입니다.

 

실제 테스트와 로그를 통해 어떤 차이가 존재하는지 확인해보고자 합니다.

 

@Transactional(readOnly = true) 유무


좌석 정보 조회 API를 호출하면 서비스 단에서 Repo를 호출하게 됩니다.

 

좌석 정보를 조회하기 위해 Repository에서 한 번의 SELECT 쿼리를 실행하여 데이터를 가져옵니다.

하지만 @Transactional(readOnly=true)을 사용하는 경우, SELECT 쿼리뿐만 아니라 추가적인 JDBC 호출이 발생하고 있었습니다.

 

MySQL의 general-log를 사용하여 트랜잭션의 유무에 따라 어떻게 동작하는지 확인해 보겠습니다.

 

트랜잭션 사용 x

트랜잭션을 사용하지 않고 조회한 로그입니다.

데이터를 가져오기 위한 SELECT 쿼리만 발생하고 있습니다.

 

@Transactional(readOnly = true)

읽기 전용 트랜잭션을 사용하여 조회한 로그입니다.

 

실행되기를 기대했던 SELECT 쿼리 앞뒤로 추가적인 쿼리들이 발생했습니다.

 

SET TRANSACTION, AUTOCOMMIT과 같이 5개의 쿼리가 더 발생했습니다.

 

이는 JPA에서 @Transactional을 사용하면서 트랜잭션을 관리하기 위해 내부적으로 실행되는 설정 때문에 실행됩니다.

 

이처럼 트랜잭션을 사용하면 추가적인 JDBC 호출이 더 발생하게 되고, 이것이 조회 성능에 영향을 줄 수 있겠다고 생각했습니다.

 

 

성능에 영향이 있을까?


SET TRANSACTION, AUTOCOMMIT과 같은 트랜잭션 처리에 사용되는 쿼리들이 조회 성능에 영향을 미치는지 확인해 보겠습니다.

 

트랜잭션 사용 x
트랜잭션 사용 x
트랜잭션 사용
@Transactional(readOnly = true)

 

동일한 조건에서 테스트한 결과, 트랜잭션을 사용하지 않는 경우 MTT(평균 응답 시간)가 약 2.68배 증가한 것을 확인했습니다.

 

이를 통해, 읽기 전용 트랜잭션을 사용하여 발생하는 추가적인 쿼리가 조회 성능에 영향을 미친다는 것을 확인할 수 있었습니다.

 

 

JPA 사용 시 @Transactional 주의할 점


Replication

간단한 프로젝트에서는 데이터베이스를 하나만 사용합니다.

 

하지만 실제 운용 서비스와 같이 Replication 방식을 구성한 시스템에서는 문제가 발생할 수 있습니다.

 

예를 들어, Replication 환경에서는 트랜잭션의 readOnly 여부를 따져 Master과 Slave DB로의 트래픽을 분산합니다. 

 

트랜잭션을 제거하면 읽기 요청이 Master로 요청되는 상황이 발생할 수 있습니다. 

 

따라서 Replication 환경에서 트랜잭션을 제거하고 싶다면,

트랜잭션 어노테이션을 사용하면서, 전파 속성을 설정하여 트랜잭션 없는 readOnly DB 접근이 가능하도록 해야 합니다.

 

제가 참고한 카카오페이 테크 블로그에서는 커스텀 어노테이션을 제안하였습니다.

@Transactional(readOnly = true, propagation = Propagation.SUPPORTS)
annotation class ReadOnlyTransactional

 

 

저는 커스텀 어노테이션을 작성하지는 않았고, 전파 속성을 변경하여 검증을 진행했습니다.

 

propagation을 NOT_SUPPORTS로 변경해 본 결과, 트랜잭션 관련 쿼리가 발생하지 않는 것을 확인할 수 있었습니다.

전파 속성 변경
propagation = NOT_SUPPORTS

 

 

Lazy Loading

Spring에서 트랜잭션을 시작하지 않으면 JPA는 영속성 컨텍스트를 사용할 수 없어서 Lazy Loading을 사용할 수 없게 됩니다.

 

따라서 Lazy Loading을 사용하고 있다면, @Transactional을 제거하면 안 됩니다. 

 

JpaRepository 사용

Spring Data JPA를 사용할 때는 보통 JpaRepository를 상속받아 Repository 인터페이스를 정의합니다.

JpaRepository를 상속하면, 스프링 데이터 JPA는 내부적으로 SimpleJpaRepository라는 구현체를 사용합니다.


이를 통해 findById, save, delete 같은 기본 메서드들이 자동으로 구현됩니다.

 

하지만 해당 클래스는 클래스 레벨에서 @Transactional을 사용하고 있습니다.

 

서비스 단에서 트랜잭션을 삭제하더라도, JpaRepository를 상속받는 경우 본인도 모르게 트랜잭션을 사용하게 됩니다.

 

 

실제 SimpleRepository를 확인해 보면 클래스 레벨에서 이미 @Transactional(readOnly=true)가 선언되어 있습니다.

 

 

그렇다면 다시 확인해 볼 필요가 있습니다.

 

Repository에 JpaRepository를 상속받고, 서비스 단에서는 트랜잭션을 제거한 뒤 로그를 살펴보았습니다.

JpaRepository 상속
JpaRepository 상속

 

트랜잭션을 사용했을 때와 동일하게 SET TRANSACTION, AUTOCOMMIT과 같은 트랜잭션 관련 쿼리가 발생했습니다.

 


 

JpaRepository를 상속받으면서 Default 트랜잭션의 영향을 받지 않기 위해서는 Querydsl이나 JPQL과 같은 커스텀 쿼리를 사용하여 해결할 수 있습니다.

 

또는 JpaRepository 대신 Repository를 상속받아 필요한 메서드를 직접 정의하는 방식으로 해결할 수 있습니다.

 

저는 프로젝트를 진행하면서, 조회 모델의 불필요한 구현을 제거하고 책임을 명확히 하기 위해 Repository를 상속받았습니다.

 

이는 SimpleJpaRepository의 기본 구현을 사용하지 않으므로 기본 트랜잭션이 자동으로 적용되지 않습니다.

 

 

 

참고


https://creampuffy.tistory.com/179

https://hungseong.tistory.com/74

https://taetae99.tistory.com/manage/newpost/?type=post&returnURL=%2Fmanage%2Fposts%2F

카카오 페이 - JPA Transactional 잘 알고 쓰고 계신가요?

 

반응형

'트러블 슈팅' 카테고리의 다른 글

[트러블슈팅] 기술에 종속된 Repository 계층 개선: JPA → MongoDB 전환기  (0) 2025.11.28
[MySQL] DISTINCT 사용에 따른 임시 테이블 및 성능 차이  (0) 2025.09.11
조회 성능 개선을 위한 쿼리 최적화 (2)  (1) 2025.08.21
조회 성능 개선을 위한 쿼리 최적화 (1)  (0) 2025.08.19
'트러블 슈팅' 카테고리의 다른 글
  • [트러블슈팅] 기술에 종속된 Repository 계층 개선: JPA → MongoDB 전환기
  • [MySQL] DISTINCT 사용에 따른 임시 테이블 및 성능 차이
  • 조회 성능 개선을 위한 쿼리 최적화 (2)
  • 조회 성능 개선을 위한 쿼리 최적화 (1)
taetae99
taetae99
우직하게 개발하기
    반응형
  • taetae99
    코드 대장간
    taetae99
  • 전체
    오늘
    어제
    • 분류 전체보기
      • Teck Stack
        • Java
        • Spring
        • DB
        • Redis
        • SpringSecurity
        • Docker
        • HTML
        • AWS
      • 우아한테크코스
      • CS & Architecture
        • DDD
        • CS
        • 디자인 패턴
      • 트러블 슈팅
      • 알고리즘
        • 프로그래머스
        • 백준
      • 프로젝트
        • Board 프로젝트
      • 기타
      • 대회 및 후기
  • 인기 글

  • hELLO· Designed By정상우.v4.10.3
taetae99
조회 성능 개선을 위한 @Transactional (3)
상단으로

티스토리툴바