PostgreSQL 42P06 오류 원인과 해결 방법 완벽 가이드

42P06
2026년 07월 10일 | DBMS Error 가이드

이 글에서 다루는 내용

42P06 에러의 원인 분석, 해결 SQL, 예방 방법을 실무 관점에서 정리합니다.

42P06 duplicate schema 는?

PostgreSQL 에러 코드 42P06은 duplicate schema 에러로, 이미 데이터베이스 내에 동일한 이름의 스키마가 존재하는 상황에서 CREATE SCHEMA 명령을 실행할 때 발생합니다. 이 에러는 SQL 표준 에러 클래스 42(Syntax Error or Access Rule Violation)에 속하며, 구조적 중복을 방지하기 위해 PostgreSQL이 엄격하게 처리하는 에러입니다. 특히 배포 자동화 스크립트, 마이그레이션 도구, 또는 여러 개발자가 동시에 작업하는 환경에서 자주 마주치게 되는 에러입니다.


주요 발생 원인

  • 마이그레이션 스크립트 중복 실행

가장 흔한 원인 중 하나입니다. CI/CD 파이프라인이나 배포 자동화 과정에서 마이그레이션 스크립트가 멱등성(idempotency) 없이 작성된 경우, 동일한 CREATE SCHEMA 구문이 두 번 이상 실행됩니다. Flyway, Liquibase와 같은 마이그레이션 도구를 사용하더라도, 마이그레이션 히스토리 테이블이 손상되거나 초기화된 경우 동일한 스크립트가 재실행될 수 있습니다.

  • IF NOT EXISTS 누락

개발자가 CREATE SCHEMA 명령을 작성할 때 IF NOT EXISTS 옵션을 명시하지 않는 경우입니다. 특히 여러 환경(개발, 스테이징, 운영)에서 공통으로 사용되는 초기화 스크립트에서 이 옵션을 빠뜨리면, 이미 스키마가 존재하는 환경에서는 반드시 에러가 발생합니다. 이는 코드 리뷰 단계에서 쉽게 놓칠 수 있는 실수입니다.

  • 멀티 테넌트 아키텍처에서의 동시성 문제

스키마 기반 멀티 테넌트(Multi-Tenant) 아키텍처에서 각 테넌트마다 별도의 스키마를 동적으로 생성하는 경우, 동일한 테넌트에 대한 요청이 거의 동시에 들어오면 두 트랜잭션이 동시에 같은 스키마를 생성하려 시도할 수 있습니다. 이 경우 한 트랜잭션은 성공하고 나머지 트랜잭션은 42P06 에러를 발생시키며 실패하게 됩니다. 이는 애플리케이션 레벨의 동시성 제어 없이 순수하게 DB 레벨에서만 스키마를 생성할 때 특히 위험합니다.


해결 방법

원인 1: 마이그레이션 스크립트 중복 실행 해결

기존에 작성된 마이그레이션 스크립트를 멱등성 있게 수정합니다. IF NOT EXISTS를 추가하는 것이 핵심입니다.

-- ❌ 문제가 되는 코드 (중복 실행 시 에러 발생)
CREATE SCHEMA app_data;

-- ✅ 개선된 코드 (중복 실행해도 안전)
CREATE SCHEMA IF NOT EXISTS app_data;

이미 스키마가 존재하는지 먼저 확인하고 싶다면 pg_namespace 시스템 카탈로그를 조회할 수 있습니다.

-- 스키마 존재 여부 직접 확인
SELECT schema_name
FROM information_schema.schemata
WHERE schema_name = 'app_data';

-- 또는 pg_namespace 활용
SELECT nspname
FROM pg_namespace
WHERE nspname = 'app_data';

원인 2: IF NOT EXISTS 누락 해결

모든 CREATE SCHEMA 구문에 IF NOT EXISTS를 추가하여 방어적으로 작성합니다.

-- 스키마 생성 + 소유자 지정 (IF NOT EXISTS 포함)
CREATE SCHEMA IF NOT EXISTS reporting
    AUTHORIZATION analyst_role;

-- DO 블록을 활용한 조건부 스키마 생성 (PostgreSQL 9.3 이하 호환)
DO $$
BEGIN
    IF NOT EXISTS (
        SELECT 1 FROM pg_namespace WHERE nspname = 'reporting'
    ) THEN
        CREATE SCHEMA reporting AUTHORIZATION analyst_role;
        RAISE NOTICE 'Schema reporting created successfully.';
    ELSE
        RAISE NOTICE 'Schema reporting already exists. Skipping.';
    END IF;
END
$$;

원인 3: 멀티 테넌트 동시성 문제 해결

Advisory Lock을 활용하여 동시에 같은 스키마가 생성되는 것을 방지합니다.

-- Advisory Lock을 사용한 안전한 스키마 생성 함수
CREATE OR REPLACE FUNCTION create_tenant_schema(tenant_id TEXT)
RETURNS VOID AS $$
DECLARE
    schema_name TEXT := 'tenant_' || tenant_id;
    lock_key    BIGINT := hashtext(schema_name);
BEGIN
    -- 세션 레벨 Advisory Lock 획득 (다른 세션은 대기)
    PERFORM pg_advisory_lock(lock_key);

    BEGIN
        -- 이미 존재하면 건너뜀
        IF NOT EXISTS (
            SELECT 1 FROM pg_namespace WHERE nspname = schema_name
        ) THEN
            EXECUTE format('CREATE SCHEMA %I', schema_name);
            RAISE NOTICE 'Schema % created.', schema_name;
        ELSE
            RAISE NOTICE 'Schema % already exists.', schema_name;
        END IF;
    EXCEPTION
        WHEN duplicate_schema THEN
            -- 동시성으로 인한 에러도 안전하게 처리
            RAISE NOTICE 'Schema % was created by another session.', schema_name;
    END;

    -- Lock 해제
    PERFORM pg_advisory_unlock(lock_key);
END;
$$ LANGUAGE plpgsql;

-- 사용 예시
SELECT create_tenant_schema('acme_corp');
SELECT create_tenant_schema('globex');

애플리케이션 코드에서 42P06 에러를 명시적으로 핸들링하는 것도 좋은 방법입니다.

-- 에러 코드로 분기하는 PL/pgSQL 예외 처리
DO $$
BEGIN
    CREATE SCHEMA new_tenant_schema;
EXCEPTION
    WHEN duplicate_schema THEN  -- SQLSTATE '42P06'
        RAISE WARNING 'Schema already exists, continuing...';
    WHEN OTHERS THEN
        RAISE;  -- 다른 에러는 재발생
END;
$$;

예방 방법

  • 모든 DDL 스크립트에 IF NOT EXISTS 표준화

팀 내 코딩 컨벤션으로 CREATE SCHEMA, CREATE TABLE, CREATE INDEX 등 모든 오브젝트 생성 DDL에 IF NOT EXISTS를 의무적으로 사용하도록 규칙을 정합니다. Git pre-commit hook이나 CI 파이프라인에서 IF NOT EXISTS 없는 CREATE SCHEMA 구문을 자동으로 검출하는 린트 규칙을 추가하면 코드 리뷰 전에 미리 차단할 수 있습니다.

“`sql

— 팀 표준 스키마 초기화 템플릿

CREATE SCHEMA IF NOT EXISTS app_core;

CREATE SCHEMA IF NOT EXISTS app_audit;

CREATE SCHEMA IF NOT EXISTS app_reporting;

“`

  • 마이그레이션 도구의 상태 관리 철저히 유지

Flyway나 Liquibase를 사용한다면 마이그레이션 히스토리 테이블(flyway_schema_history, databasechangelog)을 절대 수동으로 수정하거나 삭제하지 않습니다. 운영 환경에서 스키마 변경이 필요한 경우 반드시 새 마이그레이션 파일을 추가하고, 기존 마이그레이션 파일을 수정하는 방식은 지양해야 합니다. 또한, 배포 전에 flyway validate 또는 liquibase status 명령으로 마이그레이션 상태를 사전 검증하는 습관을 들이는 것이 중요합니다.


관련 에러

  • 42P07 (duplicate_table): 이미 존재하는 테이블을 CREATE TABLE로 생성하려 할 때 발생하는 에러로, 42P06과 동일한 패턴으로 IF NOT EXISTS로 해결할 수 있습니다.
  • 42710 (duplicate_object): 이미 존재하는 데이터베이스 오브젝트(인덱스, 시퀀스, 타입 등)를 생성하려 할 때 발생합니다.
  • 42P04 (duplicate_database): CREATE DATABASE 시 동일한 이름의 데이터베이스가 이미 존재할 때 발생하며, createdb 명령에서도 동일하게 나타납니다.
  • 23505 (unique_violation): 데이터 레벨의 중복 에러로, DDL이 아닌 DML(INSERT, UPDATE) 시 UNIQUE 제약 위반 시 발생합니다.
DBMS 에러 코드 시리즈

주요 DBMS error code를 정리하는 시리즈입니다.
블로그 홈에서 다른 에러도 확인하세요.

본 포스트는 AI가 생성한 기술 가이드입니다. 운영 환경 적용 전 충분한 검토를 권장합니다.

댓글 남기기