PostgreSQL
PostgreSQL: EXPLAIN을 활용한 선택도 추정 정확도 분석
dewstream
2025. 5. 11. 08:00
728x90
※ PostgreSQL: Analysis of Selectivity Estimation Accuracy Using EXPLAIN.
※ Version: PostgreSQL 17.
안녕하세요. 듀스트림입니다.
계속해서 이전 포스팅과 이어지는 내용입니다.
PostgreSQL: 선택도 기반 실행 계획 수립 원리
※ PostgreSQL: The Principle of Execution Plan Generation Based on Selectivity.※ Version: PostgreSQL 17. 안녕하세요. 듀스트림입니다. 오늘 포스팅은 이전 포스팅과 이어지는 내용입니다. PostgreSQL: 동등 조건과 범위
dewstream.tistory.com
PostgreSQL 옵티마이저는 실행 계획 수립 시 조건절의 선택도(Selectivity)를 기반으로 예상 처리 행 수(rows), 비용(cost), 전략(Index Scan, Seq Scan 등)을 결정합니다.
이 추정값은 항상 정확하진 않으며, 통계의 신선도나 데이터 분포(skew)에 따라 실제 실행 결과와 오차가 발생할 수 있습니다.
1. EXPLAIN (ANALYZE)란?
- PostgreSQL이 쿼리를 어떻게 실행할지 계획(plan)을 보여주는 도구
- ANALYZE 옵션을 함께 주면 실제로 쿼리를 실행한 후, 예상과 실제 실행 결과를 함께 비교해 보여줍니다.
-- 예.
EXPLAIN (ANALYZE, BUFFERS)
SELECT * FROM users WHERE city = 'Seoul';
- 주요 항목 설명
항목 | 설명 |
Plan | 실제 사용된 실행 계획 노드 (Seq Scan, Index Scan 등) |
Rows | 옵티마이저가 예상한 결과 row 수 |
Actual Rows | 실제 실행 결과에서 반환된 row 수 |
Loops | 반복 횟수 (Nested Loop 등에서 중요) |
Buffers | 디스크 또는 캐시 페이지 접근 정보 (I/O 측정 가능) |
2. 선택도 추정 정확도 평가 방법
- 옵티마이저의 선택도 추정이 정확한지 판단하려면 다음을 비교합니다.
예상 행 수 (rows) vs 실제 행 수 (actual rows)
- 기준 판단
기준 | 의미 |
예상값 ≒ 실제값 | 선택도 추정 정확 |
예상 ≪ 실제 | 선택도 과소 추정 (실제는 훨씬 많은 row 처리됨) |
예상 ≫ 실제 | 선택도 과대 추정 (불필요하게 비싼 계획이 선택됐을 수 있음) |
실행 전략 오류와 직결될 수 있으므로 반드시 주기적으로 점검해야 합니다.
3. 예제
3.1 테스트 데이터 생성
CREATE TABLE users (id SERIAL, city TEXT, age INT);
INSERT INTO users
SELECT i,
CASE WHEN i % 100 = 0 THEN 'Seoul' ELSE 'Other' END,
(RANDOM() * 100)::INT
FROM generate_series(1, 100000) i;
CREATE INDEX idx_users_city ON users(city);
ANALYZE users;
3.2 테스트 쿼리 실행
-- 1차 수행
EXPLAIN (ANALYZE, BUFFERS)
SELECT * FROM users WHERE city = 'Seoul';
--- QUERY PLAN ---
Index Scan using idx_user_city on users (cost=0.29..44.00 rows=950 width=14) (actual time=0.048..0.982 rows=1000 loops=1)
Index Cond: (city = 'Seoul'::text)
Buffers: shared hit=541 read=3
Planning:
Buffers: shared hit=15 read=1
Planning Time: 0.332 ms
Execution Time: 1.186 ms
(7 rows)
-- rows=950, actual rows=1000으로 거의 유사하므로, 선택도 추정 정확함
-- ±10% 이내면 높은 정확도
-- skew 데이터 추가
INSERT INTO users
SELECT 100001 + i, 'Seoul', (RANDOM() * 100)::INT
FROM generate_series(1, 10000) i;
-- 2차 수행
EXPLAIN (ANALYZE, BUFFERS)
SELECT * FROM users WHERE city = 'Seoul';
--- QUERY PLAN ---
Index Scan using idx_user_city on users (cost=0.30..151.05 rows=3307 width=14) (actual time=0.020..2.364 rows=13000 loops=1)
Index Cond: (city = 'Seoul'::text)
Buffers: shared hit=1154
Planning Time: 0.066 ms
Execution Time: 3.027 ms
(5 rows)
-- rows=3307, actual rows=13000으로 선택도 과소 추정
-- 실제보다 단순한 실행 계획이 선택되었을 수 있음
-- 통계 갱신
ANALYZE users;
-- 3차 수행
EXPLAIN (ANALYZE, BUFFERS)
SELECT * FROM users WHERE city = 'Seoul';
--- QUERY PLAN ---
Index Scan using idx_user_city on users (cost=0.30..348.40 rows=12328 width=14) (actual time=0.017..1.762 rows=13000 loops=1)
Index Cond: (city = 'Seoul'::text)
Buffers: shared hit=1154
Planning Time: 0.057 ms
Execution Time: 2.247 ms
(5 rows)
-- rows=12328, actual rows=13000으로 거의 유사
4. 선택도 오차 발생 원인
원인 | 설명 |
오래된 통계 | 데이터 변경 후 ANALYZE 미수행 시 발생 |
skew 분포 | 특정 값이 지나치게 많지만 히스토그램/MCV에 반영되지 않음 |
통계 수집 부족 | default_statistics_target이 낮아 MCV/히스토그램 정밀도가 떨어짐 |
상관 컬럼 누락 | 다중 컬럼 상관관계가 CREATE STATISTICS로 반영되지 않음 |
5. 오차 보완 및 튜닝 방법
항목 | 조치 |
통계 갱신 | ANALYZE, VACUUM ANALYZE 수행 |
통계 정밀도 향상 | ALTER TABLE ... SET STATISTICS 500, default_statistics_target 증가 |
다중 컬럼 관계 반영 | CREATE STATISTICS (dependencies) 활용 |
실행 계획 강제 적용 | ENABLE_* 파라미터로 특정 계획 비활성화, pg_hint_plan 사용 (최후에 사용하시길 바랍니다.) |
6. 요약 정리
개념 | 설명 |
EXPLAIN (ANALYZE) | 실제 실행 결과와 옵티마이저 예상값을 비교 가능 |
핵심 비교 지표 | 예상 Rows vs Actual Rows |
오차 의미 | 과소 추정 = 실행 계획 축소, 과대 추정 = 불필요한 계획 확장 |
원인 분석 | 오래된 통계, skew, 통계 목표값 낮음, 다중 컬럼 미반영 등 |
보완 방법 | ANALYZE, 통계 설정 증가, CREATE STATISTICS 활용 |
14.1. Using EXPLAIN
14.1. Using EXPLAIN # 14.1.1. EXPLAIN Basics 14.1.2. EXPLAIN ANALYZE 14.1.3. Caveats PostgreSQL devises a query plan for each query it …
www.postgresql.org
오늘은 여기까지 ~
728x90