(진)커버링인덱스 vs 복합인덱스 성능측정

hyezuu·2025년 3월 12일

인덱싱

목록 보기
2/2
post-thumbnail

시작하며

두 가지 인덱스 전략을 JMeter로 테스트한 결과를 분석해보자. 동일한 데이터와 쿼리에 대해 각각 다른 인덱스 전략을 적용했을 때 성능이 어떻게 달라지는지 확인해보자.

테스트 환경

  • 데이터 수 약 100만
  • 동일한 쿼리 실행
  • 동일한 테스트 조건 (4,000개 요청)
  • 동일한 인덱스 컬럼 구성

생성되는 쿼리 (JPQL)

SELECT o.order_id,
       r.restaurant_id,
       r.name AS restaurant_name,
       c.food_type,
       m.name AS menu_name,
       o.order_status,
       o.order_type,
       o.created_at,
       o.updated_at
FROM p_order o
         JOIN p_menu m ON m.menu_id = o.menu_id
         JOIN p_restaurant r ON r.restaurant_id = m.restaurant_id
         JOIN p_category c ON c.category_id = r.category_id
WHERE o.user_id = 'testsec2'
  AND o.is_deleted = false
  AND o.order_status <> 'PENDING'
ORDER BY o.created_at DESC
LIMIT 10 OFFSET 0;

JMeter 결과 분석(커버링인덱스)

1. 주요 지표 해석

항목설명
표본 수 (Samples)4000총 요청 개수
평균 응답 시간2088ms요청당 평균 응답 시간
최소 응답 시간35ms최소 응답 시간 (비정상적으로 낮아 보임)
최대 응답 시간8507ms가장 오래 걸린 요청의 응답 시간
표준 편차878.35응답 시간 분포의 변동성
오류율 (%)0.00%실패율
처리량 (Throughput)35.2/sec초당 처리된 요청 수
수신 KB/초133.53 KB/s서버에서 클라이언트로 수신된 데이터량
평균 바이트 크기3888 bytes요청당 평균 데이터 크기
전송 KB/초12.50 KB/s클라이언트에서 서버로 전송한 데이터량

인덱스

@Table(name = "p_order", indexes = {
	@Index(name = "idx_porder_user_created_status",
		columnList = "user_id, created_at, is_deleted, order_status, menu_id, "
			+ "order_id, order_type, updated_at")
})

JMeter 결과 분석(복합인덱스)


1. 주요 지표 해석

항목설명
표본 수 (Samples)4000총 요청 개수
평균 응답 시간697ms요청당 평균 응답 시간
최소 응답 시간22ms최소 응답 시간 (비정상적으로 낮아 보임)
최대 응답 시간3551ms가장 오래 걸린 요청의 응답 시간
표준 편차428.11응답 시간 분포의 변동성
오류율 (%)0.00%실패율
처리량 (Throughput)137.2/sec초당 처리된 요청 수
수신 KB/초520.89 KB/s서버에서 클라이언트로 수신된 데이터량
평균 바이트 크기3888 bytes요청당 평균 데이터 크기
전송 KB/초46.63 KB/s클라이언트에서 서버로 전송한 데이터량

인덱스

@Table(name = "p_order", indexes = {
	@Index(name = "idx_porder_user_created_status",
		columnList = "user_id, created_at, is_deleted, order_status, menu_id, "
			+ "order_id, order_type, updated_at")
})

성능 비교 결과 요약

측정 항목커버링 인덱스복합 인덱스개선율
평균 응답 시간2088ms697ms67% 개선
최대 응답 시간8507ms3551ms58% 개선
처리량35.2/sec137.2/sec290% 향상
표준 편차878.35428.1151% 감소

주요 발견점

  1. 처리량의 극적인 향상: 복합 인덱스를 사용했을 때 초당 처리 요청 수가 약 4배 가까이 증가했다. 35.2/sec에서 137.2/sec로 향상되었다.

  2. 평균 응답 시간 대폭 감소: 평균 응답 시간이 2088ms에서 697ms로 약 67% 개선되었다. 이는 사용자 경험에 직접적인 영향을 미치는 중요한 지표다.

  3. 최악의 경우 시나리오 개선: 최대 응답 시간도 8507ms에서 3551ms로 크게 줄어들었다. 이는 시스템 안정성과 일관성 측면에서 중요한 개선점이다.

  4. 응답 시간 일관성 향상: 표준 편차가 878.35에서 428.11로 감소해 응답 시간의 변동성이 크게 줄었다. 이는 사용자들이 더 일관된 경험을 할 수 있음을 의미한다.

기술적 분석

두 테스트에서 동일한 인덱스 컬럼 구성을 사용했지만, 실제 데이터베이스 엔진에서 인덱스를 활용하는 방식에 차이가 있었던 것으로 보인다. 복합 인덱스 접근 방식이 주어진 쿼리 패턴에 훨씬 효율적으로 작동했다.

주어진 쿼리는 WHERE 절에서 user_id, is_deleted, order_status 조건을 사용하고 ORDER BY created_at DESC로 정렬하는데, 복합 인덱스 구성에서 이 조건들이 최적화되어 처리된 것으로 판단된다.

WHERE o.user_id = 'testsec2'
  AND o.is_deleted = false
  AND o.order_status <> 'PENDING'
ORDER BY o.created_at DESC

인덱스 순서가 user_id, created_at, is_deleted, order_status...로 되어 있어, WHERE 조건에 맞는 행을 빠르게 찾고 created_at으로 정렬된 결과를 효율적으로 가져올 수 있었다.

결론

이번 테스트 결과는 적절한 인덱스 전략이 데이터베이스 성능에 얼마나 큰 영향을 미칠 수 있는지 명확하게 보여준다. 복합 인덱스 접근 방식은 커버링 인덱스에 비해 약 3-4배 더 나은 처리량과 67% 더 빠른 응답 시간을 제공했다.

실제 프로덕션 환경에서는 이런 성능 차이가 서버 자원 활용, 사용자 경험, 그리고 시스템 확장성에 상당한 영향을 미칠 수 있다. 따라서 데이터베이스 쿼리 패턴을 면밀히 분석하고 그에 맞는 최적의 인덱스 전략을 수립하는 것이 중요하다.

번외 인덱스(x) VS 커버링 인덱스 VS 복합 인덱스

측정 항목인덱스 없음커버링 인덱스복합 인덱스
표본 수4,0004,0004,000
평균 응답 시간6,306ms2,088ms697ms
최소 응답 시간232ms35ms22ms
최대 응답 시간15,287ms8,507ms3,551ms
표준 편차1,687.58878.35428.11
오류율 (%)0.00%0.00%0.00%
처리량 (Throughput)28.0/sec35.2/sec137.2/sec
수신 KB/초106.25 KB/s133.53 KB/s520.89 KB/s
평균 바이트 크기3,888 bytes3,888 bytes3,888 bytes
전송 KB/초9.95 KB/s12.50 KB/s46.63 KB/s

이 표를 통해 인덱스 없음 → 커버링 인덱스 → 복합 인덱스로 가면서 성능이 점진적으로 향상되는 것을 명확하게 볼 수 있다. 특히 복합 인덱스의 경우 인덱스가 없는 상황에 비해 처리량이 약 5배 향상되고, 평균 응답 시간은 약 9배 단축되었다.

커버링인덱스는 사실 단일 테이블의 모든 컬럼에 인덱스를 걸어줘야하는데, 결국 join해서 찾아야하다보니 이런 결과가 나왔다.
성능이 더 안좋은 그냥 복합인덱스, 잘못걸린 인덱스의 사례가 아닐까 싶다.

profile
기록

0개의 댓글