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

2202H
2026년 08월 14일 | DBMS Error 가이드

이 글에서 다루는 내용

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

2202H invalid tablesample argument 는?

PostgreSQL 에러 코드 2202H: invalid tablesample argumentTABLESAMPLE 절에 전달된 인수(argument)가 유효하지 않을 때 발생하는 에러입니다. TABLESAMPLE은 테이블에서 일부 행(row)을 무작위로 샘플링하여 반환하는 기능으로, BERNOULLI 또는 SYSTEM 방식을 지원하며, 각 방식은 0 이상 100 이하의 퍼센트 값을 인수로 받습니다. 이 범위를 벗어나거나 NULL, 문자열 등 잘못된 타입의 값을 전달하면 해당 에러가 발생합니다.


주요 발생 원인

1. 샘플링 퍼센트 값이 유효 범위(0~100)를 벗어난 경우

TABLESAMPLE의 인수는 반드시 0 이상 100 이하의 숫자여야 합니다. 예를 들어 -10이나 150 같은 값을 전달하면 PostgreSQL은 즉시 2202H 에러를 발생시킵니다. 이는 실수로 변수나 계산식의 결과를 그대로 전달할 때 자주 발생하는 패턴입니다.

2. NULL 값을 인수로 전달한 경우

애플리케이션 레이어에서 동적으로 샘플링 비율을 결정할 때 초기화되지 않은 변수나 쿼리 결과가 NULL로 반환되어 그대로 TABLESAMPLE 인수로 넘겨지는 경우가 있습니다. PostgreSQL은 NULL을 유효한 샘플링 인수로 허용하지 않으며, 이 경우에도 동일한 에러가 발생합니다. 특히 PL/pgSQL 함수 내에서 변수 초기화를 누락했을 때 자주 목격됩니다.

3. 잘못된 데이터 타입이나 표현식을 전달한 경우

TABLESAMPLE의 인수는 숫자형(numeric) 상수 또는 숫자형으로 캐스팅 가능한 표현식이어야 합니다. 문자열 리터럴('50')을 직접 넘기거나, 함수 반환값의 타입이 기대와 다를 경우 파싱 또는 실행 단계에서 에러가 발생합니다. 특히 동적 SQL을 생성하는 과정에서 타입 변환을 명시하지 않은 채 값을 삽입할 때 이 문제가 발생하기 쉽습니다.


해결 방법

원인 1: 범위를 벗어난 퍼센트 값 수정

올바른 범위(0~100) 내의 값을 전달해야 합니다. 아래는 잘못된 쿼리와 수정된 쿼리의 예제입니다.

-- ❌ 잘못된 예: 범위를 벗어난 값 (에러 발생)
SELECT * FROM orders TABLESAMPLE BERNOULLI(150);
-- ERROR:  invalid tablesample argument
-- DETAIL:  Argument must be between 0 and 100.

-- ❌ 잘못된 예: 음수 값 (에러 발생)
SELECT * FROM orders TABLESAMPLE SYSTEM(-10);
-- ERROR:  invalid tablesample argument

-- ✅ 올바른 예: 유효 범위 내의 값 사용
SELECT * FROM orders TABLESAMPLE BERNOULLI(10);

-- ✅ 동적으로 계산된 값에 CLAMP 적용 예시
DO $$
DECLARE
    sample_pct NUMERIC := 150; -- 잘못된 값이 들어왔다고 가정
BEGIN
    -- 값을 0~100 범위로 강제 조정
    sample_pct := GREATEST(0, LEAST(100, sample_pct));
    RAISE NOTICE 'Adjusted sample percentage: %', sample_pct;
END;
$$;

원인 2: NULL 값 처리

NULL이 전달될 가능성이 있는 경우 COALESCE를 사용하여 기본값을 설정하거나, PL/pgSQL에서 변수 초기화를 명확히 해야 합니다.

-- ❌ 잘못된 예: NULL 전달 (에러 발생)
-- 아래는 PL/pgSQL 내에서 NULL 변수를 그대로 사용하는 경우
DO $$
DECLARE
    sample_rate NUMERIC; -- 초기화하지 않음 (NULL)
    result RECORD;
BEGIN
    -- sample_rate가 NULL이므로 에러 발생
    FOR result IN
        EXECUTE 'SELECT * FROM orders TABLESAMPLE BERNOULLI(' || sample_rate || ')'
    LOOP
        RAISE NOTICE '%', result;
    END LOOP;
END;
$$;

-- ✅ 올바른 예: COALESCE로 기본값 처리
DO $$
DECLARE
    sample_rate NUMERIC := NULL; -- NULL 시나리오 가정
    safe_rate   NUMERIC;
    result      RECORD;
BEGIN
    -- NULL일 경우 기본값 10으로 대체
    safe_rate := COALESCE(sample_rate, 10);

    FOR result IN
        EXECUTE 'SELECT * FROM orders TABLESAMPLE BERNOULLI(' || safe_rate || ')'
    LOOP
        RAISE NOTICE '%', result;
    END LOOP;
END;
$$;

-- ✅ 일반 쿼리에서도 안전하게 처리
SELECT * FROM large_table
TABLESAMPLE BERNOULLI(COALESCE(NULL, 5));

원인 3: 잘못된 데이터 타입 처리

타입 캐스팅을 명시적으로 적용하고, 동적 SQL 생성 시 타입을 확인합니다.

-- ❌ 잘못된 예: 문자열을 그대로 전달 시도
-- (파서 레벨에서 막히거나 동적 SQL에서 에러 발생)
DO $$
DECLARE
    pct TEXT := '25 percent'; -- 잘못된 형식
BEGIN
    EXECUTE 'SELECT COUNT(*) FROM orders TABLESAMPLE BERNOULLI(' || pct || ')';
END;
$$;

-- ✅ 올바른 예: 명시적 타입 캐스팅 사용
DO $$
DECLARE
    pct TEXT    := '25';
    num_pct NUMERIC;
BEGIN
    -- 문자열을 NUMERIC으로 안전하게 변환
    num_pct := pct::NUMERIC;

    -- 범위 검증 추가
    IF num_pct < 0 OR num_pct > 100 THEN
        RAISE EXCEPTION 'Sample percentage must be between 0 and 100, got: %', num_pct;
    END IF;

    EXECUTE 'SELECT COUNT(*) FROM orders TABLESAMPLE BERNOULLI($1)' USING num_pct;
    RAISE NOTICE 'Query executed successfully with %% sampling', num_pct;
END;
$$;

-- ✅ 실무 활용: 대용량 테이블 분석을 위한 안전한 샘플링 함수
CREATE OR REPLACE FUNCTION safe_tablesample(
    p_table_name TEXT,
    p_percentage NUMERIC DEFAULT 10,
    p_method TEXT DEFAULT 'BERNOULLI'
)
RETURNS SETOF RECORD
LANGUAGE plpgsql
AS $$
DECLARE
    safe_pct NUMERIC;
    safe_method TEXT;
BEGIN
    -- 퍼센트 유효성 검사 및 보정
    safe_pct := GREATEST(0.001, LEAST(100, COALESCE(p_percentage, 10)));

    -- 메서드 유효성 검사
    IF p_method NOT IN ('BERNOULLI', 'SYSTEM') THEN
        RAISE EXCEPTION 'Invalid tablesample method: %. Use BERNOULLI or SYSTEM', p_method;
    END IF;
    safe_method := p_method;

    RETURN QUERY EXECUTE format(
        'SELECT * FROM %I TABLESAMPLE %s(%s)',
        p_table_name,
        safe_method,
        safe_pct
    );
END;
$$;

예방 방법

1. 입력값 유효성 검사 레이어 구축

TABLESAMPLE에 동적 값을 사용할 때는 반드시 애플리케이션 또는 함수 레이어에서 입력값 검증 로직을 구현하세요. GREATEST(0, LEAST(100, input_value))와 같은 패턴으로 값이 항상 유효 범위 안에 들어오도록 강제하고, NULL 가능성을 COALESCE로 방어하는 것을 습관화해야 합니다. 특히 사용자 입력이나 외부 시스템으로부터 받은 값을 직접 쿼리에 삽입할 때는 파라미터 바인딩(USING 절)을 사용하여 SQL 인젝션과 타입 에러를 동시에 방지하세요.

2. 샘플링 전용 래퍼 함수 및 테스트 코드 작성

위에서 소개한 safe_tablesample 같은 래퍼 함수를 팀 공용 유틸리티로 표준화하고, 이 함수에 대한 단위 테스트(pgTAP 등 활용)를 작성해 두면 팀 전체가 안전하게 샘플링을 활용할 수 있습니다. CI/CD 파이프라인에 경계값 테스트(0, 100, -1, 101, NULL)를 포함시켜 배포 전에 에러를 조기에 발견하는 체계를 마련하는 것이 장기적으로 매우 효과적입니다.


관련 에러

  • 2202G: invalid tablesample repeat: TABLESAMPLE 절에서 REPEATABLE 시드 값이 유효하지 않을 때 발생합니다. 시드 값 역시 특정 범위를 준수해야 하며, 이 에러와 유사한 맥락에서 발생합니다.
  • 22003: numeric_value_out_of_range: 샘플링 인수 계산 과정에서 숫자 오버플로우가 발생할 경우 연관되어 나타날 수 있습니다.
  • 42601: syntax_error: 동적 SQL로 TABLESAMPLE 쿼리를 구성할 때 형식 오류가 있으면 함께 발생하는 경우가 있어 디버깅 시 함께 확인이 필요합니다.
  • 42P01: undefined_table: TABLESAMPLE을 사용할 때 테이블 이름이 잘못된 경우 발생하며, 동적 쿼리에서 두 에러가 겹치는 상황이 생길 수 있습니다.
DBMS 에러 코드 시리즈

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

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

댓글 남기기