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

HV021
2026년 09월 26일 | DBMS Error 가이드

이 글에서 다루는 내용

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

HV021 fdw inconsistent descriptor information 는?

PostgreSQL에서 HV021 에러는 Foreign Data Wrapper(FDW)를 통해 외부 데이터 소스에 접근할 때, 외부 테이블의 컬럼 정의(descriptor)와 실제 원격 데이터 소스의 구조 사이에 불일치가 발생했음을 나타냅니다. 즉, FDW가 외부 테이블의 메타데이터를 읽거나 실행 계획을 수립하는 과정에서 예상했던 컬럼 타입, 순서, 또는 개수가 실제 원격 테이블의 것과 맞지 않을 때 이 에러가 발생합니다. 주로 postgres_fdw, file_fdw, oracle_fdw 등 다양한 FDW 구현체에서 공통적으로 발생할 수 있으며, 외부 테이블 정의 이후 원격 스키마가 변경된 경우 가장 빈번하게 나타납니다.


주요 발생 원인

1. 원격 테이블의 스키마 변경 후 외부 테이블 정의 미갱신

FDW로 연결된 외부 테이블(FOREIGN TABLE)을 생성한 이후, 원격 서버의 실제 테이블에 컬럼이 추가되거나 삭제되거나 타입이 변경되었을 때 로컬의 외부 테이블 정의가 업데이트되지 않으면 이 에러가 발생합니다. PostgreSQL의 FDW는 쿼리 실행 시점에 로컬 외부 테이블 메타데이터를 기반으로 디스크립터를 구성하는데, 이 정보가 원격 실제 데이터와 다를 경우 HV021이 트리거됩니다. 이는 실무에서 가장 흔한 원인으로, 특히 마이그레이션이나 스키마 배포 작업 이후 누락되는 경우가 많습니다.

2. 외부 테이블 컬럼 타입 불일치

로컬에서 외부 테이블을 정의할 때 컬럼 데이터 타입을 원격 테이블과 다르게 지정하면, FDW가 데이터를 가져오는 과정에서 디스크립터 불일치를 감지하고 에러를 발생시킵니다. 예를 들어, 원격 테이블의 컬럼이 BIGINT인데 로컬 외부 테이블에서 INTEGER로 정의했거나, TEXT를 VARCHAR(50)으로 정의하여 실제 데이터 변환이 불가능한 경우가 해당됩니다. 이 문제는 초기 외부 테이블 생성 시 충분한 검토 없이 빠르게 작업했을 때 자주 발생합니다.

3. FDW 드라이버 버전 또는 구현 버그

특정 FDW 익스텐션의 구버전이나 버그가 있는 버전을 사용할 경우, 디스크립터 정보를 올바르게 처리하지 못해 HV021이 발생하기도 합니다. 예를 들어, oracle_fdw나 jdbc_fdw 같은 서드파티 FDW는 PostgreSQL 메이저 버전 업그레이드 이후 호환성 문제가 발생할 수 있습니다. FDW 익스텐션이 현재 PostgreSQL 버전에 맞게 컴파일되고 업데이트되어 있는지 반드시 확인해야 합니다.


해결 방법

원인 1 해결: 외부 테이블 재정의 또는 IMPORT FOREIGN SCHEMA 활용

원격 테이블 스키마를 기준으로 외부 테이블을 재생성하거나, IMPORT FOREIGN SCHEMA를 사용하여 자동으로 동기화합니다.

-- 기존 외부 테이블 삭제
DROP FOREIGN TABLE IF EXISTS public.orders_foreign;

-- 원격 스키마를 자동으로 임포트하여 외부 테이블 재생성
IMPORT FOREIGN SCHEMA public
    LIMIT TO (orders)
    FROM SERVER remote_pg_server
    INTO public;

-- 또는 수동으로 최신 스키마에 맞게 외부 테이블을 다시 생성
CREATE FOREIGN TABLE public.orders_foreign (
    order_id   BIGINT NOT NULL,
    user_id    BIGINT NOT NULL,
    order_date TIMESTAMP WITH TIME ZONE,
    status     VARCHAR(50),
    total_amt  NUMERIC(15, 2)
)
SERVER remote_pg_server
OPTIONS (schema_name 'public', table_name 'orders');
-- 현재 외부 테이블의 컬럼 정의 확인
SELECT attname, atttypid::regtype, attnum
FROM pg_attribute
WHERE attrelid = 'public.orders_foreign'::regclass
  AND attnum > 0
ORDER BY attnum;

원인 2 해결: 컬럼 타입 수정

외부 테이블의 컬럼 타입을 원격 테이블과 일치시킵니다. PostgreSQL FDW는 ALTER FOREIGN TABLE을 통해 컬럼 타입을 수정할 수 있습니다.

-- 외부 테이블 컬럼 타입 변경 예시
ALTER FOREIGN TABLE public.orders_foreign
    ALTER COLUMN order_id TYPE BIGINT;

ALTER FOREIGN TABLE public.orders_foreign
    ALTER COLUMN total_amt TYPE NUMERIC(15, 2);

-- 컬럼 추가 (원격에 새로 추가된 컬럼 반영)
ALTER FOREIGN TABLE public.orders_foreign
    ADD COLUMN updated_at TIMESTAMP WITH TIME ZONE;

-- 컬럼 삭제 (원격에서 삭제된 컬럼 제거)
ALTER FOREIGN TABLE public.orders_foreign
    DROP COLUMN IF EXISTS deprecated_col;
-- 원격 테이블 구조 확인 (postgres_fdw 사용 시 dblink 활용)
SELECT *
FROM dblink(
    'host=remote_host port=5432 dbname=mydb user=myuser password=mypass',
    $$ SELECT column_name, data_type, character_maximum_length
       FROM information_schema.columns
       WHERE table_schema = 'public'
         AND table_name = 'orders'
       ORDER BY ordinal_position $$
) AS t(column_name TEXT, data_type TEXT, char_max_length INTEGER);

원인 3 해결: FDW 익스텐션 업데이트

-- 현재 설치된 FDW 익스텐션 버전 확인
SELECT name, default_version, installed_version
FROM pg_available_extensions
WHERE name LIKE '%fdw%';

-- FDW 익스텐션 업데이트
ALTER EXTENSION postgres_fdw UPDATE;

-- 필요 시 재설치 (서드파티 FDW의 경우 OS 레벨에서 패키지 업그레이드 후 실행)
DROP EXTENSION IF EXISTS oracle_fdw CASCADE;
CREATE EXTENSION oracle_fdw;

-- Foreign Server 및 User Mapping 재설정
CREATE SERVER oracle_server
    FOREIGN DATA WRAPPER oracle_fdw
    OPTIONS (dbserver '//oracle-host:1521/ORCL');

CREATE USER MAPPING FOR myuser
    SERVER oracle_server
    OPTIONS (user 'oracle_user', password 'oracle_pass');

예방 방법

1. 원격 스키마 변경 시 자동 동기화 프로세스 구축

원격 데이터베이스의 스키마 변경이 발생할 때마다 로컬 외부 테이블을 자동으로 재동기화하는 CI/CD 파이프라인 또는 스크립트를 구축하는 것이 중요합니다. 아래와 같이 스키마 버전 비교 스크립트를 주기적으로 실행하여 불일치를 조기에 탐지하세요.

-- 외부 테이블 컬럼 정의와 원격 실제 테이블 구조를 비교하는 점검 쿼리
-- (postgres_fdw 환경에서 information_schema 활용)
WITH local_cols AS (
    SELECT attname AS col_name,
           atttypid::regtype::TEXT AS col_type,
           attnum AS col_order
    FROM pg_attribute
    WHERE attrelid = 'public.orders_foreign'::regclass
      AND attnum > 0
      AND NOT attisdropped
),
remote_cols AS (
    SELECT *
    FROM dblink(
        'host=remote_host dbname=mydb user=myuser password=mypass',
        $$ SELECT column_name, data_type, ordinal_position
           FROM information_schema.columns
           WHERE table_schema = 'public' AND table_name = 'orders'
           ORDER BY ordinal_position $$
    ) AS r(col_name TEXT, col_type TEXT, col_order INTEGER)
)
SELECT
    COALESCE(l.col_name, r.col_name) AS column_name,
    l.col_type AS local_type,
    r.col_type AS remote_type,
    CASE WHEN l.col_name IS NULL THEN '원격에만 존재'
         WHEN r.col_name IS NULL THEN '로컬에만 존재'
         WHEN l.col_type != r.col_type THEN '타입 불일치'
         ELSE '일치'
    END AS status
FROM local_cols l
FULL OUTER JOIN remote_cols r ON l.col_name = r.col_name
ORDER BY COALESCE(l.col_order, r.col_order);

2. 스테이징 환경에서 FDW 연결 사전 검증 및 모니터링

운영 환경에 스키마 변경을 적용하기 전, 반드시 스테이징 환경에서 외부 테이블 쿼리를 검증하십시오. 또한 PostgreSQL의 log_fdw 관련 파라미터와 모니터링 도구를 통해 FDW 쿼리 실행 오류를 실시간으로 감지하고 알림을 설정하는 것이 좋습니다.

-- FDW 연결 상태 및 쿼리 정상 여부 점검용 헬스체크 쿼리
-- 이를 cron job 또는 모니터링 시스템에 등록하여 주기적으로 실행
DO $$
DECLARE
    v_count INTEGER;
BEGIN
    -- 외부 테이블에서 소량 데이터 조회 테스트
    SELECT COUNT(*) INTO v_count
    FROM public.orders_foreign
    LIMIT 1;

    RAISE NOTICE 'FDW 헬스체크 통과: orders_foreign 테이블 접근 정상 (count: %)', v_count;
EXCEPTION
    WHEN OTHERS THEN
        RAISE WARNING 'FDW 헬스체크 실패: % (SQLSTATE: %)', SQLERRM, SQLSTATE;
END;
$$;

관련 에러

  • HV000 (fdw_error): FDW 관련 일반적인 에러의 부모 에러 코드로, HV021이 해결되지 않을 경우 이 코드로 포괄적으로 보고되기도 합니다.
  • HV002 (fdw_column_name_not_found): 외부 테이블에 정의된 컬럼 이름이 원격 테이블에 존재하지 않을 때 발생하며, HV021과 함께 나타날 수 있습니다.
  • HV090 (fdw_invalid_string_length_or_buffer_length): 컬럼 크기 불일치로 인해 데이터 변환 중 버퍼 오버플로우가 발생할 때 나타나며, 타입 불일치 문제와 밀접하게 연관됩니다.
  • HV00R (fdw_unable_to_establish_connection): FDW가 원격 서버에 연결 자체를 못할 때 발생하며, 연결 설정 점검이 필요합니다.

DBMS 에러 코드 시리즈

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

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

댓글 남기기