2026년 07월 19일 | DBMS Error 가이드
이 글에서 다루는 내용
57014 에러의 원인 분석, 해결 SQL, 예방 방법을 실무 관점에서 정리합니다.
57014 query canceled 는?
PostgreSQL 에러 코드 57014 query canceled는 실행 중인 쿼리가 외부 요인에 의해 강제로 중단되었을 때 발생하는 에러입니다. 가장 흔한 원인은 statement_timeout 설정으로 인해 허용된 실행 시간을 초과하거나, 사용자 혹은 관리자가 pg_cancel_backend() 함수를 통해 쿼리를 명시적으로 취소한 경우입니다. 또한 락 대기 시간 초과(lock_timeout), 유휴 트랜잭션 초과(idle_in_transaction_session_timeout) 등 다양한 타임아웃 설정이 복합적으로 작용하여 이 에러를 유발할 수 있습니다.
주요 발생 원인
- statement_timeout 초과
가장 빈번하게 발생하는 원인으로, 데이터베이스 또는 세션 레벨에서 설정된 statement_timeout 값을 쿼리 실행 시간이 초과할 때 발생합니다. 예를 들어, 수백만 건의 레코드를 조회하는 복잡한 집계 쿼리나 인덱스가 없는 컬럼에 대한 풀 스캔이 타임아웃의 주요 원인이 됩니다. 운영 환경에서는 일반적으로 statement_timeout을 수 초에서 수십 초 사이로 짧게 설정하므로, 무거운 분석 쿼리가 이 제한에 자주 걸리게 됩니다.
- lock_timeout 초과 또는 락 경합
여러 트랜잭션이 동일한 행이나 테이블에 동시에 접근하려 할 때 락 경합이 발생하며, 설정된 lock_timeout 시간 안에 락을 획득하지 못하면 쿼리가 취소됩니다. 특히 대량 UPDATE, DELETE 작업이나 DDL 명령(ALTER TABLE 등)이 실행 중일 때 다른 쿼리들이 오랫동안 대기 상태에 빠지는 경우가 많습니다. 이 경우 에러 메시지는 ERROR: canceling statement due to lock timeout으로 함께 출력되기도 합니다.
- 사용자 또는 관리자에 의한 명시적 취소
DBA 또는 모니터링 시스템이 pg_cancel_backend() 또는 pg_terminate_backend() 함수를 호출하여 특정 세션의 쿼리를 강제로 종료한 경우에도 이 에러가 발생합니다. 자동화된 슬로우 쿼리 킬러(slow query killer) 스크립트나 pgBouncer, AWS RDS의 쿼리 타임아웃 정책 등 외부 시스템이 개입하는 경우도 포함됩니다. 이 경우에는 PostgreSQL 로그에서 어느 백엔드가 취소 요청을 보냈는지 추적하는 것이 중요합니다.
해결 방법
1. statement_timeout 관련 해결
현재 세션 또는 특정 쿼리에 한해 타임아웃을 늘리거나 해제할 수 있습니다.
-- 현재 설정된 statement_timeout 확인
SHOW statement_timeout;
-- 현재 세션에서만 타임아웃 늘리기 (예: 5분)
SET statement_timeout = '5min';
-- 특정 트랜잭션 내에서만 타임아웃 늘리기
BEGIN;
SET LOCAL statement_timeout = '10min';
SELECT COUNT(*) FROM large_orders_table WHERE created_at > '2020-01-01';
COMMIT;
-- 무거운 분석 쿼리 실행 전 임시 해제 (주의: 운영 환경에서는 신중하게)
SET statement_timeout = 0;
SELECT
customer_id,
SUM(amount) AS total_amount,
COUNT(*) AS order_count
FROM orders
GROUP BY customer_id
ORDER BY total_amount DESC;
SET statement_timeout = '30s'; -- 작업 후 다시 원복
쿼리 자체를 최적화하는 것이 근본적인 해결책입니다. EXPLAIN ANALYZE로 실행 계획을 분석하고 적절한 인덱스를 추가하세요.
-- 실행 계획 분석
EXPLAIN (ANALYZE, BUFFERS, FORMAT TEXT)
SELECT *
FROM orders
WHERE customer_id = 12345 AND status = 'PENDING';
-- 누락된 인덱스 추가
CREATE INDEX CONCURRENTLY idx_orders_customer_status
ON orders (customer_id, status);
2. lock_timeout 관련 해결
락 대기로 인한 취소를 방지하려면, 먼저 현재 어떤 쿼리가 락을 보유하고 있는지 파악해야 합니다.
-- 현재 락을 보유한 세션 확인
SELECT
pid,
now() - pg_stat_activity.query_start AS duration,
query,
state
FROM pg_stat_activity
WHERE (now() - pg_stat_activity.query_start) > interval '5 seconds'
AND state != 'idle';
-- 락 충돌 현황 조회
SELECT
blocked_locks.pid AS blocked_pid,
blocked_activity.usename AS blocked_user,
blocking_locks.pid AS blocking_pid,
blocking_activity.usename AS blocking_user,
blocked_activity.query AS blocked_statement,
blocking_activity.query AS blocking_statement
FROM pg_catalog.pg_locks blocked_locks
JOIN pg_catalog.pg_stat_activity blocked_activity
ON blocked_activity.pid = blocked_locks.pid
JOIN pg_catalog.pg_locks blocking_locks
ON blocking_locks.locktype = blocked_locks.locktype
AND blocking_locks.relation = blocked_locks.relation
AND blocking_locks.pid != blocked_locks.pid
JOIN pg_catalog.pg_stat_activity blocking_activity
ON blocking_activity.pid = blocking_locks.pid
WHERE NOT blocked_locks.granted;
-- 락을 보유한 세션 취소 (취소 요청)
SELECT pg_cancel_backend(blocking_pid);
-- 락을 보유한 세션 강제 종료 (더 강한 방법)
SELECT pg_terminate_backend(blocking_pid);
3. 명시적 취소에 대한 대응
슬로우 쿼리 로그를 활성화하여 어떤 쿼리가 반복적으로 취소되는지 추적합니다.
-- postgresql.conf 또는 세션 레벨에서 슬로우 쿼리 로깅 설정
ALTER SYSTEM SET log_min_duration_statement = '3000'; -- 3초 이상 쿼리 로깅
ALTER SYSTEM SET log_lock_waits = 'on'; -- 락 대기 로깅
SELECT pg_reload_conf();
-- 현재 실행 중인 오래된 쿼리 확인
SELECT
pid,
usename,
application_name,
client_addr,
now() - query_start AS running_time,
state,
left(query, 100) AS query_snippet
FROM pg_stat_activity
WHERE state = 'active'
AND query_start < now() - interval '1 minute'
ORDER BY running_time DESC;
예방 방법
- 환경별 타임아웃 정책을 명확히 분리하여 설정하기
OLTP 환경(웹 애플리케이션)과 OLAP 환경(배치, 분석)의 타임아웃 값을 동일하게 설정하면 분석 쿼리가 자주 취소되거나, 반대로 느린 쿼리가 시스템을 점유하는 문제가 발생합니다. PostgreSQL의 Role(사용자) 레벨 또는 데이터베이스 레벨로 타임아웃을 분리하여 적용하는 것이 Best Practice입니다.
“`sql
— 애플리케이션 사용자에게는 짧은 타임아웃 적용
ALTER ROLE app_user SET statement_timeout = ’10s’;
— 분석/배치 사용자에게는 긴 타임아웃 적용
ALTER ROLE analytics_user SET statement_timeout = ’30min’;
— 특정 데이터베이스 전체에 기본 타임아웃 설정
ALTER DATABASE mydb SET statement_timeout = ’60s’;
“`
- 정기적인 인덱스 점검 및 쿼리 최적화 프로세스 운영
pg_stat_statements 확장을 활성화하여 실행 시간이 긴 쿼리를 주기적으로 모니터링하고, 인덱스 활용도가 낮은 쿼리를 사전에 최적화하는 것이 타임아웃 에러를 근본적으로 예방하는 방법입니다. 인덱스를 추가할 때는 운영 중 락을 방지하기 위해 반드시 CREATE INDEX CONCURRENTLY를 사용해야 합니다.
“`sql
— pg_stat_statements로 느린 쿼리 상위 10개 조회
SELECT
left(query, 80) AS query_snippet,
calls,
round(total_exec_time::numeric, 2) AS total_ms,
round(mean_exec_time::numeric, 2) AS mean_ms,
round((100 * total_exec_time / sum(total_exec_time) OVER ())::numeric, 2) AS pct
FROM pg_stat_statements
ORDER BY total_exec_time DESC
LIMIT 10;
“`
관련 에러
- 57P01 (
admin_shutdown): DBA가 서버를 종료하거나 재시작할 때 실행 중인 쿼리가 강제 종료되며 발생합니다. - 57P02 (
crash_shutdown): 서버 크래시로 인해 세션이 비정상 종료될 때 발생합니다. - 55P03 (
lock_not_available):NOWAIT옵션을 사용한 쿼리에서 즉시 락을 획득하지 못할 때 발생합니다. - 40P01 (
deadlock_detected): 두 개 이상의 트랜잭션이 서로의 락을 기다리는 교착 상태에서 발생하며, 57014와 함께 자주 혼동되는 에러입니다.
주요 DBMS error code를 정리하는 시리즈입니다.
블로그 홈에서 다른 에러도 확인하세요.
본 포스트는 AI가 생성한 기술 가이드입니다. 운영 환경 적용 전 충분한 검토를 권장합니다.