2026년 08월 17일 | DBMS Error 가이드
이 글에서 다루는 내용
ORA-02298 에러의 원인 분석, 해결 SQL, 예방 방법을 실무 관점에서 정리합니다.
ORA-02298 cannot validate – parent keys not found 는?
ORA-02298 에러는 외래 키(Foreign Key) 제약 조건을 활성화하거나 새로 추가하려고 할 때, 자식 테이블의 데이터 중 부모 테이블에 존재하지 않는 키 값이 있을 경우 발생하는 에러입니다. 즉, 참조 무결성(Referential Integrity)을 위반하는 데이터가 이미 자식 테이블에 존재할 때 Oracle이 제약 조건 검증을 거부하면서 발생합니다. 데이터 마이그레이션, 대량 데이터 적재(Bulk Load), 또는 오랫동안 비활성화되어 있던 제약 조건을 다시 활성화하는 상황에서 특히 자주 목격되는 에러입니다.
주요 발생 원인
1. ENABLE VALIDATE 시 고아 데이터(Orphan Data) 존재
가장 흔한 원인으로, 외래 키 제약 조건이 DISABLE 상태였던 동안 부모 테이블에 존재하지 않는 값이 자식 테이블에 삽입된 경우입니다. 제약 조건을 다시 ENABLE VALIDATE로 전환하려 할 때, Oracle은 기존 데이터 전체를 검증하므로 이러한 고아 데이터가 있으면 즉시 ORA-02298이 발생합니다. 특히 ETL 작업이나 야간 배치 처리 중 제약을 해제한 후 복원하는 상황에서 빈번하게 나타납니다.
2. 데이터 마이그레이션 또는 초기 데이터 적재 순서 오류
부모 테이블보다 자식 테이블에 데이터를 먼저 삽입하거나, 부모 테이블의 일부 데이터가 누락된 상태에서 외래 키 제약을 추가하려 할 때 발생합니다. 레거시 시스템에서 데이터를 이관할 때 적재 순서를 잘못 설정하거나, 부모 데이터의 일부가 변환 과정에서 유실되는 경우가 대표적입니다. 이 경우 단순히 제약 조건 문제가 아니라 데이터 품질 문제와 직결되어 있으므로 반드시 근본 원인을 파악해야 합니다.
3. 참조하는 부모 키가 삭제 또는 변경된 경우
자식 테이블에 데이터가 있는 상태에서 부모 테이블의 키 값이 직접 삭제되거나 업데이트된 후, 외래 키 제약을 다시 검증하려 할 때 발생합니다. ON DELETE CASCADE 또는 ON DELETE SET NULL 옵션이 설정되어 있지 않은 외래 키 제약에서 부모 레코드를 무단으로 삭제하면, 이미 참조가 깨진 상태에서 제약 조건 활성화 시 이 에러가 나타납니다.
해결 방법
STEP 1. 고아 데이터 식별
먼저 어떤 자식 레코드가 부모 테이블에 매칭되는 값이 없는지 확인합니다.
-- 고아 데이터(Orphan Data) 조회
-- 예시: ORDERS 테이블이 CUSTOMERS 테이블을 참조하는 경우
SELECT o.order_id, o.customer_id
FROM orders o
WHERE NOT EXISTS (
SELECT 1
FROM customers c
WHERE c.customer_id = o.customer_id
);
-- 또는 LEFT OUTER JOIN 방식으로 확인
SELECT o.order_id, o.customer_id
FROM orders o
LEFT OUTER JOIN customers c ON o.customer_id = c.customer_id
WHERE c.customer_id IS NULL;
STEP 2-A. 고아 데이터 삭제 (데이터가 불필요한 경우)
부모에 존재하지 않는 자식 데이터가 실제로 불필요한 더미 데이터라면 삭제합니다.
-- 고아 데이터 삭제
DELETE FROM orders o
WHERE NOT EXISTS (
SELECT 1
FROM customers c
WHERE c.customer_id = o.customer_id
);
COMMIT;
-- 이후 제약 조건 활성화
ALTER TABLE orders ENABLE VALIDATE CONSTRAINT fk_orders_customers;
STEP 2-B. 부모 데이터 보완 (누락된 부모 데이터 삽입)
자식 데이터는 유효하나 부모 테이블에 데이터가 누락된 경우, 부모 데이터를 먼저 삽입합니다.
-- 누락된 부모 데이터 삽입
INSERT INTO customers (customer_id, customer_name, created_date)
SELECT DISTINCT o.customer_id, 'UNKNOWN', SYSDATE
FROM orders o
WHERE NOT EXISTS (
SELECT 1
FROM customers c
WHERE c.customer_id = o.customer_id
);
COMMIT;
-- 부모 데이터 보완 후 제약 조건 활성화
ALTER TABLE orders ENABLE VALIDATE CONSTRAINT fk_orders_customers;
STEP 2-C. ENABLE NOVALIDATE 옵션 활용 (임시 방편)
당장 제약 조건을 완전히 검증하기 어려운 상황에서 기존 데이터는 건너뛰고 향후 데이터부터 제약을 적용하는 방법입니다. 이는 임시 방편이므로 반드시 데이터 정제 작업을 병행해야 합니다.
-- 기존 데이터는 무시하고 신규 데이터부터 제약 적용
ALTER TABLE orders ENABLE NOVALIDATE CONSTRAINT fk_orders_customers;
-- 나중에 데이터 정제 후 완전 검증으로 전환
-- ALTER TABLE orders ENABLE VALIDATE CONSTRAINT fk_orders_customers;
STEP 3. 제약 조건 현황 확인
-- 제약 조건 상태 확인
SELECT constraint_name,
constraint_type,
status,
validated,
rely
FROM user_constraints
WHERE table_name = 'ORDERS'
AND constraint_type = 'R'; -- R = Referential (Foreign Key)
-- 참조 대상 테이블 및 컬럼 확인
SELECT a.constraint_name,
a.table_name AS child_table,
b.table_name AS parent_table,
c.column_name AS child_column,
d.column_name AS parent_column
FROM user_constraints a
JOIN user_constraints b ON a.r_constraint_name = b.constraint_name
JOIN user_cons_columns c ON a.constraint_name = c.constraint_name
JOIN user_cons_columns d ON b.constraint_name = d.constraint_name
WHERE a.table_name = 'ORDERS'
AND a.constraint_type = 'R';
예방 방법
1. 데이터 적재 시 부모→자식 순서 철저히 준수 및 제약 비활성화 최소화
ETL이나 데이터 마이그레이션 작업 시 반드시 부모 테이블 데이터를 먼저 적재한 후 자식 테이블 데이터를 적재하는 순서를 스크립트 레벨에서 강제합니다. 불가피하게 제약 조건을 비활성화해야 하는 경우에는 작업 완료 즉시 ENABLE VALIDATE로 복원하고, 복원 스크립트가 배치 잡의 마지막 단계에 반드시 포함되도록 자동화합니다.
-- 배치 작업 전후 제약 비활성화/활성화 패턴 예시
-- 작업 전
ALTER TABLE orders DISABLE CONSTRAINT fk_orders_customers;
-- 데이터 적재 작업 수행...
-- 작업 후 즉시 복원 (배치 스크립트 마지막 단계)
ALTER TABLE orders ENABLE VALIDATE CONSTRAINT fk_orders_customers;
2. 정기적인 참조 무결성 점검 스크립트 운영
운영 환경에서는 제약 조건이 NOVALIDATE 상태로 방치되거나 고아 데이터가 서서히 누적되는 경우가 있습니다. 아래와 같이 DBA_CONSTRAINTS를 주기적으로 점검하고, 고아 데이터 탐지 쿼리를 정기 모니터링 배치에 포함시켜 문제를 사전에 인지합니다.
-- NOVALIDATE 상태의 외래 키 제약 조건 목록 조회 (정기 점검용)
SELECT owner,
table_name,
constraint_name,
status,
validated
FROM dba_constraints
WHERE constraint_type = 'R'
AND validated = 'NOT VALIDATED'
ORDER BY owner, table_name;
관련 에러
- ORA-02291: 자식 테이블에 INSERT 또는 UPDATE 시 참조하는 부모 키가 존재하지 않을 때 발생하는 에러로, ORA-02298과 같은 참조 무결성 위반이지만 DML 시점에서 즉시 감지됩니다.
- ORA-02292: 부모 테이블의 레코드를 삭제하거나 업데이트할 때 자식 레코드가 존재하여 작업이 차단될 때 발생합니다.
- ORA-02449: 테이블을 DROP하려 할 때 해당 테이블의 기본 키나 유니크 키를 참조하는 외래 키가 다른 테이블에 존재할 경우 발생합니다.
주요 DBMS error code를 정리하는 시리즈입니다.
블로그 홈에서 다른 에러도 확인하세요.
본 포스트는 AI가 생성한 기술 가이드입니다. 운영 환경 적용 전 충분한 검토를 권장합니다.