DB - Index

데일리·2024년 11월 21일

TIL

목록 보기
11/16
post-thumbnail

우리가 쿼리를 짜다보면 필연적으로 생각해야할 것은 인덱스 생성이다. 이번에는 인덱스의 원리부터 장단점까지 파악해보자

인덱스란?

인덱스는 데이터베이스를 효율적으로 검색할 수 있도록 테이블의 특정 컬럼에 대한 별도의 데이터 구조를 생성하는 기술이다. 쉽게 말하면 인덱스는 책의 색인처럼 작동하여 원하는 데이터를 더 빠르게 찾도록 도와준다고 보면 된다.

인덱스의 원리

인덱스는 보통 B-Tree 또는 Hash 자료구조를 기반으로 만들어진다.

  • B-Tree 인덱스: 대부분의 데이터베이스에서 기본적으로 사용, 데이터가 정렬된 상태로 유지되어 범위 검색과 정렬 작업에서 유리함.
  • Hash 인덱스: 특정 키 값에 대한 빠른 검색에 유리, 범위 검색에는 적합하지 않음

데이터베이스는 테이블의 데이터를 정렬하여 인덱스를 생성하고, 특정 컬럼의 값과 해당 데이터가 저장된 위치를 매핑한다. 이 때 검색시 전체 테이블을 스캔하는 대신, 인덱스를 먼저 조회하여 필용한 데이터를 효율적으로 찾는 것이다.

장점

  1. 검색 성능 향상
  • 인덱스를 사용하면 데이터를 검색할 때 속도가 매우 빨라진다.
    예) 수백만 건의 데이터에서 특정 사용자 ID를 찾는 경우, 테이블 전체를 스캔할 필요 없이 인덱스만 참조하여 빠르게 결과를 얻을 수 있다.
  1. 정렬 및 범위 검색 효율
  • 정렬된 상태로 유지되므로 정렬이나, BEETWEEN, LIKE, ORDER BY 같은 범위 검색에 유리하다.
  1. 고유성 보장
  • Unique Index를 사용하면 특정 컬럼의 값이 중복되지 않음을 보장할 수 있다.

예시) 고객 관리 시스템에서 고객 ID에 인덱스를 설정하면 특정 고객 ID로 조회하는 작업이 훨씬 빨라진다.

단점

  1. 추가 저장 공간
  • 인덱스를 유지하려면 별도의 저장 공간이 필요하다, 즉 테이블이 클수록 인덱스가 커질 수 있다는 점을 유의해야 한다.
  1. 쓰기 작업의 성능 저하
  • 데이터를 삽입, 업데이트, 삭제할 때마다 관련된 인덱스를 수정해야 하므로 성능에 영향을 미칠 수 있다.
  1. 과도한 인덱스 사용
  • 너무 많은 인덱스를 사용하면, 쓰기 작업의 성능 저하와 저장 공간 증가로 이어질 수 있다.

예시) 매일 수백만 개의 트랜젝션 데이터가 추가되는 테이블에 과도한 인덱스를 설정하면, 삽입 작업이 느려지고 인덱스 크기 관리가 어려워질 수 있다.

인덱스 생성 시 Tips

  1. 자주 사용되는 컬럼에 인덱스를 생성
  • 조건문 사용: Where, Join, Order by, Group by와 같이 자주 검색에 사용되는 컬럼에 인덱스를 생성한다.
SELECT * FROM users WHERE email = 'example@example.com';

위의 쿼리가 주된 경우에는 email에 인덱스를 설정하면 검색 속도가 향상된다.

  1. 고유한 값이 많은 컬럼을 선택
  • 인덱스는 고유한 값이 많은 만큼 효과적이다.
    예시) 주민등록번호, 이메일 주소처럼 고유한 값이 많은 컬럼은 인덱스 효과가 크다.

  • 이에 반해 삽입/수정이 많은 컬럼에는 데이터가 변경될 때마다 인덱스가 업데이트되므로 쓰기 성능이 저하될 수 있기에 신중하게 선택해야 한다.

3. 🔥복합 인덱스

실무에서 가장 많이 사용하는 복합인덱스는 순서에 따라서도 인덱스 적용이 달라지기 때문에 신중하게 생성해야 한다.

  • 컬럼 순서를 신중하게 생각해야 하는데 만일 (A, B)로 인덱스가 생성되었을 경우
    where A = 10 또는 where A = 10 and B = 20 쿼리 모두 적용이 된다. 그러나 where B = 20 쿼리에는 적용이 안된다.

즉 왼쪽 부터 연속인 필드에 대해서는 인덱스를 사용할 수 있고 오른쪽으로부터는 사용이 불가하다는 것을 명심해야한다.

  • 검색 조건 패턴에 대해서도 순서에 따라 최적화 할 수 있는데
    검색 조건에서 정확한 비교(==)가 자주 사용되는 컬럼을 앞에 배치한다. 그리고 범위 검색(<, >, BETWEEN)이 자주 사용되는 컬럼을 뒤에 두어야 한다.

예시)

SELECT * FROM orders WHERE user_id = 123 AND order_date > '2024-01-01';

위와 같은 쿼리가 있다면 user_id, order_date 순으로 두어야 효율적이고, 또 user_id와 같은 경우에는 따로 단독 쿼리로도 사용이 되기 때문에 인덱스가 적게 생성될 수 있다.

  • 또 Order By 쿼리에서도 사용할 경우 최적화를 이끌어 낼 수 있다.
    이 필드에 경우 정확한 값 -> 범위 -> 정렬 조건 필드 순으로 인덱스를 생성하는 것이 유리 하다.

그 밖에도 Distinct, Join에서도 성능 최적화를 줄 수 있고 실무에서는 복합인덱스 사용을 피할 수가 없다.

복합 인덱스는 메모리 사용량이 적지 않으므로 적절하게 사용되야 하는데 이 때 팁은 생성하고 데이터베이스 실행 계획(EXPLAIN)을 사용하여 몇번의 key를 거쳤는지 몇번의 레코드들을 거쳤는지 확인해보고 성능 향상이 이뤄냈을 때 생성하는 것이 좋다.

  1. 사용하지 않은 인덱스의 경우 삭제
    인덱스는 저장 공간을 차지 하기 때문에 사용하지 않은 인덱스에 대한 주기적인 관리가 필요하다. 또한 Primary Key, Foreign Key에 대해서도 인덱스가 자동으로 생성되기 때문에 이러한 컬럼에 대해서는 인덱스를 중복해서 생성하지 않아도 되는 점을 생각해야 한다.

마무리

개발을 시작할 초기에는 인덱스의 중요성을 그렇게 많이 생각하지 못하고 쿼리를 짰던적이 많았다. 그러다가 대규모 파이프라인 개발을 해보고 내가 만든 쿼리에 인덱스 생성이 안되어 있어서 서버의 Pods이 죽어버린☠️ 그런 안타까운 사연을 한번 겪고 난 후에는 쿼리를 만들거나 엔티티를 만들 때 주로 사용되는 필드가 무엇인지 인덱스를 어떻게 생성해야할지 생각을 한다....

이 포스팅을 읽는 분들은 그러한 실수를 하지 않기를 바라며 이번 포스팅을 마친다~~

profile
하루에 한편 씩 읽기 좋은 테크 로그

0개의 댓글