본문으로 건너뛰기

10.6 auto_explain

auto_explain은 슬로우 쿼리의 EXPLAIN ANALYZE 결과를 자동으로 로그에 남기는 표준 확장입니다. 사후 분석에 그 시점의 plan을 확인하는 유일한 방법. pg_stat_statements가 요약 통계라면 auto_explain은 개별 trace.

활성

# postgresql.conf
shared_preload_libraries = 'pg_stat_statements,auto_explain'

auto_explain.log_min_duration = '1s'        # 1초 넘는 쿼리만
auto_explain.log_analyze = on                # 실제 실행 시간 (BUFFERS·timing 포함)
auto_explain.log_buffers = on                # cache hit/read 통계
auto_explain.log_timing = on                 # actual time (off하면 약간 오버헤드 ↓)
auto_explain.log_verbose = on                # 컬럼 정보
auto_explain.log_triggers = on               # 트리거 시간
auto_explain.log_settings = on               # 비기본 설정 표시 (PG 12+)
auto_explain.log_format = json               # text/json/yaml/xml
auto_explain.log_nested_statements = on      # 함수 내부 쿼리도 포함
auto_explain.log_level = log                 # log_min_messages 단계
auto_explain.sample_rate = 1.0               # 1.0 = 모든 슬로우 쿼리. 0.1 = 10%만

auto_explain은 함수 안에서만 켤 수도 있습니다.

LOAD 'auto_explain';
SET auto_explain.log_min_duration = '0';
SET auto_explain.log_analyze = on;

-- 이 세션의 모든 쿼리가 EXPLAIN ANALYZE 자동 출력
SELECT ...

출력 예시

text 포맷:

2026-05-23 11:00:01 KST [12345] LOG:  duration: 1503.421 ms
  plan:
    Query Text: SELECT * FROM orders WHERE user_id = $1
    Index Scan using orders_user_id_idx on orders  (cost=0.42..823.51 rows=1000 width=64)
      Index Cond: (user_id = $1)
      Buffers: shared hit=14 read=200

JSON 포맷은 자동 분석 도구가 파싱하기 쉬워 운영에서 더 선호.

트레이드오프

옵션비용
log_analyze = on매 쿼리 실행을 측정 — 일반적으로 slowdown ~ 1%
log_timing = on노드 단위 timing — Linux는 매우 가벼움, 가상 환경에서 약간 비용
log_min_duration = 0 (모든 쿼리)로그 폭증 + 측정 비용. 디버깅 외 금지
sample_rate = 0.110% 샘플 — 부하 줄임
log_format = json파싱 용이, 약간 큼

운영 권장 출발:

auto_explain.log_min_duration = '1s'
auto_explain.log_analyze = on
auto_explain.log_buffers = on
auto_explain.log_format = json
auto_explain.sample_rate = 1.0

부하가 큰 시스템에서 sample_rate를 0.1로 낮춰도 슬로우 쿼리 자체가 드물면 충분한 샘플 확보.

분석 도구 짝

도구활용
explain.depesz.com텍스트 plan 시각화
explain.dalibo.comJSON plan
pgBadgerauto_explain의 plan 통계
Loki + GrafanaJSON 로그 검색

함수 내부 쿼리

기본은 최상위 쿼리만 측정합니다. PL/pgSQL 함수 내부의 SQL을 보려면:

auto_explain.log_nested_statements = on

함수 내부의 각 SQL이 별도로 측정되어 로그.

auto_explain vs EXPLAIN ANALYZE 직접 호출

측면auto_explainEXPLAIN ANALYZE
발생 시점운영 중 실시간 자동운영자가 수동 호출
재현 어려운 쿼리잡힘못 잡음 (한 번 발생)
운영 부하약간 (sample_rate로 제어)0 (호출 안 함)
데이터 부작용없음INSERT/UPDATE/DELETE는 실제 적용됨

운영 중 간헐적 느린 쿼리의 plan을 잡는 거의 유일한 방법.

pg_stat_statements와의 차이

항목pg_stat_statementsauto_explain
데이터 형태누적 카운터개별 trace
어디 저장shared memorylog 파일
정규화쿼리 패턴별 합산개별 호출별
사용어떤 쿼리가 무거운가그 쿼리가 어떤 plan을 받았나

둘은 대체재가 아니라 보완재. 함께 켜는 게 표준입니다.

활용 워크플로

    flowchart LR
  STATS["pg_stat_statements<br/>(요약)"] --> TOP["TOP 슬로우 쿼리 식별"]
  AE["auto_explain<br/>(개별 plan 캡처)"] --> LOG["로그에서 plan 찾기"]
  TOP --> JOIN["queryid 매칭"]
  LOG --> JOIN
  JOIN --> FIX["plan 미스 원인 파악·튜닝"]

  classDef stat fill:#dbeafe,stroke:#1d4ed8,color:#1e3a8a
  classDef ae fill:#fed7aa,stroke:#c2410c,color:#7c2d12
  classDef fix fill:#d1fae5,stroke:#047857,color:#064e3b
  class STATS,TOP stat
  class AE,LOG ae
  class JOIN,FIX fix
  

PG 14+의 queryid로 두 도구 결과를 매칭 가능합니다.

주의

주의메모
log_min_duration = 0은 디버깅용운영에서는 1s 이상만
로그 디스크 폭증 가능rotation·외부 수집 필수
함수 내부 SQL의 paramter 노출민감 정보 — log_parameter_max_length로 잘라낼 수 있음
crash 분석 후엔 로그가 곧 plan 원본백업 보존 정책에 포함

정리

  • auto_explain = 슬로우 쿼리의 EXPLAIN을 자동 로그
  • 운영 표준: log_min_duration = 1s, log_analyze = on, JSON 포맷
  • 함수 내부 쿼리도 log_nested_statements = on
  • pg_stat_statements와 짝 — 요약 + 개별 plan
  • explain.depesz·explain.dalibo와 결합해 빠른 분석
  • 측정 비용은 1% 내외 — sample_rate로 더 줄일 수 있음

다음 절(10.7)에서는 외부 모니터링 도구 — Prometheus, Datadog, pgwatch2와의 통합을 봅니다.