PostgreSQL 인덱스 통계와 ANALYZE 이해하기
PostgreSQL 인덱스 통계의 개념과 pg_stats·pg_stat_user_indexes 조회 방법, ANALYZE 실행 기준과 실무 적용 사례를 초보자 관점에서 정리한 기술 자료
목차
개요
쿼리 성능을 개선하려면 통계의 역할을 이해하는 것이 중요하다. PostgreSQL은 실행 계획을 만들 때 통계 정보를 사용한다. 특히 인덱스와 관련된 통계는 옵티마이저가 효율적인 접근 경로를 선택하는 데 큰 영향을 준다. 이 글에서는 pg_stats와 관련 뷰를 통해 통계를 확인하는 방법과 ANALYZE 명령의 사용 시점을 실무 관점에서 설명한다.
PostgreSQL 통계의 기본 개념
통계의 목적
통계는 테이블의 데이터 분포를 요약한다. 옵티마이저는 이 요약을 바탕으로 행 수 추정, 조인 방식, 인덱스 사용 여부를 결정한다. 잘못된 통계는 잘못된 계획으로 이어져 성능 저하를 유발한다.
주요 통계 항목
- n_distinct: 고유값 수 추정
- null_frac: NULL 비율
- most_common_vals: 자주 등장하는 값 목록
- histogram_bounds: 값 분포의 구간 경계
- correlation: 물리적 정렬과 값 분포의 상관 관계
통계 조회: pg_stats와 pg_stat_user_indexes
PostgreSQL은 여러 뷰를 제공한다. pg_stats는 칼럼별 통계 요약을 보여준다. pg_stat_user_indexes 등은 인덱스의 사용 통계를 제공한다. 두 뷰를 조합하면 인덱스 효율을 판단할 수 있다.
pg_stats 조회 예시
SELECT schemaname, tablename, attname, n_distinct, null_frac, most_common_vals
FROM pg_stats
WHERE tablename = 'orders' AND schemaname = 'public';
결과에서 n_distinct와 histogram_bounds를 확인하면 선택성(selectivity)을 파악할 수 있다. most_common_vals는 특정 값에 쏠림 현상이 있는지 보여준다.
인덱스 사용 통계 확인
SELECT schemaname, relname AS table, indexrelname AS index, idx_scan, idx_tup_read, idx_tup_fetch
FROM pg_stat_user_indexes
WHERE relname = 'orders';
idx_scan은 인덱스가 사용된 횟수를, idx_tup_fetch는 실제로 인덱스 통해 읽은 행 수를 나타낸다. 이를 통해 인덱스가 실무에서 유의미하게 사용되는지 판단한다.
ANALYZE의 역할과 실행 시점
ANALYZE는 테이블의 샘플링을 통해 통계를 갱신한다. VACUUM과 함께 사용되기도 하지만 ANALYZE만 단독으로 실행할 수 있다. 통계가 오래되면 옵티마이저의 추정이 빗나가므로 주기적 갱신이 필요하다.
언제 ANALYZE를 실행해야 하는가
- 대량의 INSERT/UPDATE/DELETE가 발생한 후
- 데이터 분포가 크게 변한 경우
- 테이블 구조 변경(칼럼 추가 등) 후
- 쿼리 계획이 갑자기 나빠진 경우
ANALYZE 실행 예시
ANALYZE public.orders;
-- 또는 데이터베이스 전체를 갱신
ANALYZE;
특정 칼럼만 갱신하려면 칼럼명을 지정할 수 있다. 통계 샘플링 크기는 default_statistics_target 설정으로 조정 가능하다. 값이 클수록 더 정밀하지만 처리 시간이 증가한다.
실무 적용과 모범 사례
모니터링 절차
- 정기적으로 pg_stat_user_tables와 pg_stat_user_indexes 확인
- 특정 쿼리의 계획이 비정상적이면 pg_stats로 해당 칼럼 확인
- 데이터 변경량이 크면 자동화된 ANALYZE 트리거 도입
통계 세부 조정
default_statistics_target을 높여 특정 칼럼의 통계를 더 정밀하게 만들 수 있다. 예컨대 WHERE 절에 자주 쓰이는 칼럼은 ALTER TABLE ... ALTER COLUMN ... SET STATISTICS로 타겟을 증가시킨다. 다만 설정 값이 지나치면 ANALYZE 비용이 커진다.
인덱스 관련 실무 팁
- 인덱스 사용 빈도가 낮으면 제거를 검토
- 복합 조건에서는 통계 기반으로 인덱스 순서와 조합을 판단
- 정렬된 입력이 많으면 correlation 값을 확인해 인덱스 효율을 예측
문제 해결 예시
예상과 다른 계획이 선택될 때의 접근법은 다음과 같다.
- 문제 쿼리의 EXPLAIN ANALYZE 실행
- 관련 칼럼을 pg_stats로 조회해 분포 확인
- 필요 시 ANALYZE 수행 후 계획 변화 확인
-- 문제 원인 진단 절차 예시
EXPLAIN (ANALYZE, BUFFERS) SELECT * FROM orders WHERE status = 'pending';
SELECT attname, n_distinct, most_common_vals FROM pg_stats WHERE tablename='orders';
ANALYZE public.orders;
EXPLAIN (ANALYZE, BUFFERS) SELECT * FROM orders WHERE status = 'pending';
마무리
통계는 옵티마이저의 핵심 정보원이다. pg_stats와 pg_stat_user_indexes를 통해 현재 상태를 파악하고, 필요할 때 ANALYZE로 갱신하면 안정적인 쿼리 성능을 유지할 수 있다. 설정과 실행 빈도는 시스템 특성에 맞춰 조정하는 것이 중요하다.