[JPA] DB Index 개념과 JPA에서 Index 설정하기

HeavyJ·2023년 5월 6일
2

자바/스프링부트

목록 보기
7/17

스터디에서 DB Index와 관련된 테코톡을 다 같이 시청했는데 JPA에서는 어떻게 적용하는지가 궁금해졌습니다.

Index 우아한 테코톡 영상

인덱스의 개념을 알아보고 JPA로 어떻게 인덱스를 사용하는지에 대해서 작성해보겠습니다!!

인덱스

인덱스가 필요한 이유

테이블에 100만개의 데이터가 존재하다고 가정해봅시다.
joonghyun 이라는 사람이 들어있는 데이터를 찾을 때 컴퓨터는 처음부터 끝까지 데이터를 검색하게 됩니다. 만약 초반부에 joonghyun 데이터가 있다면 다행이겠지만, 후반부에 존재한다면 검색에 오랜 시간이 걸립니다.

그런데, 여기서 만약에 블로그의 목차처럼 목차가 존재한다면 검색 시간이 훨씬 단축되지 않을까? 에서 고안된 개념이 인덱스입니다.

select * from user where user_name = joonghyun;

이라는 검색 구문이 있을 경우 만약 user name에 해당하는 인덱스가 있다면 검색이 훨씬 빨리 될 것입니다.

create index user_name_index on user(user_name);

여기서 index는 user_name의 주소값을 저장하는 별도의 특별한 자료구조입니다.
즉, user_name 컬럼에 대한 index가 존재하면 테이블 전체를 탐색하지 않고 해당 index를 바탕으로 joonghyun의 위치를 빠르게 검색할 수 있습니다.

인덱스 자료 구조

Hash Table

해시 테이블은 Key - Value로 이루어진 데이터를 저장하는데 특화된 자료 구조입니다.
예를 들어, user_name에 대한 인덱스를 만든다고 했을 때 user_name(key)과 주소값(value)로 이루어진 해시 테이블을 만든다면 너무 합리적일 것 같습니다!

하지만, 해시 테이블은 안타깝게도 인덱스 자료구조로 쓰이는 경우가 적다고 합니다.

  1. 부적절한 해시 함수로 인해 중복된 해시 값이 발생해 해시 충돌이 일어날 경우에는 시간 복잡도가 O(N)까지 상승할 수 있습니다. -> 중복된 이름이 많은 경우 해시 충돌이 지속적으로 발생하겠죠??

  2. 등호 연산에만 효율적이고 부등호 연산에는 부적합합니다. user_name 처럼 등호 연산만 사용할 수도 있지만 부등호 연산이 필요한 컬럼에는 부적합합니다.

B-Tree

B-Tree는 자식 노드가 2개 이상인 트리입니다. 각 key의 왼쪽 자신은 항상 key 보다 작은 값을, 오른쪽 자식은 큰 값을 가집니다. B-Tree를 인덱스로 사용한다면 user_name(key)로 하고 데이터의 위치(value)로 저장합니다. 그리고, B-Tree는 항상 key를 기준으로 오름차순 정렬입니다. 때문에, 부등호 연산에 대해 해시 테이블보다 효율적인 데이터 탐색이 가능합니다!

하지만, 테이블에 데이터가 갱신(Insert, Update, Delete)가 많이 발생하면 트리의 균형이 깨져버려 성능이 악화됩니다. 추가로, 순차검색을 해야 할 경우 중위 순회를 하기 때문에 검색 효율이 좋지 않습니다.

이러한 이유 때문에 MySQL 엔진인 InnoDB는 B-Tree를 확장/개선한 B+Tree를 인덱스의 자료 구조로 사용합니다.

B+Tree

B+Tree는 말단의 리프 노드에만 데이터의 위치를 관리합니다. 중간 브랜치 노드에 value가 없기 때문에 B-Tree보다 메모리를 덜 차지하고 노드의 메모리에 더 많은 key를 저장할 수 있습니다. 때문에 트리의 높이가 낮아져서 검색 속도가 증가합니다.

인덱스 대상 컬럼 선정하기

카디널리티가 높은 컬럼을 우선적으로 인덱싱하는 것이 좋습니다.
카디널리티란 중복도가 낮은 것입니다! 다른 의미로 유니크한 값의 개수입니다.

  • 남 - 여 2가지 값만 존재하는 성별 컬럼의 경우 중복도가 높기 때문에 카디널리티가 낮습니다.
  • 주민번호 컬럼은 중복도가 낮기 때문에 카디널리티가 높습니다.

카디널리티가 높은 컬럼일수록 인덱스를 통해 데이터를 더 많이 필터링할 수 있습니다.

JPA에서 Index를 설정하는 방법

테이블 컬럼을 index로 설정하기

@Entity
@Table(name = "post_table", indexes = @Index(name = "idx_post_title", columnList = "post_title"))
public class Post{
	@Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "post_title", nullable = false)
    private String postTitle;
    
    @Column(name = "post_content", nullable = false)
    private String postContent;
    
}

이렇게 Entity 클래스에서 post_title 컬럼에 대해 인덱스를 설정해주게 되면 아래의 그림같이 인덱스가 테이블에서 설정이 된 걸 확인할 수 있습니다.

index에 unique 속성 추가하기

만약 unique 속성을 걸고 싶다면 unique = true 옵션으로 unique index로 생성이 됩니다.

@Entity
@Table(name = "post_table", indexes = @Index(name = "idx_post_title", columnList = "post_title", unique = true))
public class Post{
	@Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "post_title", nullable = false)
    private String postTitle;
    
    @Column(name = "post_content", nullable = false)
    private String postContent;
    
}

Non_unique가 0으로 바뀌면서 unique index가 됩니다

두 개의 컬럼으로 인덱스 만들기

두 개의 컬럼으로 하나의 인덱스를 만들 수 있습니다.

@Entity
@Table(name = "post_table", indexes = @Index(name = "idx_post_title_and_content", columnList = "post_title, post_content"))
public class Post{
	@Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "post_title", nullable = false)
    private String postTitle;
    
    @Column(name = "post_content", nullable = false)
    private String postContent;
    
}

같은 이름을 가진 인덱스가 생성된 것을 확인할 수 있습니다. seq 번호로 title과 content가 분류되는 것 같습니다.

테스트

데이터 10000개 넣고 9990번째 데이터 찾기

인덱스를 걸지 않은 경우

검색 시간 : 120ms

인덱스를 post_title로 설정한 경우

검색 시간 : 103ms

검색 속도 약 17% 상승


데이터 100000개 넣고 99900번째 데이터 찾기

인덱스를 걸지 않은 경우

검색 시간 : 209ms


인덱스를 post_title로 설정한 경우

검색 시간 : 134ms

검색 속도 약 56% 상승


확실히 인덱스를 설정하니까 검색속도가 빨라진다는 것을 확인할 수 있습니다.

이렇게 JPA를 사용해서 컬럼에 index를 설정하는 방법에 대해서 알아봤습니다.

비약적으로 속도가 증가하다 보니까 검색을 자주하는 컬럼에 적용을 한다면 확실한 성능 개선은 보장될 것 같네요 👍

profile
There are no two words in the English language more harmful than “good job”.

2개의 댓글

comment-user-thumbnail
2023년 5월 8일

영상 외의 내용도 굉장히 많이 추가해서 정리해주셨네요 👍👍👍
정리 굉장히 잘 해주셔서 Index 공부하는데 많이 도움될 것 같아요 감사합니다 !

1개의 답글