2026년 10월 05일 | DBMS Error 가이드
이 글에서 다루는 내용
ORA-29275 에러의 원인 분석, 해결 SQL, 예방 방법을 실무 관점에서 정리합니다.
ORA-29275 partial multibyte character 는?
ORA-29275 에러는 멀티바이트 문자(예: UTF-8, AL32UTF8 등)를 처리하는 과정에서 문자열이 도중에 잘려 불완전한 바이트 시퀀스가 발생했을 때 나타나는 오류입니다. 주로 CLOB, BLOB, VARCHAR2 데이터를 특정 바이트 길이로 자르거나 변환하는 과정에서 문자 경계를 무시하고 바이트 단위로 잘라낼 때 발생합니다. 특히 한국어, 중국어, 일본어처럼 한 문자가 2~4바이트를 차지하는 다국어 환경에서 SUBSTR, UTL_FILE, UTL_RAW 등의 함수를 사용할 때 자주 목격됩니다.
주요 발생 원인
1. SUBSTRB 또는 바이트 기반 문자열 처리 시 문자 경계 무시
SUBSTRB 함수는 문자(character) 단위가 아닌 바이트(byte) 단위로 문자열을 잘라냅니다. 한글이나 한자처럼 한 문자가 3바이트를 사용하는 경우, 중간 바이트에서 문자열을 자르면 불완전한 멀티바이트 문자가 남아 ORA-29275가 발생합니다.
예를 들어, '안녕하세요'를 SUBSTRB로 4바이트만 잘라내면 두 번째 문자(‘녕’)의 첫 번째 바이트만 남아 불완전한 시퀀스가 만들어집니다. 이 값을 이후 문자열 변환이나 출력 함수에 전달하면 에러가 발생합니다.
2. UTL_RAW 또는 UTL_FILE을 이용한 RAW 데이터 변환 시 문자 경계 오류
UTL_RAW.CAST_TO_VARCHAR2 또는 UTL_RAW.SUBSTR 함수를 사용하여 RAW 타입 데이터를 VARCHAR2로 변환하거나 일부분만 추출할 때, 멀티바이트 문자의 중간 바이트에서 잘리면 해당 에러가 발생합니다. RAW 데이터를 다루는 배치 프로그램이나 파일 I/O 처리 로직에서 자주 나타납니다.
특히 네트워크 또는 외부 시스템으로부터 수신한 RAW 데이터를 고정 크기 버퍼로 나누어 처리할 때 버퍼 크기가 문자 경계와 맞지 않으면 이 에러가 반복적으로 발생할 수 있습니다.
3. DBMS_LOB.SUBSTR을 사용한 CLOB 처리 시 바이트/문자 단위 혼용
DBMS_LOB.SUBSTR 함수는 기본적으로 문자 단위로 동작하지만, 내부적으로 데이터베이스 캐릭터 셋과 NLS 설정에 따라 바이트 변환 과정에서 문제가 생길 수 있습니다. CLOB 데이터를 VARCHAR2로 변환하는 과정에서 최대 길이(32767바이트)를 초과하거나 중간에 잘릴 때 멀티바이트 문자 경계 문제가 발생합니다.
또한, 대용량 CLOB 데이터를 페이징(Paging) 처리하거나 청크(Chunk) 단위로 나눌 때 청크 크기가 멀티바이트 문자의 경계와 정확히 맞지 않으면 이 에러가 발생합니다.
해결 방법
원인 1 해결: SUBSTRB 대신 SUBSTR 사용 또는 문자 경계 확인
문자 단위로 처리하는 SUBSTR을 사용하면 멀티바이트 문자 경계 문제를 피할 수 있습니다.
-- 잘못된 방법: SUBSTRB로 바이트 단위 자르기 (ORA-29275 유발 가능)
SELECT SUBSTRB('안녕하세요', 1, 4) FROM DUAL;
-- 올바른 방법: SUBSTR로 문자 단위 자르기
SELECT SUBSTR('안녕하세요', 1, 2) FROM DUAL; -- '안녕' 반환
-- 바이트 기준으로 자르되 문자 경계를 보장하는 방법
-- LENGTHB로 바이트 길이를 확인하고 안전하게 처리
SELECT SUBSTR('안녕하세요', 1,
LENGTH(SUBSTRB('안녕하세요', 1, 6))
) FROM DUAL;
바이트 기반으로 반드시 잘라야 하는 경우에는 아래와 같이 안전한 함수를 만들어 사용합니다.
-- 멀티바이트 안전 SUBSTRB 대체 함수
CREATE OR REPLACE FUNCTION SAFE_SUBSTRB(
p_str IN VARCHAR2,
p_start IN NUMBER,
p_len IN NUMBER
) RETURN VARCHAR2 IS
v_result VARCHAR2(32767);
v_byte_str VARCHAR2(32767);
BEGIN
v_byte_str := SUBSTRB(p_str, p_start, p_len);
-- 불완전한 멀티바이트 문자를 제거하기 위해 CONVERT 활용
v_result := CONVERT(v_byte_str, 'AL32UTF8', 'AL32UTF8');
RETURN v_result;
EXCEPTION
WHEN OTHERS THEN
-- 마지막 바이트를 하나씩 줄여가며 완전한 문자 경계 찾기
RETURN SUBSTRB(p_str, p_start, p_len - 1);
END;
/
원인 2 해결: UTL_RAW 처리 시 문자 경계 보정
-- RAW 데이터를 VARCHAR2로 변환할 때 안전하게 처리
DECLARE
v_raw RAW(100);
v_char VARCHAR2(200);
BEGIN
-- 테스트용 RAW 데이터 생성 (한글 '안녕' UTF-8 바이트)
v_raw := UTL_RAW.CAST_TO_RAW('안녕하세요');
-- 잘못된 방법: 중간 바이트에서 자르기
-- v_char := UTL_RAW.CAST_TO_VARCHAR2(UTL_RAW.SUBSTR(v_raw, 1, 4));
-- 올바른 방법: 전체 변환 후 문자 단위로 자르기
v_char := UTL_RAW.CAST_TO_VARCHAR2(v_raw);
v_char := SUBSTR(v_char, 1, 2); -- 문자 단위 처리
DBMS_OUTPUT.PUT_LINE('결과: ' || v_char);
END;
/
-- RAW 버퍼를 안전하게 나누는 방법
DECLARE
v_raw_data RAW(32767);
v_chunk RAW(1000);
v_str VARCHAR2(4000);
v_offset NUMBER := 1;
v_chunk_size NUMBER := 990; -- 멀티바이트 여유분 고려
BEGIN
-- 실제 데이터 로드 로직 (예시)
v_raw_data := UTL_RAW.CAST_TO_RAW('한글데이터샘플입니다테스트용도입니다');
WHILE v_offset <= UTL_RAW.LENGTH(v_raw_data) LOOP
v_chunk := UTL_RAW.SUBSTR(v_raw_data, v_offset, v_chunk_size);
-- EXCEPTION 처리로 ORA-29275 핸들링
BEGIN
v_str := UTL_RAW.CAST_TO_VARCHAR2(v_chunk);
EXCEPTION
WHEN OTHERS THEN
-- 청크 크기를 줄여 재시도
v_chunk := UTL_RAW.SUBSTR(v_raw_data, v_offset, v_chunk_size - 3);
v_str := UTL_RAW.CAST_TO_VARCHAR2(v_chunk);
END;
DBMS_OUTPUT.PUT_LINE(v_str);
v_offset := v_offset + UTL_RAW.LENGTH(v_chunk);
END LOOP;
END;
/
원인 3 해결: DBMS_LOB.SUBSTR 안전 처리
-- CLOB 데이터를 안전하게 VARCHAR2로 변환
DECLARE
v_clob CLOB;
v_result VARCHAR2(4000);
v_len NUMBER;
v_offset NUMBER := 1;
v_amount NUMBER := 1000; -- 문자 단위 청크 크기
BEGIN
-- 테스트용 CLOB 생성
v_clob := TO_CLOB('안녕하세요. 이것은 ORA-29275 테스트용 한글 데이터입니다. 멀티바이트 문자 처리를 안전하게 합니다.');
v_len := DBMS_LOB.GETLENGTH(v_clob);
WHILE v_offset <= v_len LOOP
-- 문자(character) 단위로 읽기 (바이트 단위 아님)
v_result := DBMS_LOB.SUBSTR(
lob_loc => v_clob,
amount => LEAST(v_amount, v_len - v_offset + 1), -- 문자 수
offset => v_offset -- 문자 위치
);
DBMS_OUTPUT.PUT_LINE('청크: ' || v_result);
v_offset := v_offset + v_amount;
END LOOP;
END;
/
-- CLOB을 VARCHAR2로 변환하는 안전한 함수
CREATE OR REPLACE FUNCTION CLOB_TO_VARCHAR2(
p_clob IN CLOB,
p_max_chars IN NUMBER DEFAULT 4000
) RETURN VARCHAR2 IS
v_result VARCHAR2(4000);
v_len NUMBER;
BEGIN
v_len := DBMS_LOB.GETLENGTH(p_clob);
IF v_len IS NULL OR v_len = 0 THEN
RETURN NULL;
END IF;
-- 문자 단위로 안전하게 추출
v_result := DBMS_LOB.SUBSTR(
lob_loc => p_clob,
amount => LEAST(p_max_chars, v_len),
offset => 1
);
RETURN v_result;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('CLOB 변환 오류: ' || SQLERRM);
RETURN NULL;
END;
/
-- 사용 예
SELECT CLOB_TO_VARCHAR2(clob_column, 2000)
FROM your_table
WHERE id = 1;
예방 방법
1. 문자 처리 함수는 반드시 문자(Character) 단위 함수 사용 원칙 수립
개발 가이드라인에 SUBSTRB, INSTRB, LENGTHB 등 바이트 기반 함수 사용을 금지하거나 반드시 문자 경계 검증 로직을 포함하도록 코딩 컨벤션을 정합니다. 대신 SUBSTR, INSTR, LENGTH 함수를 기본으로 사용하고, 바이트 단위 처리가 꼭 필요한 경우에는 전용 Wrapper 함수를 만들어 팀 내 공유합니다. 또한 NLS_CHARACTERSET을 AL32UTF8로 통일하여 예측 가능한 바이트 길이 환경을 조성합니다.
-- 현재 DB 캐릭터셋 확인
SELECT VALUE FROM NLS_DATABASE_PARAMETERS
WHERE PARAMETER = 'NLS_CHARACTERSET';
-- 세션 레벨 NLS 설정 확인
SELECT * FROM NLS_SESSION_PARAMETERS
WHERE PARAMETER IN ('NLS_CHARACTERSET', 'NLS_LENGTH_SEMANTICS');
-- 길이 단위를 CHAR로 설정하여 VARCHAR2 선언 시 문자 기준 적용
ALTER SESSION SET NLS_LENGTH_SEMANTICS = CHAR;
2. 데이터 입력 및 변환 시 유효성 검증 로직 구현
RAW, CLOB 등 이진 또는 대용량 데이터를 문자열로 변환하기 전에 반드시 유효성 검증 함수를 통과하도록 아키텍처를 설계합니다. 아래와 같이 멀티바이트 유효성을 사전에 체크하는 함수를 공통 유틸리티로 등록하여 프로젝트 전반에 적용합니다.
-- 멀티바이트 문자열 유효성 검증 함수
CREATE OR REPLACE FUNCTION IS_VALID_MULTIBYTE(
p_str IN VARCHAR2
) RETURN VARCHAR2 IS
v_dummy VARCHAR2(32767);
BEGIN
-- CONVERT를 통해 유효한 멀티바이트 문자열인지 확인
v_dummy := CONVERT(p_str, 'AL32UTF8', 'AL32UTF8');
RETURN 'VALID';
EXCEPTION
WHEN OTHERS THEN
RETURN 'INVALID: ' || SQLERRM;
END;
/
-- 데이터 입력 전 검증 예
SELECT column_name, IS_VALID_MULTIBYTE(column_name) AS validation_result
FROM your_table
WHERE IS_VALID_MULTIBYTE(column_name) != 'VALID';
관련 에러
- ORA-06502:
PL/SQL: numeric or value error: character string buffer too small— 문자열 버퍼 크기 부족으로 발생하며, ORA-29275와 함께 발생하는 경우가 많습니다. VARCHAR2 변수의 크기를 문자 단위로 충분히 선언해야 합니다. - ORA-12704:
character set mismatch— 서로 다른 캐릭터셋 간 변환 시 발생하며, 멀티바이트 처리 중 자주 동반됩니다. - ORA-01461:
can bind a LONG value only for insert into a LONG column— VARCHAR2 크기 초과 시 발생하며, CLOB 처리 중 ORA-29275와 연계될 수 있습니다. - ORA-00910:
specified length too long for its datatype— 캐릭터셋 변경 후 컬럼 길이가 부족할 때 발생하며, 멀티바이트 환경 전환 시 함께 검토해야 합니다.
주요 DBMS error code를 정리하는 시리즈입니다.
블로그 홈에서 다른 에러도 확인하세요.
본 포스트는 AI가 생성한 기술 가이드입니다. 운영 환경 적용 전 충분한 검토를 권장합니다.