DB 인덱스를 효과적으로 설정하는 법

GonnabeAlright·2022년 4월 25일
1
post-thumbnail
post-custom-banner

DB에는 여러 개의 테이블이 존재하고 그 테이블에는 다양한 수의 데이터가 쌓입니다. 만약 천 만개의 데이터가 쌓였다고 가정할 때, 여러 조건을 조합해서 데이터를 조회하려면 로딩 시간이 아주 오래 걸립니다. 이 때 인덱스(Index)를 설정하면 속도가 빨라집니다.

인덱스의 특징

✅ 인덱스는 WHERE 절에서 효과가 있다.

인덱스는 SELECT - FROM - WHERE 절 중 WHERE 절에 사용할 컬럼에 대한 효율화라고 볼 수 있습니다. WHERE절을 사용하지 않고 인덱스가 걸린 컬럼을 조회하는 것은 성능에 아무런 영향이 없습니다.

예를 들어, '학생' 테이블에 '학번', '이름', '전화번호'가 있다고 가정해봅시다.
인덱스는 '학번', '전화번호'에 걸려 있습니다. 다음 중 인덱스가 영향을 주는 쿼리는 어떤 것일까요 ?

  • 1번 SELECT '학번' FROM '학생';
  • 2번 SELECT '전화번호' FROM '학생' WHERE '이름' = '김철수';
  • 3번 SELECT * FROM '학생' WHERE 학번' = 1;

정답은 3번입니다.
WHERE절에 사용할 때 성능을 향상시킵니다.

그렇다면 무조건 많이 설정하면 좋은걸까 ?

인덱스는 하나 혹은 여러 개의 컬럼에 대해 설정할 수 있습니다.
단일 인덱스를 여러 개 생성할 수도 여러 컬럼을 묶어 복합 인덱스를 설정할 수도 있습니다.

그러나 무조건 많이 설정하는게 검색 속도 향상을 높여주지는 않습니다.

인덱스는 데이터베이스 메모리를 사용하여 테이블 형태로 저장되므로 개수와 저장 공간은 비례합니다.

  • 조회시 자주 사용하고
  • 고유한 값 위주로

인덱스를 설정하는게 좋습니다.

DML(Data Manipulation Language) 각각에는 어떤 영향을 미칠까 ?

SELECT 쿼리에서 성능이 잘 나오지만 INSERT, UPDATE, DELETE 쿼리에서는 때에 따라 다릅니다.

  • UPDATE, DELETE는 WHERE 절에 잘 설정된 인덱스로 조건을 붙여주면 조회할 때 성능은 크게 저하되지 않으나 (업데이트 할 데이터를 찾을 때의 속도가 빨라지는 것이지, 업데이트 자체가 빨라지는 것은 아님)
  • INSERT의 경우, 새로운 데이터가 추가되면서 기존에 인덱스 페이지에 저장되어 있던 탐색 위치가 수정되어야 하므로 효율이 좋지 않습니다.

즉, 인덱스는 원하는 데이터를 빠르게 찾을 때 빛을 발합니다.

그럼 어떤 컬럼에 인덱스를 설정하는게 좋을까 ?

인덱스는 한 테이블당 보통 3~5개 정도가 적당합니다.
물론 테이블의 목적 등에 따라 개수는 달라질 수 있습니다.

인덱스는 컬럼을 정해서 설정하는 것이므로 후보 컬럼의 특징을 잘 파악해야 합니다.
아래 4가지 기준을 사용하면 효율적으로 인덱스를 설정할 수 있습니다.

  • 카디널리티 (Cardinality)
  • 선택도 (Selectivity)
  • 활용도
  • 중복도

카디널리티 (Cardinality)

✅ 카디널리티가 높을 수록 인덱스 설정에 좋은 컬럼입니다.
즉, 한 컬럼이 갖고 있는 값의 중복 정도가 낮을 수록 인덱스로 사용하기 좋습니다.

컬럼에 사용되는 값의 다양성 정도, 즉 중복 수치를 나타내는 지표입니다.
후보 컬럼에 따라 상대적으로 중복 정도가 낮다, 혹은 높다로 표현됩니다.

예를 들어 10개 rows를 가지는 '학생' 테이블에 '학번''이름' 컬럼이 있다고 해봅시다.

  • '학번'은 학생마다 부여 받으므로 10개 값 모두 고유합니다.
  • 중복 정도가 낮으므로 카디널리티가 높습니다.
  • '이름'은 동명이인이 있을 수 있으니 1~10개 사이의 값을 가집니다.
  • 중복 정도가 '학번'에 비해 높으므로 카디널리티가 낮다고 표현할 수 있습니다.

선택도 (Selectivity)

선택도가 낮을 수록 인덱스 설정에 좋은 컬럼입니다.
5 ~ 10% 정도가 적당합니다.

데이터에서 특정 값을 얼마나 잘 선택할 수 있는지에 대한 지표입니다.
선택도는 아래와 같이 계산합니다.

  • 컬럼의 특정 값의 row 수 / 테이블의 총 row 수 * 100
  • 컬럼의 값들의 평균 row 수 / 테이블의 총 row 수 * 100

예를 들어, 10개 rows를 가지는 '학생' 테이블에 '학번', '이름', '성별' 컬럼이 있다고 해봅시다.
학번은 고유하고 이름은 2명씩 같고 성별은 남여 5:5 비율입니다.

  • '학번'의 선택도 = 1/10 * 100 = 10%
    SELECT COUNT(1) FROM '학생' WHERE '학번' = 1;
    모두 고유하므로 특정 값: 1
  • '이름'의 선택도 = 2/10 * 100 = 20%
    SELECT COUNT(1) FROM '학생' WHERE '이름' = '김철수';
    2명씩 같으므로 특정 값: 2
  • '성별'의 선택도 = 5/10 * 100 = 50%
    SELECT COUNT(1) FROM '학생' WHERE '성별' = F;
    5명씩 같으므로 특정 값: 5

즉, 선택도는 특정 필드값을 지정했을 때 선택되는 레코드 수를 테이블 전체 레코드 수로 나눈 것입니다.

활용도

✅ 활용도가 높을수록 인덱스 설정에 좋은 컬럼입니다.

해당 컬럼이 실제 작업에서 얼마나 활용되는지에 대한 값입니다.
수동 쿼리 조회, 로직과 서비스에서 쿼리를 날릴 때 WHERE절에 자주 활용되는지를 판단하면 됩니다.

중복도

✅ 중복도가 없을 수록 인덱스 설정에 좋은 컬럼입니다.

post-custom-banner

0개의 댓글