2026년 09월 18일 | DBMS Error 가이드
이 글에서 다루는 내용
53200 에러의 원인 분석, 해결 SQL, 예방 방법을 실무 관점에서 정리합니다.
53200 out of memory 는?
PostgreSQL 에러 코드 53200은 데이터베이스 서버가 쿼리 실행, 정렬, 해시 조인 등의 작업을 수행하는 도중 운영체제로부터 충분한 메모리를 할당받지 못할 때 발생합니다. 이 에러는 단순히 서버의 물리적 메모리가 부족한 경우뿐만 아니라, PostgreSQL 내부 설정값이 지나치게 낮거나 높게 잡혀 있어 메모리 요청이 실패하는 경우에도 나타납니다. 특히 대용량 데이터 처리, 복잡한 집계 쿼리, 다수의 동시 접속 세션이 몰릴 때 빈번하게 발생하므로 운영 환경에서 각별한 주의가 필요합니다.
주요 발생 원인
- work_mem 설정값 과다 또는 과소 설정
work_mem은 정렬(Sort), 해시 조인(Hash Join), 비트맵 힙 스캔(Bitmap Heap Scan) 등의 작업에서 각 연산자 노드별로 사용되는 메모리 크기를 결정합니다. 이 값이 지나치게 크게 설정되어 있고 동시 접속 세션이 많을 경우, 총 메모리 사용량이 물리 메모리를 초과하여 OOM 상황이 발생할 수 있습니다. 반대로 너무 낮게 설정되면 디스크 기반 정렬이 과도하게 발생하고, 경우에 따라 내부 임시 버퍼 할당 실패로 이어질 수 있습니다.
- 대용량 쿼리 및 서브쿼리의 무분별한 실행
수백만 건 이상의 데이터를 한 번에 정렬하거나 여러 단계의 서브쿼리를 중첩하여 실행할 경우, 각 단계마다 중간 결과셋을 메모리에 올리려 시도하면서 메모리 고갈이 발생합니다. 특히 ORDER BY, GROUP BY, DISTINCT, WINDOW FUNCTION 등을 대용량 테이블에 동시에 적용하면 단일 쿼리만으로도 수 GB의 메모리를 요구하는 상황이 생길 수 있습니다. 쿼리 실행 계획을 사전에 검토하지 않고 운영 환경에 배포하는 경우 이 문제가 특히 빈번하게 나타납니다.
- shared_buffers 및 OS 캐시 경합
shared_buffers가 물리 메모리 대비 지나치게 크게 설정되어 있거나, 여러 PostgreSQL 인스턴스가 동일 서버에서 구동되는 경우 OS 레벨의 메모리 경합이 발생합니다. Linux 환경에서는 OOM Killer가 PostgreSQL 프로세스를 강제 종료하는 극단적인 상황으로 번지기도 합니다. 이 경우 PostgreSQL 로그에 out of memory 에러와 함께 커널 로그(dmesg)에 OOM Killer 관련 메시지가 동시에 기록됩니다.
해결 방법
1. work_mem 튜닝
현재 설정값을 확인하고 세션 레벨 또는 글로벌 레벨로 조정합니다. 동시 접속 수를 고려해 work_mem = 물리메모리 / (max_connections × 쿼리당 평균 노드 수)를 기준으로 계산하는 것이 좋습니다.
-- 현재 work_mem 설정 확인
SHOW work_mem;
-- 세션 레벨에서 임시 조정 (테스트용)
SET work_mem = '64MB';
-- 특정 쿼리에만 적용
SET LOCAL work_mem = '128MB';
-- postgresql.conf 전역 설정 변경 후 reload
-- work_mem = '32MB' -- 동시 접속 100개 기준 보수적 설정
-- 변경 후 설정 반영
SELECT pg_reload_conf();
-- 현재 메모리 관련 설정 전체 조회
SELECT name, setting, unit, context
FROM pg_settings
WHERE name IN ('work_mem', 'shared_buffers', 'maintenance_work_mem', 'max_connections');
2. 대용량 쿼리 최적화
실행 계획을 분석하여 메모리를 많이 소모하는 노드를 파악하고, 쿼리를 분할하거나 인덱스를 추가합니다.
-- 실행 계획에서 메모리 사용량 확인 (BUFFERS 옵션 포함)
EXPLAIN (ANALYZE, BUFFERS, FORMAT TEXT)
SELECT department_id, COUNT(*), SUM(salary)
FROM employees
GROUP BY department_id
ORDER BY SUM(salary) DESC;
-- 대용량 정렬이 필요한 경우 커서(CURSOR)를 사용해 분할 처리
BEGIN;
DECLARE large_cursor CURSOR FOR
SELECT *
FROM large_table
ORDER BY created_at DESC;
FETCH 1000 FROM large_cursor;
-- 반복 처리 후 닫기
CLOSE large_cursor;
COMMIT;
-- 불필요한 DISTINCT 제거, EXISTS로 대체
-- 개선 전 (메모리 과다 사용)
SELECT DISTINCT customer_id FROM orders WHERE status = 'ACTIVE';
-- 개선 후 (EXISTS 활용)
SELECT customer_id
FROM customers c
WHERE EXISTS (
SELECT 1 FROM orders o
WHERE o.customer_id = c.customer_id
AND o.status = 'ACTIVE'
);
-- 파티션 테이블 활용으로 스캔 범위 축소
-- 인덱스 추가로 Seq Scan을 Index Scan으로 전환
CREATE INDEX CONCURRENTLY idx_orders_status_customer
ON orders(status, customer_id)
WHERE status = 'ACTIVE';
3. shared_buffers 및 시스템 메모리 조정
-- 현재 shared_buffers 확인
SHOW shared_buffers;
-- 물리 메모리 사용 현황 확인 (pg_top 또는 아래 뷰 활용)
SELECT
pg_size_pretty(pg_database_size(current_database())) AS db_size,
(SELECT setting::bigint * 8192
FROM pg_settings WHERE name = 'shared_buffers') / 1024 / 1024 AS shared_buffers_mb;
-- 메모리 압박 상황에서 autovacuum 메모리 사용 제한
ALTER SYSTEM SET autovacuum_work_mem = '128MB';
SELECT pg_reload_conf();
-- 임시 파일 사용 현황 모니터링 (temp_file 과다 사용은 work_mem 부족 신호)
SELECT query, temp_files, temp_bytes / 1024 / 1024 AS temp_mb
FROM pg_stat_statements
WHERE temp_bytes > 0
ORDER BY temp_bytes DESC
LIMIT 10;
예방 방법
- 정기적인 메모리 사용량 모니터링 및 알림 설정
pg_stat_activity, pg_stat_statements 뷰를 활용해 메모리 집약적 쿼리를 주기적으로 탐지하고, Prometheus + pg_exporter 등의 모니터링 도구를 통해 메모리 임계값 초과 시 알림을 받도록 설정합니다. Linux의 경우 /proc/meminfo와 PostgreSQL 로그를 연동하여 OOM 발생 직전 패턴을 사전에 파악하는 것이 효과적입니다. 또한 log_temp_files 파라미터를 설정해 임시 파일 생성 쿼리를 자동으로 로깅함으로써 work_mem 조정이 필요한 쿼리를 신속하게 식별할 수 있습니다.
-- 임시 파일 생성 쿼리 로깅 활성화 (0 = 모든 임시 파일 로깅)
ALTER SYSTEM SET log_temp_files = 0;
SELECT pg_reload_conf();
- Connection Pooling 도입 및 max_connections 최적화
PgBouncer와 같은 커넥션 풀러를 도입하면 실제 PostgreSQL 백엔드 프로세스 수를 줄여 총 메모리 사용량을 효과적으로 억제할 수 있습니다. max_connections를 무작정 높이는 것은 work_mem × max_connections의 잠재적 최대 메모리 소비를 기하급수적으로 증가시키므로, 실제 동시 접속 패턴을 분석한 후 적절한 값으로 유지해야 합니다. 일반적으로 물리 메모리 16GB 서버 기준 max_connections = 100~200, work_mem = 32~64MB를 출발점으로 삼고 부하 테스트를 통해 최적값을 도출하는 것을 권장합니다.
관련 에러
- 53100 (disk full): 메모리 부족으로 인해 임시 파일을 디스크에 기록할 때 디스크 공간도 동시에 부족한 경우 함께 발생할 수 있습니다.
- 53300 (too many connections): 과도한 동시 접속이 메모리 고갈의 직접적인 원인이 되므로 53200과 연쇄적으로 나타나는 경우가 많습니다.
- 57P01 (admin shutdown) / 57P02 (crash shutdown): OOM Killer에 의해 PostgreSQL 프로세스가 강제 종료된 후 재시작 과정에서 기록될 수 있습니다.
- 42P19 (invalid_recursion): 재귀 CTE(WITH RECURSIVE)가 무한 루프에 빠질 경우 메모리를 계속 소모하다가 53200으로 이어지기도 합니다.
주요 DBMS error code를 정리하는 시리즈입니다.
블로그 홈에서 다른 에러도 확인하세요.
본 포스트는 AI가 생성한 기술 가이드입니다. 운영 환경 적용 전 충분한 검토를 권장합니다.