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

42710
2026년 09월 14일 | DBMS Error 가이드

이 글에서 다루는 내용

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

42710 duplicate object 는?

PostgreSQL 에러 코드 42710은 duplicate_object 에러로, 이미 데이터베이스에 동일한 이름의 객체(오브젝트)가 존재할 때 발생합니다. 주로 CREATE 구문을 실행할 때 동일한 이름의 테이블, 인덱스, 시퀀스, 뷰, 타입, 역할(Role) 등이 이미 존재하는 경우에 트리거됩니다. 마이그레이션 스크립트를 반복 실행하거나, 여러 개발자가 동시에 DDL 작업을 수행할 때 자주 마주치는 에러입니다.


주요 발생 원인

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

배포 자동화 파이프라인(CI/CD)에서 마이그레이션 스크립트가 멱등성(Idempotency) 없이 작성된 경우, 동일한 CREATE TABLE 또는 CREATE INDEX 구문이 두 번 이상 실행될 수 있습니다. 특히 Flyway, Liquibase 같은 마이그레이션 도구를 사용하지 않고 수동으로 SQL 파일을 적용할 때 빈번하게 발생합니다. 배포 이후 롤백 후 재배포 시 이미 생성된 객체가 남아 있어 동일한 에러가 반복될 수 있습니다.

  • 인덱스 및 제약조건 이름 중복

테이블 생성 시 또는 ALTER TABLE 명령으로 제약조건(CONSTRAINT)이나 인덱스를 추가할 때 명시적으로 이름을 지정하지 않거나, 이미 존재하는 이름과 동일하게 지정하는 경우 에러가 발생합니다. PostgreSQL은 인덱스와 제약조건의 이름을 스키마 레벨에서 고유하게 관리하기 때문에, 서로 다른 테이블이라도 같은 스키마 안에서 동일한 인덱스 이름을 사용하면 충돌이 일어납니다. 여러 팀이 각자의 기능 브랜치에서 마이그레이션을 개발한 뒤 병합할 때 이런 문제가 자주 발생합니다.

  • 역할(Role) 또는 데이터베이스 중복 생성 시도

CREATE ROLE 또는 CREATE DATABASE 명령을 실행할 때 이미 동일한 이름의 역할이나 데이터베이스가 존재하는 경우에도 42710 에러가 발생합니다. 서버 초기화 스크립트나 Docker 컨테이너 시작 스크립트에서 조건 없이 CREATE ROLE을 실행하면 컨테이너가 재시작될 때마다 에러를 마주치게 됩니다. 이는 운영 환경보다는 개발 및 테스트 환경에서 특히 자주 발생합니다.


해결 방법

원인 1 해결: IF NOT EXISTS 절 사용

가장 단순하고 효과적인 해결 방법은 CREATE 구문에 IF NOT EXISTS 절을 추가하는 것입니다. 이 절은 동일한 이름의 객체가 이미 존재하면 에러 대신 경고(NOTICE)를 반환하고 실행을 계속합니다.

-- 기존 에러 발생 코드
CREATE TABLE users (
    id SERIAL PRIMARY KEY,
    email VARCHAR(255) NOT NULL
);

-- 해결: IF NOT EXISTS 사용
CREATE TABLE IF NOT EXISTS users (
    id SERIAL PRIMARY KEY,
    email VARCHAR(255) NOT NULL
);

-- 뷰에도 동일하게 적용 가능
CREATE OR REPLACE VIEW active_users AS
SELECT id, email FROM users WHERE is_active = true;

-- 시퀀스에도 적용
CREATE SEQUENCE IF NOT EXISTS user_id_seq START 1;

원인 2 해결: 인덱스/제약조건 존재 여부 확인 후 생성

인덱스의 경우 IF NOT EXISTS를 PostgreSQL 9.5 이상부터 지원합니다. 제약조건은 직접 지원하지 않으므로 카탈로그 조회를 통해 처리합니다.

-- 인덱스 중복 방지
CREATE INDEX IF NOT EXISTS idx_users_email ON users(email);

-- 제약조건 존재 여부 확인 후 추가 (DO 블록 활용)
DO $$
BEGIN
    IF NOT EXISTS (
        SELECT 1
        FROM information_schema.table_constraints
        WHERE constraint_schema = 'public'
          AND table_name = 'users'
          AND constraint_name = 'uq_users_email'
    ) THEN
        ALTER TABLE users ADD CONSTRAINT uq_users_email UNIQUE (email);
    END IF;
END
$$;

-- 기존 인덱스 조회 (사전 확인용)
SELECT indexname, tablename, indexdef
FROM pg_indexes
WHERE schemaname = 'public'
  AND tablename = 'users';

원인 3 해결: 역할 및 데이터베이스 중복 생성 방지

-- Role 중복 방지 (DO 블록 활용)
DO $$
BEGIN
    IF NOT EXISTS (
        SELECT 1 FROM pg_roles WHERE rolname = 'app_user'
    ) THEN
        CREATE ROLE app_user WITH LOGIN PASSWORD 'securepassword';
    END IF;
END
$$;

-- 데이터베이스 중복 방지
DO $$
BEGIN
    IF NOT EXISTS (
        SELECT 1 FROM pg_database WHERE datname = 'myapp_db'
    ) THEN
        -- 주의: CREATE DATABASE는 트랜잭션 블록 내에서 실행 불가
        -- 아래 구문은 psql 메타커맨드로 처리하거나 외부 스크립트에서 실행
        RAISE NOTICE 'Database myapp_db does not exist. Please create it manually.';
    END IF;
END
$$;

-- psql 커맨드라인에서 안전하게 처리하는 방법
-- psql -c "SELECT 1 FROM pg_database WHERE datname='myapp_db'" | grep -q 1 || createdb myapp_db

충돌하는 객체 강제 재생성 (주의: 데이터 손실 가능)

-- 기존 테이블 삭제 후 재생성 (운영 환경 사용 금지!)
DROP TABLE IF EXISTS staging_temp_table CASCADE;
CREATE TABLE staging_temp_table (
    id SERIAL PRIMARY KEY,
    data JSONB
);

-- 인덱스 재생성
DROP INDEX IF EXISTS idx_users_email;
CREATE INDEX idx_users_email ON users(email);

예방 방법

  • 모든 DDL 스크립트를 멱등성(Idempotent)하게 작성하라

마이그레이션 스크립트는 몇 번을 실행해도 동일한 결과를 보장해야 합니다. CREATE TABLE, CREATE INDEX, CREATE ROLE 등 모든 객체 생성 구문에는 반드시 IF NOT EXISTS를 기본으로 사용하고, 제약조건처럼 직접 지원이 안 되는 경우엔 DO $$ ... $$ 익명 블록으로 카탈로그를 조회하여 조건부 실행하는 패턴을 팀 전체 코딩 컨벤션으로 확립하세요. 이 습관 하나만으로 배포 파이프라인에서 발생하는 42710 에러의 90% 이상을 사전 차단할 수 있습니다.

  • 마이그레이션 도구를 도입하고 네이밍 컨벤션을 표준화하라

Flyway, Liquibase, Alembic(Python) 같은 마이그레이션 도구를 사용하면 스크립트 실행 이력을 DB에 저장하고 중복 실행을 자동으로 방지합니다. 또한 인덱스와 제약조건에는 {테이블명}_{컬럼명}_{타입} 형식의 명명 규칙(예: idx_users_email, uq_orders_order_number)을 팀 전체가 준수하도록 강제하면, 여러 개발자가 동시에 마이그레이션을 작성하더라도 이름 충돌 가능성을 크게 줄일 수 있습니다.


관련 에러

  • 42701 duplicate_column: ALTER TABLE ... ADD COLUMN 시 이미 존재하는 컬럼 이름을 추가하려 할 때 발생합니다.
  • 42P07 duplicate_table: CREATE TABLE 시 동일 스키마 내 같은 이름의 테이블이 이미 존재할 때 발생하며, 42710과 혼동하기 쉽습니다.
  • 23505 unique_violation: DDL이 아닌 DML(INSERT, UPDATE) 시점에 유니크 제약조건을 위반하는 데이터를 삽입할 때 발생하는 런타임 에러로, 42710과는 발생 시점이 다릅니다.
  • 42723 duplicate_function: 동일한 시그니처(함수명 + 인자 타입)의 함수를 CREATE FUNCTION으로 다시 생성하려 할 때 발생합니다. CREATE OR REPLACE FUNCTION으로 대부분 해결됩니다.

DBMS 에러 코드 시리즈

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

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

댓글 남기기