-- 확장 설치 CREATE EXTENSION IF NOTEXISTS pg_stat_statements;
-- 설치 확인 SELECT*FROM pg_available_extensions WHERE name ='pg_stat_statements';
2. postgresql.conf 설정
# postgresql.conf 파일에 추가 shared_preload_libraries = 'pg_stat_statements'
# 추적할 쿼리 수 (기본값: 5000) pg_stat_statements.max = 10000
# 쿼리 추적 모드 (top: 최상위 쿼리만, all: 중첩 쿼리 포함) pg_stat_statements.track = all
설정 변경 후 PostgreSQL 재시작 필요:
# 재시작 sudo systemctl restart postgresql
# 또는 pg_ctl restart
3. 실행 횟수가 많은 Top N 쿼리
SELECT query, calls AS exec_count, total_exec_time, mean_exec_time, min_exec_time, max_exec_time, rows FROM pg_stat_statements ORDERBY calls DESC LIMIT 10;
4. 평균 실행 시간이 긴 Top N 쿼리
SELECT query, calls AS exec_count, mean_exec_time, min_exec_time, max_exec_time, stddev_exec_time FROM pg_stat_statements WHERE calls >10-- 최소 10회 이상 실행된 쿼리 ORDERBY mean_exec_time DESC LIMIT 10;
5. 총 실행 시간이 긴 Top N 쿼리
SELECT query, calls AS exec_count, total_exec_time, mean_exec_time, (total_exec_time /SUM(total_exec_time) OVER ()) *100AS percentage, rows FROM pg_stat_statements ORDERBY total_exec_time DESC LIMIT 10;
SELECT substring(query, 1, 100) AS short_query, calls, ROUND(total_exec_time::numeric, 2) AS total_time_ms, ROUND(mean_exec_time::numeric, 2) AS avg_time_ms, ROUND((100* total_exec_time /SUM(total_exec_time) OVER ())::numeric, 2) AS percentage, rowsAS total_rows, ROUND((rows/ calls)::numeric, 2) AS avg_rows_per_call FROM pg_stat_statements WHERE calls >5 ORDERBY total_exec_time DESC LIMIT 10;
8. 현재 실행중인 쿼리 확인
-- 현재 활성 쿼리 확인 SELECT pid, usename, application_name, client_addr, state, query_start, NOW() - query_start AS duration, query FROM pg_stat_activity WHERE state !='idle' AND query NOTLIKE'%pg_stat_activity%' ORDERBY duration DESC;
9. 느린 쿼리 로깅 설정
-- 현재 세션에만 적용 SET log_min_duration_statement =1000; -- 1초 이상 쿼리 로깅
-- 전역 설정 (postgresql.conf)
postgresql.conf:
# 1초 이상 실행되는 쿼리 로깅 log_min_duration_statement = 1000
# 로그에 추가 정보 포함 log_line_prefix = '%t [%p]: [%l-1] user=%u,db=%d,app=%a,client=%h ' log_statement = 'all' # 또는 'ddl', 'mod', 'none' log_duration = on log_lock_waits = on
-- 데이터베이스별 통계 SELECT d.datname, COUNT(*) AS query_count, SUM(calls) AS total_calls, ROUND(SUM(total_exec_time)::numeric, 2) AS total_time_ms FROM pg_stat_statements s JOIN pg_database d ON s.dbid = d.oid GROUPBY d.datname ORDERBY total_time_ms DESC;
-- 캐시 히트율 확인 SELECT query, calls, shared_blks_hit, shared_blks_read, CASE WHEN (shared_blks_hit + shared_blks_read) >0 THEN ROUND((shared_blks_hit::numeric/ (shared_blks_hit + shared_blks_read)) *100, 2) ELSE0 ENDAS cache_hit_ratio FROM pg_stat_statements WHERE (shared_blks_hit + shared_blks_read) >0 ORDERBY cache_hit_ratio ASC LIMIT 10;
주요 컬럼 설명
calls: 쿼리 실행 횟수
total_exec_time: 총 실행 시간 (밀리초)
mean_exec_time: 평균 실행 시간 (밀리초)
rows: 반환되거나 영향받은 총 행 수
shared_blks_hit: 공유 버퍼 캐시에서 읽은 블록 수
shared_blks_read: 디스크에서 읽은 블록 수
temp_blks_read/written: 임시 파일 I/O (정렬, 해시 등)
pg_stat_statements vs pg_stat_activity
pg_stat_statements: 누적 통계 (과거부터 현재까지의 모든 쿼리)
pg_stat_activity: 현재 실행 중인 쿼리만 표시
참고사항
pg_stat_statements는 PostgreSQL 9.2 이상에서 사용 가능합니다
shared_preload_libraries 설정 변경 시 PostgreSQL 재시작이 필요합니다
쿼리는 정규화되어 저장됩니다 (파라미터 값은 ? 또는 $1 등으로 대체)
프로덕션 환경에서 사용 시 pg_stat_statements.max 값을 적절히 조정하세요