대용량 데이터 처리 / 검색 성능 개

제이 용·2025년 12월 30일

목표

  • JDBC를 이용해 유저 데이터 500만 건 Bulk Insert

  • 닉네임으로 유저를 검색하는 API 구현

  • 검색 성능 병목을 분석하고 인덱스를 통해 개선

  • 성능 개선을 정량적 근거(EXPLAIN) 로 비교


대용량 데이터 생성 (JDBC Bulk Insert)

  • 구현 방식

  • JPA가 아닌 순수 JDBC + Batch Insert

  • PreparedStatement + executeBatch()

  • rewriteBatchedStatements=true 옵션 사용

  • 10,000건 단위 commit

String sql = "INSERT INTO users (nick_name) VALUES (?)";
PreparedStatement ps = con.prepareStatement(sql);

for (int i = 1; i <= 5_000_000; i++) {
    ps.setString(1, "nick_" + UUID.randomUUID());
    ps.addBatch();

    if (i % 10_000 == 0) {
        ps.executeBatch();
        con.commit();
        ps.clearBatch();
    }
}

깨달은 점

JPA로 500만 건 insert는 사실상 불가능

JDBC Batch + 옵션이 없으면 속도 & 메모리 문제 발생

테스트 코드로 데이터 생성하는 것은 “한 번 실행용”


테스트 환경 트러블 슈팅

  • ❌ OutOfMemoryError 발생
java.lang.OutOfMemoryError: Java heap space
  • 원인

    • batch size 과도

    • MySQL batch rewrite 미적용

    • Test JVM Heap 부족

  • 해결

    • batchSize 조절

    • rewriteBatchedStatements=true

    • 테스트는 한 번만 실행

    • ❌ 테스트 데이터가 사라지는 문제

  • 현상

    • 테스트에서 500만 건 생성

    • 애플리케이션 실행 시 데이터 사라짐

  • 원인

spring.jpa.hibernate.ddl-auto: create-drop

애플리케이션 실행 시 테이블 DROP


###정리

테스트 = 데이터 생성

애플리케이션 실행은 불필요

DB 확인은 SQL로 직접


닉네임 검색 API 구현

@GetMapping("/users")
public ResponseEntity<List<UserResponse>> search(@RequestParam String nickName) {
    return ResponseEntity.ok(userService.findByNickName(nickName));
}

List<User> findByNickName(String nickName);
  • 정확히 일치 검색 (=)

  • 랜덤 닉네임 → 실제 존재하는 값으로 테스트 필요


성능 병목 분석 (인덱스 적용 전)

EXPLAIN SELECT * FROM users WHERE nick_name = 'nick_xxxxx';
  • 결과
항목
typeALL
rows5,000,000
keyNULL
  • 의미

    • Full Table Scan

    • 모든 행을 순차 비교

    • 데이터 증가 시 성능 선형 악화


인덱스 적용

CREATE INDEX idx_users_nick_name ON users (nick_name);
  • 서비스 코드 변경 없이 SQL 인덱스만 추가

성능 개선 결과 (EXPLAIN 기준)

구분typerows
인덱스 전ALL5,000,000
인덱스 후ref1
  • 핵심 변화

    • ALL → ref

    • Full Scan 제거

    • B-Tree 인덱스 기반 탐색

ms보다 EXPLAIN이 중요한 이유

  • ms는 캐시·환경 영향 큼

  • 로컬 환경에서는 체감 어려움

  • EXPLAIN은 DB의 실행 전략 자체

  • 성능 개선의 증거는 “몇 ms 줄었다” 가 아닌 “접근 방식이 ALL → ref로 바뀌었다”


핵심 정리

500만 건 데이터 환경에서 닉네임 검색 시

인덱스 미적용 시 Full Table Scan이 발생했으며,

단일 컬럼 인덱스 적용만으로 조회 범위를 500만 → 1건으로 줄일 수 있었다.

느낀 점

대용량 데이터에서는 “동작함”보다 “어떻게 접근하는지”가 중요

성능 개선은 코드보다 DB 구조 설계가 핵심

인덱스는 단순하지만 가장 강력한 최적화 수단이다!!

빠이팅w(゚Д゚)w

10개의 댓글

comment-user-thumbnail
2025년 12월 30일

메모리 OutOfMemoryError 뜨신거 배치사이즈 자체를 줄이는 것도 좋지만 인텔리제이자체의 메모리를 증가시키는 방법도 있어요!
컴퓨터의 사양이 모자란게 아니시면 확인해보시고 적용해보시면 좋을 듯!

1개의 답글
comment-user-thumbnail
2026년 1월 4일

TIL 작성 기원 5일차 w(゚Д゚)w

1개의 답글
comment-user-thumbnail
2026년 1월 5일

도무지 올라오지않는 그의 til

1개의 답글
comment-user-thumbnail
2026년 1월 7일

2026년 1월 7일에 또 방문한 사람

1개의 답글
comment-user-thumbnail
2026년 1월 7일

이 글에 댓글이 10개 모이면 트러블슈팅 써주시나용?

1개의 답글