Post

TIL(20240812) [Index는 무엇인가?]

TIL(20240812) [Index는 무엇인가?]

성능개선이 필요하다고 느꼈던 건 프론트 구현 직후였다.

챌린지 top10 조회시 ui가 늦게 그려진다는 느낌을 받았는데.. 거기서 부터 시작됫던 것 같다… 왜 느릴까..에서 부터 쿼리문이 잘못되었는가..살펴보니 불필요한 쿼리문이 나가는 것도 아니었고, 포스트맨으로 성능테스틑 했을 때 200ms 이하의 요청에 대한 응답속도가 나왔다. 그 당시에, 원인을 찾기가 너무 어려워 현재까지 미스테리이지만 하나 추측은.. 내가 실행 프로그램을 너무 많이 돌리고 있는 터라 컴퓨터가 힘들어 해서였나? 라고 .. 예측할 뿐이다. 현재, 아래 이미지를 봐도 나쁘지 않은 속도(빠르다?)라는 것이 확연히 보이기 때문이다.

(첫 구현 이후로 top10 백엔드 코드가 바뀌거나 프론트 코드가 바뀐적이 단 한번도 없다…😅)

image

그 이후 추가구현을 해야하는 할 때 포인트랭킹 조회를 구현하기 위해 QueryDSL로 작성했는데, 더미데이터를 넣으니 어마무시한 수치(유저500명 넣었고, 조회시 1600ms)가 나왔다.

queryDSL 말고 어떻게 성능적으로 개선할 수 있을까 생각했던게 인덱스였다. 작성했던 queryDSL문에는 내가 할 수 있는 가장 효율적인 쿼리라고 생각했다.. (추가쿼리가 나간다던지 그런 문제는 딱히 보지 못했다. @queryInjection을 사용해서 딱 유저테이블에서 point랑 nickname만 가져오게 했지만..성능적으로 개선이 안되는 듯 했다.) 이전 블로그 글에도 정리를 했지만 index에 대한 정리가 필요한 것 같아 다시 리마인드 하는 느낌으로 작성중이다.

그리고 이후 조회 관련된 API는 더미데이터를 넣고 다 테스트를 해볼 예정이다.

왜 내가 인덱스로 구현해볼 생각을 했을까?

💡 index?

  • 인덱스는 데이터베이스에 저장된 테이블 레코드를 빠르게 탐색하기 위한 자료구조다. 여기서 레코드를 빨리 탐색할 수 있는 이유는 미리 정렬이 되어있기 때문이다. (redis랑 좀 비슷한 개념인디?)

  • 예를 들어 우리가 책에서 내용을 찾을 때 목차를 보고 빠르게 내용을 찾을 수 있듯이 데이터베이스도 레코드를 검색할 때 index를 통해 찾게되면 더 빠르게 찾을 수 있게 되는 것이다.

  • 그런데 record의 쓰기(생성/수정/삭제)가 빈번히 일어나면 재정렬하거나 인덱스를 추가해주는 작업이 필요하기 때문에 오히려 성능이 떨어질 수 있다. 그래서 무조건적인 인덱스 생성보다는 SQL문을 효율적으로 작성한 후에 그래도 뭔가 개선이 안된다고 생각될 때 인덱스 사용을 고려해보는 것도 나쁘지 않다!

💡 index 적용 기준은?

  • index는 테이블에 데이터가 대용량이고 사용빈도가 높을 때 사용하는 것이 좋다. 사용빈도가 낮고 테이블도 작다면 인덱스를 구지 사용할 필요가 없다.

위에서 인덱스로 성능개선을 하려고 한 이유는 언급했었다. 사실 사용빈도가 point의 경우 크지 않다. 하지만 유저 테이블 자체가 크기 때문에 point를 조회할려고 하면 유저테이블 전체를 확인해야하기 때문에 인덱스를 적용하면 queryDSL과 어떤 성능면에서 차이가 발생하는지 궁금했다.

쿼리문이 나가는것도 추후에 캡처해서 올려보려고 한다.

1
2
3
4
// user entity
@Table(name = "db_users", indexes = {
    @Index(name = "idx_point", columnList = "point")
})

point열의 인덱스가 생성 되어 해당 열을 기반으로 정렬 및 필터링이 된다.

index를 생성한다는 것은 예를 들어 포인트 컬럼을 복사해서 인덱스로 미리 정렬시킨다고 볼 수 있다.

1
2
@Query("SELECT NEW com.bod.bod.user.dto.PointRankingResponseDto(u.nickname, u.point) FROM User u ORDER BY u.point DESC")
List<PointRankingResponseDto> findPointRanking();

해당 쿼리가 실행되면 데이터베이스는 유저테이블 자체를 전체조회하여 정렬하고 필터링하는 것이 아닌 idx_point를 활용해서 point열을 딱 집어서 정렬과 필터링을 하기 때문에 성능면으로 효율적일 수 있게된다.

정리 -> 즉, ‘point’ 열에 인덱스를 구현하면 더 빠른 행 정렬 및 검색이 가능하기에 쿼리 성능이 향상되고, 전체 테이블 스캔의 필요성을 줄일 수 있기에 I/O 및 실행시간을 최적화 할 수 있다.

인덱스 쿼리문 image image querydsl image image

쿼리문도 똑같이 날아가고,, 포스트맨 요청시 속도도 뭐.. 거의 비슷한데.. 얼핏보면 querydsl이 더 빠른거 같고.. 아.. 어렵다.. ㅎㅎㅎㅎㅎ;;

This post is licensed under CC BY 4.0 by the author.