프로젝트

인덱스를 적용해보자

dlxortmd123 2023. 5. 13. 20:46

개요

해당 포스팅은 오디고 프로젝트를 하던 도중 발생한 이슈를 정리한 글입니다.

 

프로젝트에서 스크래핑한 데이터를 조회하는 부분이 있는데, 데이터를 추가한 후 갑자기 timeout 에러가 발생했습니다.

 

원인을 찾아보니 스크래핑한 데이터를 저장한 테이블을 조회하는 과정에서 시간이 오래 걸려 발생한 문제로 파악되었습니다.

 

이를 해결하기 위해 인덱스를 적용하고자 합니다.

 

저는 해당 프로젝트를 JPA를 이용했는데요.

먼저 문제가 됐던 JPQL문을 살펴보겠습니다.

 

select new podo.odeego.domain.path.dto.PathInfo(p.startStation, p.endStation, p.requiredTime, p.stations)
from Path p
where p.startStation in :stationNames

 

이 코드는 Path 테이블에서 주어진 역을 시작역으로 하는 경로들을 조회하는 쿼리입니다.

 

Path 테이블의 스키마는 다음과 같습니다. 지하철 출발역과 도착역 사이의 경로 데이터를 저장한 테이블입니다.

pk start_station(출발역) end_station(도착역) required_time(해당 경로의 소요 시간) stations(해당 경로의 지하철역)
bigint varchar(255) varchar(255) int longtext

 

해당 테이블에는 모든 지하철역의 경로가 모두 들어가있습니다.

 

(강남역, 홍대역), (홍대역, 강남역), (강남역, DMC역)과 같이 (출발역, 도착역)으로 하는 모든 조합을 저장해놓았습니다.

 

수도권의 역이 약 770개가 존재하므로, 60만개(770 * 769 / 2) 정도의 조합이 존재합니다.

 

모든 데이터를 한번에 스크래핑할 수 없어, 순차적으로 데이터를 삽입했습니다.

 

하지만 데이터가 20만개가 넘어갔을 때 연동 테스트를 하던 도중 timeout 에러가 발생했습니다.

 

인덱스 적용 전

여기까지 서론이었고, 인덱스를 적용하기 전 기존 상태에서는 얼마나 걸리는지 확인해보겠습니다.

 

테스트는 JMeter를 통해 진행했습니다.

(테스트 환경은 로컬에서 진행했고, 5초에 걸쳐 300개의 API를 요청했습니다.)

 

평균 약 2000ms로 API 응답 속도가 측정되었습니다.

로컬 컴퓨터가 배포된 서버 컴퓨터(AWS 프리티어)보다 빠른 것을 고려하면, EC2에서 더 느릴 것으로 예상됩니다.

 

단일 인덱스 적용

그럼 이제 Path 테이블에 인덱스를 적용해보겠습니다.

 

해당 테이블에 인덱스를 적용하기 위해 테이블을 조회하는 쿼리의 where 및 join 조건을 확인해보았습니다.

 

각 조건들에 있는 칼럼들의 카디널리티를 고려했을 때 출발역 칼럼이 가장 적합하다고 생각이 들어 해당 칼럼에 적용해보겠습니다.

 

create index path_start_index
on path (start_station);

 

인덱스를 적용한 후 실행 계획을 확인해보겠습니다.

Index Range Scan을 한 것을 볼 수 있습니다.

 

추가로 인덱스 적용전 실행 계획을 확인해보면 당연히 Table Full Scan을 하는 것을 볼 수 있습니다.

 

그럼 인덱스를 적용했을 때 실제 응답 속도는 얼마나 개선되었을까요?

위와 같이 응답 속도가 101ms로 상당히 개선된 것을 볼 수 있습니다.

 

회고

사실 인덱스에 대해 개념적으로는 알고 있었지만 실제로 사용하는 것은 처음이다보니 얼마나 효용성을 가지는지는 모르고 있었습니다.

막상 사용해보니 성능 개선율이 매우 빠른 것을 알 수 있었습니다.

 

해당 테이블은 일단 데이터가 모두 추가가 되면 데이터를 변경하거나 추가할 일이 없어 인덱스를 적용하기에 더 적합했던 것 같습니다.