Skip to content

Refactor: video테이블에 count 칼럼에 인덱스 부여#138

Merged
Munhangyeol merged 2 commits intoICT-Dev-Route:mainfrom
Munhangyeol:main
Jan 5, 2025
Merged

Refactor: video테이블에 count 칼럼에 인덱스 부여#138
Munhangyeol merged 2 commits intoICT-Dev-Route:mainfrom
Munhangyeol:main

Conversation

@Munhangyeol
Copy link
Contributor

@Munhangyeol Munhangyeol commented Jan 5, 2025

🔎 작업 내용

  • video 테이블에 count 칼럼에 인덱싱 부여

  • 자세한 내용은 아래에

findTop3Videos() 메서드 리팩토링

페이징 기법에 대한 고려

원래 리팩토링을 위해서 페이징 기법을 사용하려고 했으나, 현재의 비즈니스 로직과 맞지 않음을 공부하는 과정에서 알게 되었다.
페이징 기법은 게시판에서 전체 데이터를 그때 그때 보여주는 게 아닌, 게시판에 보여지는 데이터의 갯수만 서버단에서 클라이언트단으로 넘겨줌으로써 (이 때 넘겨주는 데이터 리스트의 단위를 페이지라고 한다), 훨씬 나은 성능을 제공하는 기법이다.
따라서 현재 최적화하려는 findTop3Videos의 경우와는 다르다.
findTop3Videos는 시작 페이지에서만 상위 조회수 3개의 비디오를 보여주는 경우이므로, 위처럼 페이지 단위의 리스트를 클라이언트 단으로 넘겨줄 이유가 없음을 알게 되었다.

인덱싱 도입

Spring Data JPA에서는 단순한 SQL의 OrderByLimit의 기능을
findTop3ByOrderByCountDesc()처럼 TopLimit의 기능을, OrderByOrderByCountDesc를 통해서 이름을 정의함으로써 기능을 만들 수 있다.
findTop3ByOrderByCountDesc()은 다음과 같은 쿼리를 만든다.

Select * From videos order by count desc limit 3

이 쿼리 내에서는 우선 정렬을 하고, 상위 3개의 결과를 반환하는데, MySQL 옵티마이저는
정렬 시 indexing이 안 되어있으면 버퍼에 데이터를 넣어두고 정렬하는 filesort를 사용한다.
하지만 인덱싱을 활용하면 sort를 거치지 않고, 결과를 반환하기에 더 빠른 결과를 가져올 수 있다.
현재 count에 대한 인덱싱이 되어 있지 않아, 레코드 수가 많아지면 정렬 과정을 거쳐야 하므로 느려질 수밖에 없다.

따라서 count에 대해서 인덱스를 적용해보고자 한다.

추가 공부 사항

인덱싱 성능 테스트

video table에서 count를 인덱싱 적용한 것이다.
성능 테스트는 SHOW PROFILES;를 통해서 쿼리문 수행 시간을 비교할 것이다.

인덱싱 적용

인덱싱 적용 코드

@Entity
@Getter
@Table(indexes = @Index(name="idx_count", columnList = "count"))
public class Videos {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "video_id")
    private Long id;
    @Column(length = 2048)
    private String url;
    private String title;
    @Column(length = 2048)
    private String thumbnail_url;
    private Long price;
    @Column(name = "video_rank")
    // 추가 필드 생략
}

@Index 속성

속성 설명
name 인덱스 이름. 데이터베이스에서 인덱스를 식별할 때 사용.
columnList 인덱스를 적용할 컬럼들. 여러 컬럼을 콤마로 구분하여 설정 가능.
unique true로 설정하면 인덱스를 유니크 인덱스로 생성. 기본값은 false.

총 갯수가 1000개일 때

인덱싱 적용 전

image

image

인덱싱 적용 후

image

쿼리 성능이 0.001040.00033으로 향상됨을 확인.


총 갯수가 10000개일 때

인덱싱 적용 전

image

image

인덱싱 적용 후

image

인덱스 적용 전 0.009398에서 적용 후 0.00033으로
속도가 매우 향상됨을 확인.


총 갯수가 100000개일 때

인덱싱 적용 전

image

image

인덱싱 적용 후

image

0.056sec0.00037sec정렬 속도가 크게 개선.
인덱스 적용 전에는 MySQL이 테이블의 모든 데이터를 읽고 정렬한 후, 상위 3개의 결과를 반환.
반면 인덱스를 적용하면, 정렬 없이 range index scan을 사용하여 쿼리를 훨씬 빠르게 수행.


조건에 맞는 로우의 갯수가 많아지면?

데이터가 1000개일 때

쿼리

SELECT * FROM videos ORDER BY count DESC LIMIT 300;

조건에 맞는 로우의 갯수가 많아질 때의 결과 분석

적용 전

image

image

적용 후

image

성능 상 큰 차이가 나지 않음을 확인.


결과에 대한 고찰

image (1)

조건에 맞는 로우의 갯수가 전체 데이터 비율 중 적은 경우

  • 조건에 맞는 로우의 비율이 전체 데이터의 20~25% 이하일 때 인덱스 사용이 효율적이다.
  • 데이터의 규모가 커질수록 성능 이점이 더욱 커지며, 정렬의 비용이 감소한다.

조건에 맞는 로우의 갯수가 전체 데이터 비율 중 많은 경우

  • 조건에 맞는 로우의 비율이 20~25%를 초과하면, 인덱스 사용의 성능 차이가 크지 않거나 오히려 느릴 수 있다.
  • 이 경우, 공간상의 이점을 위해 인덱스를 사용하지 않는 것이 더 적합하다.

원인 분석

  1. 랜덤 IO 발생

    • 인덱스를 통해 찾은 각 레코드 주소를 기반으로 데이터를 접근하는 과정에서 랜덤 IO가 발생한다.
    • 디스크의 비연속적 위치를 읽게 되어 성능 저하를 초래한다.
  2. 오버헤드 증가

    • 데이터 범위가 넓어질수록 랜덤 IO가 반복적으로 발생하여 성능 저하와 오버헤드 증가를 유발한다.
  3. 순차 접근의 효율성

    • 조건에 맞는 데이터가 많을 경우, 인덱스를 사용하는 것보다 순차적으로 데이터를 읽는 방식이 더 빠르고 효율적이다.

결론

  • 인덱스 사용의 적합성은 데이터 비율과 크기에 따라 달라진다.
    • 데이터의 일부만 접근하는 경우에는 인덱스 사용이 성능에 큰 도움이 된다.
    • 그러나 조건에 맞는 데이터가 전체 데이터의 상당 부분을 차지하면, 인덱스 사용은 큰 이점을 제공하지 않는다.

참고 출처

@Munhangyeol Munhangyeol merged commit c3d30a9 into ICT-Dev-Route:main Jan 5, 2025
1 check failed
@Munhangyeol Munhangyeol added 🆙새로운 기능 추가된 기능이 있어요 ✨리팩토링 리팩토링된 부분이 있어요 labels Jan 5, 2025
@Munhangyeol Munhangyeol changed the title Refactor: video테이블에 count 칼럼에 인덱싱 부여 Refactor: video테이블에 count 칼럼에 인덱스 부여 Jan 7, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

✨리팩토링 리팩토링된 부분이 있어요 🆙새로운 기능 추가된 기능이 있어요

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant