2026년 08월 31일 | DBMS Error 가이드
이 글에서 다루는 내용
2BP01 에러의 원인 분석, 해결 SQL, 예방 방법을 실무 관점에서 정리합니다.
2BP01 dependent objects still exist 는?
PostgreSQL 에러 코드 2BP01은 특정 데이터베이스 객체를 삭제하려 할 때, 해당 객체에 의존하는 다른 객체가 존재하는 경우 발생하는 에러입니다. 예를 들어 테이블, 스키마, 함수, 타입 등을 DROP 명령으로 제거하려 할 때, 해당 객체를 참조하고 있는 뷰(View), 외래키(Foreign Key), 함수, 트리거 등이 남아 있다면 PostgreSQL은 이 에러를 발생시키며 작업을 거부합니다. 이는 데이터베이스의 참조 무결성과 객체 간 의존성을 보호하기 위한 PostgreSQL의 안전장치로, 의도치 않은 연쇄 삭제를 방지하는 중요한 메커니즘입니다.
주요 발생 원인
1. 다른 뷰(View) 또는 Materialized View가 해당 테이블/컬럼을 참조하는 경우
가장 빈번하게 발생하는 원인으로, 특정 테이블이나 컬럼을 기반으로 생성된 뷰가 존재할 때 원본 테이블을 삭제하려 하면 이 에러가 발생합니다. 운영 환경에서는 여러 개의 뷰가 복잡하게 중첩 참조되는 경우가 많아, 단순히 눈에 보이는 뷰 하나만 삭제해도 해결되지 않는 상황이 자주 생깁니다.
2. 외래키 제약(Foreign Key Constraint)으로 다른 테이블이 참조하는 경우
부모 테이블을 삭제하려 할 때 자식 테이블에 해당 부모 테이블의 기본키를 참조하는 외래키 제약이 걸려 있으면 에러가 발생합니다. 특히 수십 개의 테이블이 연쇄적으로 외래키를 맺고 있는 복잡한 스키마에서는 의존성 관계를 파악하지 않고 삭제를 시도하면 반드시 이 에러를 만나게 됩니다.
3. 함수, 트리거, 도메인, 타입 등의 객체가 참조하는 경우
사용자 정의 타입(Custom Type), 도메인(Domain), 함수(Function) 등을 삭제하려 할 때 해당 객체를 컬럼 타입으로 사용하는 테이블이나 이를 내부적으로 호출하는 함수, 트리거가 있으면 에러가 발생합니다. 이 경우는 의존성이 눈에 잘 보이지 않아 초보 DBA들이 특히 당황하기 쉬운 케이스입니다.
해결 방법
해결 1: CASCADE 옵션으로 연쇄 삭제
가장 빠른 해결책은 DROP 명령에 CASCADE 옵션을 추가하는 것입니다. 단, 이 옵션은 의존 객체를 모두 함께 삭제하므로 반드시 사전에 어떤 객체가 함께 삭제되는지 확인해야 합니다.
-- 테이블 삭제 시 의존 객체 함께 삭제
DROP TABLE orders CASCADE;
-- 스키마 삭제 시 포함된 모든 객체 함께 삭제
DROP SCHEMA sales CASCADE;
-- 함수 삭제 시 의존 트리거 등 함께 삭제
DROP FUNCTION calculate_discount(numeric) CASCADE;
-- 타입 삭제 시 연관 객체 함께 삭제
DROP TYPE order_status CASCADE;
해결 2: 의존성 확인 후 순서대로 삭제
pg_depend 시스템 카탈로그를 활용하면 어떤 객체가 대상 객체에 의존하는지 정확히 파악할 수 있습니다.
-- 특정 테이블에 의존하는 객체 확인
SELECT
dep.classid::regclass AS dependent_type,
dep.objid,
obj.relname AS dependent_object_name,
dep.deptype
FROM pg_depend dep
JOIN pg_class obj ON dep.objid = obj.oid
WHERE dep.refobjid = 'orders'::regclass
AND dep.deptype = 'n';
-- 뷰 의존성 확인 (더 직관적인 방법)
SELECT
v.table_schema,
v.table_name AS view_name,
v.view_definition
FROM information_schema.views v
WHERE v.view_definition ILIKE '%orders%';
-- 외래키 의존성 확인
SELECT
tc.table_schema,
tc.table_name AS child_table,
kcu.column_name,
ccu.table_name AS parent_table,
tc.constraint_name
FROM information_schema.table_constraints tc
JOIN information_schema.key_column_usage kcu
ON tc.constraint_name = kcu.constraint_name
JOIN information_schema.constraint_column_usage ccu
ON ccu.constraint_name = tc.constraint_name
WHERE tc.constraint_type = 'FOREIGN KEY'
AND ccu.table_name = 'orders';
의존성을 확인한 후에는 의존하는 객체부터 역순으로 삭제합니다.
-- 의존 뷰 먼저 삭제
DROP VIEW IF EXISTS v_order_summary;
DROP VIEW IF EXISTS v_order_details;
-- 외래키 제약 먼저 제거
ALTER TABLE order_items DROP CONSTRAINT fk_order_items_orders;
-- 이후 원본 테이블 삭제
DROP TABLE orders;
해결 3: 외래키 제약만 일시적으로 비활성화 후 삭제
-- 트랜잭션 내에서 외래키 제약 비활성화 후 작업 (세션 레벨)
SET session_replication_role = 'replica';
DROP TABLE orders;
-- 작업 완료 후 원복
SET session_replication_role = 'origin';
> ⚠️ 주의: session_replication_role 방식은 해당 세션의 모든 트리거와 외래키 검사를 비활성화하므로 매우 신중하게 사용해야 합니다.
해결 4: 사용자 정의 타입/도메인 의존성 해결
-- 특정 타입을 사용하는 컬럼 확인
SELECT
c.table_schema,
c.table_name,
c.column_name,
c.udt_name
FROM information_schema.columns c
WHERE c.udt_name = 'order_status';
-- 컬럼 타입 변경 후 타입 삭제
ALTER TABLE orders ALTER COLUMN status TYPE VARCHAR(50) USING status::VARCHAR;
DROP TYPE order_status;
예방 방법
1. 삭제 전 의존성 점검 절차를 표준화하라
운영 환경에서 객체 삭제 작업을 수행하기 전, 반드시 의존성 점검 쿼리를 실행하는 것을 팀 내 표준 절차로 정의해야 합니다. 아래 쿼리를 체크리스트에 포함시키면 실수를 크게 줄일 수 있습니다.
-- 범용 의존성 점검 쿼리 (삭제 전 반드시 실행)
SELECT
classid::regclass AS object_type,
objid::regclass AS dependent_object,
deptype
FROM pg_depend
WHERE refobjid = '삭제_대상_객체명'::regclass
AND deptype IN ('n', 'a');
2. 개발/스테이징 환경에서 먼저 DROP RESTRICT로 검증하라
DROP 명령의 기본 동작은 RESTRICT(의존 객체 존재 시 거부)이며, 이를 개발 환경에서 먼저 실행하면 운영 환경 적용 전 의존성 문제를 안전하게 파악할 수 있습니다. CI/CD 파이프라인에 마이그레이션 스크립트 검증 단계를 추가하고, CASCADE 없이 먼저 실행해 의존성 에러가 발생하는지 확인하는 습관을 들이면 운영 환경에서의 사고를 사전에 방지할 수 있습니다.
관련 에러
23503foreign_key_violation: 외래키 제약 위반으로 데이터 삽입/수정 시 발생하며,2BP01과 유사하게 참조 무결성 관련 에러입니다.42P16invalid_table_definition: 테이블 정의 자체가 잘못된 경우 발생하며, 타입 의존성 문제와 연관될 수 있습니다.0A000feature_not_supported: 일부 CASCADE 작업이 지원되지 않는 컨텍스트에서 발생할 수 있습니다.42704undefined_object: 삭제하려는 객체 자체가 존재하지 않을 때 발생하며,DROP IF EXISTS구문으로 회피 가능합니다.
주요 DBMS error code를 정리하는 시리즈입니다.
블로그 홈에서 다른 에러도 확인하세요.
본 포스트는 AI가 생성한 기술 가이드입니다. 운영 환경 적용 전 충분한 검토를 권장합니다.