레거시 Hibernate 환경에서 대량 INSERT 성능 개선하기

wjd15sheep·2026년 4월 13일

프로젝트

목록 보기
11/11

레거시 Hibernate 환경에서 대량 INSERT 성능 개선하기

자바 주니어 개발자로 이제 8개월 차가 되었다.
현재 유지보수를 맡고 있는 기존 웹 서비스와, 새롭게 메인으로 담당하게 된 심평원 연계 서비스를 운영하고 있다.

심평원 연계 서비스는 전체 시스템 중 일부이지만, 그중에서도 핵심이 되는 중요한 서비스다.

이번 포스트에서는 해당 서비스 중 하나인 파일을 읽어 DB에 insert할 때 발생한 지연 문제와, 이를 어떻게 개선했는지에 대해 정리해보려고 한다.


문제 기능 로직

  • 기능: 파일 하나를 읽고 내용을 DB에 insert

내부 로직

  1. 파일 경로에 파일 존재 여부 확인
  2. 파일을 읽고 파일 명칭 기준으로 내역 생성
  3. 파일을 한 줄씩 파싱하여 DTO로 변환
  4. 중복 제거
  5. DB insert
  6. 프로세스 종료

문제 상황

해당 기능을 실행하는 데 시간이 과도하게 소요되었다.

  • 개발 서버 기준
  • 55,000줄 파일 처리
  • 7시간 소요

→ 명확한 성능 문제가 존재했다.


문제 분석

1. 중복 제거 로직

기존 로직은 리스트를 이중 반복문으로 비교하며 중복을 제거하는 구조였다.

for (int i = 0; i < list.size(); i++) {
    for (int j = 0; j < list.size(); j++) {
        if (i != j && list.get(i).equals(list.get(j))) {
            // 중복 제거
        }
    }
}

문제점

  • 시간복잡도: O(n²)
  • 데이터가 많아질수록 기하급수적으로 성능 저하 발생

2. insert 트랜잭션 문제

insert 과정에서도 이상한 점을 발견했다.

  • 1000건 단위로 로그 확인
구간소요 시간
초반약 2분
후반약 9분

뒤로 갈수록 점점 느려지는 현상 발생


해결

문제는 크게 두 가지였다.

  1. 중복 제거 (O(n²))
  2. insert 성능 (Hibernate 구조)

1. 중복 제거 개선

개선 방법

Set을 활용하여 중복 제거

Set<Dto> set = new HashSet<>(list);
List<Dto> distinctList = new ArrayList<>(set);

개선 효과

  • 시간복잡도
    O(n²) → O(n)

  • 대량 데이터에서 체감 성능 크게 향상


2. insert 성능 개선

기존 코드

for (int j = 0; j < list.size(); j++) {
    dao.save(list.get(j));
}

문제 원인

Hibernate의 영속성 컨텍스트 누적

  • save() 호출마다 엔티티가 세션에 계속 쌓임
  • 메모리 증가
  • dirty checking 비용 증가
  • flush 시 한 번에 처리 → 뒤로 갈수록 느려짐

해결 방법

핵심: 일정 건수마다 flush() / clear() 수행

for (int j = 0; j < list.size(); j++) {
    dao.save(list.get(j));

    if ((j + 1) % 100 == 0) {
        dao.flush();
        dao.clear();
    }
}

dao.flush();
dao.clear();

flush / clear 설명

  • flush

    • Hibernate 세션에 쌓인 SQL을 DB에 실제 반영
  • clear

    • 영속성 컨텍스트 초기화 (메모리 해제)

왜 같이 사용해야 하는가?

  • flush만 사용 → 메모리 계속 증가
  • clear만 사용 → DB 반영 안됨

👉 반드시 flush + clear를 함께 사용해야 의미 있음


개선 결과

개선 전

  • 55,000건 → 약 7시간

개선 후

  • 55,000건 → 약 5분

체감 변화

  • 속도가 일정하게 유지됨
  • 뒤로 갈수록 느려지는 현상 제거
  • 메모리 사용 안정화

느낀 점

1. “돌아가는 코드”와 “잘 돌아가는 코드”는 다르다

기능적으로는 문제가 없었지만,
데이터가 많아지자 구조적인 문제가 드러났다.


2. 자료구조 하나로 성능이 바뀐다

  • List + 이중 for문 → O(n²)
  • Set → O(n)

차이는 단순하지만 결과는 매우 크다.


3. ORM은 내부 동작을 이해하고 사용해야 한다

  • 세션 관리
  • flush 타이밍
  • 엔티티 누적

이 구조를 이해하지 못하면 성능 문제가 발생한다.


한 줄 정리

대량 데이터 처리에서는 “구조”가 성능을 결정한다.

profile
성장 위해 노력하는 웹 개발자 주니어

0개의 댓글