데이터베이스 & ORM

PostgreSQL GIN

DoRightting 2024. 11. 10. 19:57

1. GIN(Generalized Inverted Index) 개요

GIN 인덱스 사용 예시

-- 프롬프트의 키워드와 카테고리 검색을 위한 GIN 인덱스
CREATE INDEX idx_config ON prompts USING GIN (config);

-- 벡터 유사도 검색을 위한 인덱스
CREATE INDEX prompt_vector_idx ON prompts
    USING ivfflat (embedding_vector vector_l2_ops)
WITH (lists = 100);

1.1 GIN의 특징

  1. 다중 값 데이터 타입 처리
    • JSONB
    • 배열
    • 전문 검색(Full-text search)
  2. 구조
    • 키 -> 포스팅 리스트(해당 키가 출현하는 행들의 목록)
    • B-tree와 달리 하나의 열이 여러 키를 가질 수 있음

2. 프로젝트 내 GIN 인덱스 활용

2.1 JSONB 데이터 검색

@Entity
@Table(name = "prompts")
public class Prompt {
    @Type(JsonBType.class)
    @Column(columnDefinition = "jsonb")
    private Map<String, List<String>> categoryKeywords;
}

// 인덱스 생성
@Query(value = """
    CREATE INDEX IF NOT EXISTS idx_category_keywords
    ON prompts USING GIN (category_keywords)
    """, nativeQuery = true)

2.2 검색 쿼리 예시

-- 특정 키워드를 포함하는 프롬프트 검색
SELECT * FROM prompts
WHERE category_keywords @> '{"art_style": ["digital art"]}'::jsonb;

-- 여러 조건을 조합한 검색
SELECT * FROM prompts
WHERE category_keywords @> '{"medium": ["painting"]}'
  AND category_keywords ? 'color_scheme';

GIN 인덱스를 선택한 이유

  1. 데이터 특성
    • 다중 값을 가진 JSONB 데이터 저장
    • 효율적인 키워드 검색 필요
  2. // 프롬프트의 카테고리와 키워드는 JSONB 형태로 저장 @Column(columnDefinition = "jsonb") private Map<String, List<String>> categoryKeywords;
  3. 검색 성능
    • 전문 검색 지원
    • 복잡한 검색 조건에서도 높은 성능 제공

B-tree 대신 GIN을 사용했을 때의 장단점

  1. 장점
    • 다중 값 데이터의 효율적인 검색
    • 부분 일치 검색 성능 우수
  2. -- GIN의 효율적인 포함 검사 WHERE category_keywords @> '{"style": ["modern"]}'
  3. 단점
    • 인덱스 크기가 더 클 수 있음
    • 삽입 성능이 상대적으로 느릴 수 있음

GIN 인덱스의 성능 최적화

  1. 인덱스 설정
    • fastupdate 옵션 활용
    • 주기적인 VACUUM ANALYZE 수행
  2. -- 빠른 갱신을 위한 fastupdate 옵션 CREATE INDEX idx_category_keywords ON prompts USING GIN (category_keywords) WITH (fastupdate = on);
  3. 쿼리 최적화
    • 적절한 연산자 선택
    • 실행 계획 분석
  4. -- 효율적인 연산자 사용 WHERE category_keywords @> '{"key": "value"}' -- 대신 WHERE category_keywords->>'key' = 'value'

GIN 인덱스 관리

  1. 모니터링
    • 인덱스 크기 추적
    • 사용 패턴 분석
  2. -- 인덱스 크기 및 사용량 모니터링 SELECT schemaname, tablename, indexname, indexdef FROM pg_indexes WHERE indexname = 'idx_category_keywords';
  3. 유지보수
    • 주기적인 VACUUM
    • 통계 정보 업데이트
  4. -- 정기적인 인덱스 관리 VACUUM ANALYZE prompts;

GIN 인덱스 사용 시 주의할 점

  1. 리소스 관리
    • 적절한 메모리 할당
    • 디스크 공간 모니터링
  2. -- 작업 메모리 설정 SET maintenance_work_mem = '1GB';
  3. 성능 고려사항
    • 대량 데이터 처리 전략
    • 인덱스 재생성 타이밍
  4. // 대량 데이터 입력 시 인덱스 재생성 고려 @Transactional public void bulkInsert(List<Prompt> prompts) { // 인덱스 삭제 후 데이터 입력하고 인덱스 재생성 }

GIN과 다른 인덱스 타입과의 조합 결정 근거

  1. 데이터 특성 분석
    • 검색 패턴 분석
    • 데이터 타입별 최적 인덱스 선택
  2. -- 데이터 특성에 따른 인덱스 선택 CREATE INDEX idx_category_keywords USING GIN (...); -- JSONB 데이터 CREATE INDEX idx_created_at USING BTREE (...); -- 날짜 데이터
  3. 쿼리 패턴
    • 자주 사용되는 쿼리 분석
    • 복합 인덱스 고려