2026.03.27 - [Spring 2기 과제] - 포인트 기반 커피 주문 결제 시스템 (도메인 설계)
포인트 기반 커피 주문 결제 시스템 (도메인 설계)
https://github.com/Banhklo2/coffee-order-system.git GitHub - Banhklo2/coffee-order-system: Spring Boot 기반 포인트 기반 커피 주문 결제 시스템Spring Boot 기반 포인트 기반 커피 주문 결제 시스템. Contribute to Banhklo2/coffee-o
sudaruuu.tistory.com
문제 상황
인기 메뉴 조회 기능을 구현하면서,
최근 7일 데이터를 기준으로 주문 정보를 조회하는 로직을 작성했다.
public List<PopularMenuResponse> getPopularMenus() {
LocalDateTime sevenDaysAgo = LocalDateTime.now().minusDays(7);
return menuRepository.findPopularMenus(sevenDaysAgo, PageRequest.of(0, 3));
}
해당 로직은 내부적으로 다음과 같은 조건을 사용한다.
WHERE created_at >= NOW() - INTERVAL 7 DAY
하지만 이 경우, 데이터가 많아질수록
Order 테이블 전체를 탐색해야 하는 구조이기 때문에 성능 저하가 발생할 수 있다.
원인 분석
인덱스가 없는 상태에서는 DB가 조건을 만족하는 데이터를 찾기 위해
테이블 전체를 순회하는 풀 테이블 스캔(Full Table Scan)이 발생한다.
즉, 다음과 같은 비효율적인 방식으로 동작한다.
- 모든 Order 데이터를 조회
- created_at 조건을 하나씩 비교
- 최근 7일 데이터 필터링
데이터가 많아질수록 조회 성능이 급격히 저하될 수 있다.
해결 방법
created_at 컬럼에 인덱스를 추가하여
최근 7일 데이터를 빠르게 조회할 수 있도록 개선했다.
@Entity
@Table(
name = "orders",
indexes = {
@Index(name = "idx_order_created_at", columnList = "created_at")
}
)
public class Order extends BaseEntity {
}
또한 BaseEntity의 컬럼명을 명시하여 DB 컬럼과의 일관성을 확보했다.
@CreatedDate
@Column(name = "created_at", updatable = false, nullable = false)
private LocalDateTime createdAt;
테스트 및 검증
1️⃣ EXPLAIN을 통한 실행 계획 확인
인덱스가 실제로 사용되는지 확인하기 위해 다음 쿼리를 실행하였다.
EXPLAIN
SELECT *
FROM orders
WHERE created_at >= NOW() - INTERVAL 7 DAY;
2️⃣ 실행 결과

3️⃣ 결과 분석
- key: idx_order_created_at
⭐ created_at 인덱스가 사용됨 - type: range
⭐ 인덱스를 활용한 범위 조회 수행
즉, Order 테이블 전체를 조회하는 것이 아니라
인덱스를 기반으로 최근 7일 데이터만 효율적으로 탐색하도록 개선되었다.
개선 효과
- 풀 테이블 스캔 → 인덱스 기반 조회로 변경
- 조회 범위를 전체 데이터 → 최근 7일 데이터로 축소
- 인기 메뉴 조회 성능 개선
핵심 개념 정리
인덱스 + 범위 조건 → range scan 발생
WHERE created_at >= ?
이와 같이 범위 조건이 있을 경우,
DB는 인덱스를 활용한 range scan 방식으로 데이터를 조회한다.
정리
- created_at 컬럼에 인덱스를 추가하여 조회 성능을 개선하였다.
- EXPLAIN을 통해 실제 인덱스 사용 여부를 확인하였다.
- range scan을 통해 불필요한 전체 탐색을 줄일 수 있었다.
⭐ 성능 개선 작업에서는
단순히 "인덱스를 추가했다"가 아니라
실제로 인덱스가 사용되는지 검증하는 과정이 중요하다는 것을 확인할 수 있었다.
느낀 점
인덱스를 단순히 추가하는 것에서 끝나는 것이 아니라,
실제로 실행 계획을 통해 인덱스가 사용되는지 검증하는 과정이 중요하다는 것을 이해하게 되었다.
'트러블슈팅' 카테고리의 다른 글
| 인덱스 적용 이후에도 느렸던 이유 - 캐싱 도입 (0) | 2026.04.02 |
|---|---|
| Request DTO에 @Builder를 쓰면 안 되는 이유 (0) | 2026.04.01 |
| 포인트 차감 동시성 문제 해결 - 비관적 락 적용 (0) | 2026.04.01 |
| 주문 완료 후 외부 전송을 이벤트 기반으로 분리하며 겪은 문제 (0) | 2026.03.31 |
| 외부 API 호출 비동기 처리 적용 (@Async) (0) | 2026.03.31 |