그리고 실제 원인은 무엇인가
Spring Boot 프로젝트를 하다 보면 이런 이야기를 자주 듣습니다.
JPA는 느리다
MyBatis가 더 빠르다
MyBatis가 더 빠르다
하지만 실제로는 JPA 자체가 느린 것이 아니라 잘못 사용하는 경우가 많습니다.
이번 글에서는 JPA가 느리다고 느껴지는 대표적인 이유와 실제 원인을 정리합니다.
1. N+1 문제
JPA 성능 문제의 90%는 N+1 문제입니다.
예를 들어
List<Order> orders = orderRepository.findAll();
그리고
order.getMember().getName();
이렇게 접근하면 실행되는 SQL은 다음과 같습니다.
SELECT * FROM orders
SELECT * FROM member WHERE id = 1
SELECT * FROM member WHERE id = 2
SELECT * FROM member WHERE id = 3
SELECT * FROM member WHERE id = 1
SELECT * FROM member WHERE id = 2
SELECT * FROM member WHERE id = 3
즉
1 + N
쿼리가 실행됩니다.
해결 방법
fetch join 사용
@Query("""
SELECT o FROM Order o
JOIN FETCH o.member
""")
SELECT o FROM Order o
JOIN FETCH o.member
""")
또는
@EntityGraph
사용.
2. Lazy Loading 오해
JPA 기본 전략
ManyToOne → EAGER
OneToMany → LAZY
OneToMany → LAZY
하지만 실무에서는 대부분 이렇게 변경합니다.
모든 관계 → LAZY
이유는
불필요한 JOIN 방지
입니다.
3. Dirty Checking 비용
JPA는 트랜잭션 종료 시
Dirty Checking
을 수행합니다.
즉
엔티티 변경 여부 검사
입니다.
대량 데이터 처리 시
10000 entities
이면 Dirty Checking 비용이 커집니다.
해결 방법
조회 트랜잭션
@Transactional(readOnly = true)
4. Persistence Context 메모리 증가
JPA는 조회한 엔티티를 1차 캐시(Persistence Context)에 저장합니다.
예
List<Order> orders = orderRepository.findAll();
만약
100000 rows
를 조회하면
메모리 증가
합니다.
해결 방법
배치 처리 시
flush
clear
clear
사용합니다.
5. 불필요한 SELECT
예
orderRepository.save(order);
이 경우 JPA는
SELECT
INSERT
INSERT
두 번 실행할 수 있습니다.
이유
merge 동작
때문입니다.
6. 잘못된 Fetch 전략
예
@OneToMany(fetch = FetchType.EAGER)
이 경우
JOIN 폭발
이 발생합니다.
결과
Cartesian Product
문제가 발생합니다.
7. JPA를 ORM이 아닌 SQL처럼 사용
JPA는
객체 그래프 관리
를 위한 도구입니다.
하지만 이렇게 사용하는 경우가 있습니다.
for (Order order : orders) {
orderRepository.save(order);
}
orderRepository.save(order);
}
결과
1000 UPDATE
이 실행됩니다.
실제로 JPA는 느린가?
대부분 경우
JPA = SQL 생성 도구
입니다.
JPA가 생성하는 SQL이
좋은 SQL이면 빠르고
나쁜 SQL이면 느립니다.
나쁜 SQL이면 느립니다.
즉
문제는 JPA가 아니라 SQL입니다.
JPA가 강력한 이유
JPA는 다음 기능을 제공합니다.
1차 캐시
Dirty Checking
지연 로딩
Entity Graph
JPQL
Dirty Checking
지연 로딩
Entity Graph
JPQL
이 기능을 잘 사용하면 SQL보다 더 효율적인 코드가 됩니다.
실무에서 추천 전략
JPA를 사용할 때 다음 규칙을 권장합니다.
모든 관계 → LAZY
조회 쿼리 → fetch join
readOnly 트랜잭션 사용
배치 처리 시 flush / clear
조회 쿼리 → fetch join
readOnly 트랜잭션 사용
배치 처리 시 flush / clear
정리
JPA 성능 문제는 대부분 다음에서 발생합니다.
N+1 문제
잘못된 Fetch 전략
대량 데이터 조회
잘못된 Fetch 전략
대량 데이터 조회
JPA 자체가 느린 것이 아니라 잘못 사용했을 때 느려집니다.
✔ 핵심 한 줄
JPA는 느린 것이 아니라
SQL을 잘못 생성하면 느려진다.
SQL을 잘못 생성하면 느려진다.
LIST
'DB' 카테고리의 다른 글
| MSA에서 PostgreSQL 단일 인스턴스 + 스키마 분리 전략, 어디까지 안전한가? (실무 관점 분석) (0) | 2026.03.18 |
|---|---|
| [Database] 스키마 관리의 두 철학: Prisma Migrate vs Flyway 전격 비교 (0) | 2026.03.17 |
| Spring Boot에서 @Transactional을 잘못 쓰면 생기는 7가지 문제 (0) | 2026.03.11 |
| Spring Boot에서 DB 커넥션 풀 크기를 계산하는 방법 (0) | 2026.03.11 |
| Spring Boot HikariCP 설정을 잘못하면 발생하는 5가지 장애 (0) | 2026.03.11 |
