Published on

postgresql 과 django 의 인덱스 설정과 기준

Authors

인덱스를 적절하게 설정하는 것은 DB와 애플리케이션 설계 관점에서 속도향상에 매우 영향이 있습니다. django를 통해서 모델에 인덱스 설정하는 방법과 직접 postgresql 에 인덱스를 설정하는 방법을 기록하고, 인덱스 적용에 대한 관점(기준)도 기록합니다.

1. PostgreSQL에서 인덱스 설정

PostgreSQL에서는 인덱스를 다양한 방식으로 설정할 수 있고 몇가지 종류가 있습니다.

  • B-tree 인덱스: 기본 인덱스이며, 대부분의 경우 적합합니다. 데이터가 순서대로 정렬되어 저장됩니다.
  • Hash 인덱스: 해시 테이블을 사용하여 동등 비교에 최적화되어 있습니다.
  • GIN 인덱스: 다중값을 저장하는 열(예시: 배열)에 유용합니다.
  • GiST 인덱스: 근접 탐색이 필요한 경우(예: 기하학적 데이터)에 적합합니다.

먼저 sql 문으로 다음처럼 인덱스를 설정할 수 있습니다.


CREATE INDEX idx_kor_id ON people (kor_id);

2. Django 모델에서 인덱스 설정

Django에서 인덱스를 설정하는 방법은 매우 간단합니다.

모델 필드에 db_index=True 옵션을 추가하거나, Meta 클래스의 indexes 속성을 사용하여 인덱스를 정의할 수 있습니다.

다음은 예시로 주민등록번호, 나이, 이름 필드에 대해 인덱스를 설정한 것입니다.

from django.db import models

class People(models.Model):
    kor_id = models.CharField(max_length=20, unique=True, db_index=True)  # 주민번호는 고유하고, 인덱스를 설정
    name = models.CharField(max_length=100)  # 이름은 인덱스 설정 X
    age = models.IntegerField()  # 나이도 인덱스 설정 X

    class Meta:
        indexes = [
            models.Index(fields=['name']),  # 필요하다면 이름에 인덱스를 추가.
        ]

위 코드에서 kor_iddb_index=True로 인덱스가 설정되었고, Meta 클래스에서 name 필드에도 인덱스를 추가로 설정할 수 있습니다.

Django에서 PostgreSQL 인덱스를 직접 제어하고 싶다면, models.Index 클래스와 db_tablespace 옵션을 사용할 수 있습니다.

여기서 name='idx_kor_id_id'는 PostgreSQL에서 인덱스의 이름을 지정하는 방식입니다.


class People(models.Model):
    kor_id = models.CharField(max_length=20, unique=True, db_index=True)

    class Meta:
        indexes = [
            models.Index(fields=['kor_id'], name='idx_kor_id'),
        ]

3. 인덱스 설정의 기준

데이터 모델을 설계할때, 어떤 필드에 인덱스를 설정하는 것에 대한 명확한 기준이 없으면, 어려울 수 밖에 없습니다. 위의 사례처럼 주민등록번호와 이름과 나이가 있다고 가정하고 고민해보겠습니다.

1) 주민번호

(pk 아님, pk 는 따로 있다고 가정함.)

주민번호는 전국민을 대상으로 고유한 값입니다. 따라서 주민번호는 높은 카디널리티를 가집니다.

주민번호에 인덱스를 설정하면 각 학생을 빠르게 조회할 수 있기 때문에, 주민번호에 인덱스를 설정하는 것이 매우 효율적입니다.

2) 나이

나이는 대부분 비슷한 값을 갖는 경우가 많습니다.

예를 들어, 중고등학생이나 대학생들이 자주 사용하는 서비스의 경우, 나이는 주로 10대에서 20대 초반에 몰려 있기 때문에나이 열의 값들은 중복이 많이 발생합니다.

이 경우, 나이에 인덱스를 설정해도 성능 향상 효과가 크지 않을 수 있습니다.

따라서 나이에 인덱스를 설정하는 것은 필요에 따라 신중히 결정해야 합니다.

3) 이름

이름은 사람마다 다를 수 있지만, 특정 이름은 여러 사람이 공통으로 가질 수 있습니다.

서비스 규모가 커질수록 이름에 대한 카디널리티를 어느정도 가질 수 있습니다. 이름에 인덱스를 설정할 경우, 데이터셋의 크기와 이름의 중복 여부에 따라 인덱스 효율성이 매우 달라질 수 있습니다.

서비스에 유형에 따라서 고민의 여지가 많습니다.

즉, 주민번호에 인덱스를 설정하는 것이 가장 효율적이며 이것은 카디널리티가 높음에 따라 고려되는 것임을 알 수 있습니다.

4. 복합 인덱스 (Composite Index)

복합 인덱스는 말그대로 복합적인 인덱스를 의미합니다.

이는 두 개 이상의 열(column)에 대해 동시에 인덱스를 설정 하는 것 입니다.

복합 인덱스는 여러 열을 결합하여 특정 패턴으로 사용하는 경우 유용합니다.

구체적으로 복합 인덱스는 보통 여러 열을 동시에 검색하거나 정렬해야 하는 쿼리에서 유용합니다.

"이름"과 "생년월일"로 사용자를 검색하는 경우말입니다.

또 복합 인덱스는 설정된 열의 순서가 매우 중요하며 검색 성능이 달라질 수 있습니다.

PostgreSQL에서는 복합 인덱스를 사용할 때 인덱스의 첫 번째 열부터 검색을 수행합니다.

때문에 가장 자주 필터링되는 열을 먼저 쓰는 것이 중요합니다.


CREATE INDEX idx_name_birthday ON people (name, birthday);

이 경우, 데이터베이스는 "name"으로 먼저 필터링한 후, 같은 "name" 내에서 "birthday"로 검색을 최적화할 수 있습니다.

하지만, "birthday"로만 검색하는 경우에는 이 인덱스가 사용되지 않습니다.

즉, 복합 인덱스의 첫 번째 열이 쿼리에 포함되지 않으면 인덱스를 활용하지 않기 때문에, 의미가 없습니다.

Django에서 복합 인덱스 설정

위에 설정과 유사하게 indexes 에서 설정 가능합니다.

예시에서는 namebirthday에 대해 복합 인덱스를 설정했습니다. 이 인덱스는 두 열이 함께 자주 검색되는 상황에서 성능을 크게 향상시킬 수 있습니다.

from django.db import models

class PEople(models.Model):
    kor_id = models.CharField(max_length=20)
    name = models.CharField(max_length=100)
    birthday = models.DateField()

    class Meta:
        indexes = [
            models.Index(fields=['name', 'birthday']),  # 이름과 생년월일에 복합 인덱스 설정
        ]

PostgreSQL에서 복합 인덱스 생성

PostgreSQL에서 복합 인덱스를 생성하는 방법도 간단합니다.

CREATE INDEX 문을 사용하여 두 개 이상의 열을 지정할 수 있습니다.

CREATE INDEX idx_name_birthday ON people (name, birthday);

SELECT 쿼리에서 namebirthday를 동시에 검색하거나 정렬하는 작업에서 이 인덱스의 효과가 발휘됩니다.

SELECT * FROM student WHERE name = '일론' AND birthdate = '1971-06-28';

5. 복합 인덱스 vs 단일 인덱스

참고로 복합 인덱스와 단일 인덱스의 차이는 매우 중요합니다.

단일 인덱스는 하나의 열에만 적용되며, 다른 열을 필터링하는 것은 의미가 없다고 볼수 있습니다.

복합 인덱스는 여러 열을 동시에 필터링하거나 정렬하는 경우에 큰 성능 향상을 제공합니다. 다만, 인덱스의 순서가 중요하므로 쿼리 패턴을 분석하여 올바른 열 순서로 설정해야 합니다.

즉 요약하자면.. 카디널리티가 높은 열을 먼저 고려하고 동시에 쿼리하는 것에 복합인덱스를 설정하는 것이 성능 최적화에 중요한 역할한다고 볼수 있습니다.

복합 인덱스 사용 시 주의할 점

  • 검색 조건에 인덱스 열 순서대로 사용해야 성능 최적화가 가능합니다.
  • 너무 많은 열을 복합 인덱스에 포함하면, 인덱스 크기가 커지고 오히려 성능이 저하될 수 있습니다.
  • 쿼리 패턴을 분석하여 복합 인덱스의 순서를 결정하는 것이 중요합니다.

레퍼런스 링크

DB 인덱스와 트리관련 자료

django 모델 meta 공식문서

postgresql 성능 팁

  • hongreat 블로그의 글을 봐주셔서 감사합니다!^^
  • 내용에 잘못된 부분이나 의문점이 있으시다면 댓글 부탁 & 환영 합니다~!
  • (하단의 버튼을 누르시면 댓글을 보거나 작성할 수 있습니다.)
Buy Me A Coffee