1. 한 번에 처리하기 -> 작게 나눠서 천천히 처리하기
Cursor-based 예제
Bad case : 모두 조회, 모두 처리
List<Data> allData = repository.findAll();
processAll(allData);
Good case : Cursor 방식으로, 배치 사이즈로 조회하여, 부분처리
Long lastId = 0L;
int batchSize = 1000;
while (true) {
List<Data> batch = repository.findBatch(lastId, batchSize);
if (batch.isEmpty()) break;
processAll(batch);
lastId = batch.get(batch.size() - 1).getId();
}
@Query(value = "SELECT * FROM data_table WHERE id > :lastId ORDER BY id ASC LIMIT :limit", nativeQuery = true)
List<Data> findBatch(@Param("lastId") Long lastId, @Param("limit") int limit);
시간순서의 처리가 필요한 경우 (createdAt + id 복합 커서)
LocalDateTime lastCreatedAt = LocalDateTime.of(2023, 1, 1, 0, 0);
Long lastId = 0L;
int batchSize = 1000;
while (true) {
List<Data> batch = repository.findNextBatch(lastCreatedAt, lastId, PageRequest.of(0, batchSize));
if (batch.isEmpty()) break;
processAll(batch);
Data last = batch.get(batch.size() - 1);
lastCreatedAt = last.getCreatedAt();
lastId = last.getId();
}
@Query("""
SELECT d FROM Data d
WHERE (d.createdAt > :lastCreatedAt)
OR (d.createdAt = :lastCreatedAt AND d.id > :lastId)
ORDER BY d.createdAt ASC, d.id ASC
""")
List<Data> findNextBatch(@Param("lastCreatedAt") LocalDateTime lastCreatedAt,
@Param("lastId") Long lastId,
Pageable pageable);
요약 정리
1. 대용량 처리 시 id 커서 방식은 간단하고 빠름
2. createAt + id 커서는 정렬 기준이 중요할 때 안정적
'CS 정리' 카테고리의 다른 글
Java wrapper class and caching, boxing & unboxing (0) | 2025.04.24 |
---|---|
Java 대용량 데이터 처리 (2) - Stream 메모리 효율 높이기 (0) | 2025.04.20 |
Java 대용량 데이터 처리(0) (0) | 2025.04.19 |
STW, Stop the world 제어하기 (2) | 2025.04.13 |
메세지 큐, Message Queue (0) | 2025.04.13 |