2026년 09월 19일 | DBMS Error 가이드
이 글에서 다루는 내용
ORA-12899 에러의 원인 분석, 해결 SQL, 예방 방법을 실무 관점에서 정리합니다.
ORA-12899 value too large for column 는?
ORA-12899 에러는 Oracle 데이터베이스에서 특정 컬럼에 허용된 최대 바이트 길이보다 더 큰 값을 삽입하거나 업데이트하려 할 때 발생하는 에러입니다. 예를 들어, VARCHAR2(10) 타입의 컬럼에 11바이트 이상의 데이터를 입력하면 Oracle은 즉시 이 에러를 발생시키며 해당 DML 문을 거부합니다. 이 에러는 특히 멀티바이트 문자셋(예: UTF-8, AL32UTF8) 환경에서 한글, 중국어, 일본어 같은 문자를 다룰 때 더 자주 마주치게 되며, 개발자들이 바이트(Byte)와 문자(Character)의 차이를 인지하지 못할 경우 반복적으로 발생하는 고질적인 문제입니다.
주요 발생 원인
1. 멀티바이트 문자셋 환경에서의 바이트 수 오산
Oracle 데이터베이스가 AL32UTF8(UTF-8) 문자셋을 사용하는 경우, 한글 한 글자는 3바이트를 차지합니다. 따라서 VARCHAR2(10)으로 선언된 컬럼에는 영문자 10자는 들어가지만, 한글은 최대 3자(9바이트)까지만 입력이 가능합니다. 개발자가 “10글자면 충분하겠지”라고 생각하고 컬럼을 설계했을 때 한글 입력 시 즉시 ORA-12899가 발생합니다. 이는 국내 환경에서 가장 빈번하게 발생하는 원인이며, NVARCHAR2 사용 여부와 CHAR vs BYTE 시맨틱을 고려하지 않은 설계에서 비롯됩니다.
2. 애플리케이션 레이어에서의 유효성 검증 부재
프론트엔드나 애플리케이션 서버에서 입력값의 길이를 제한하지 않고 그대로 DB로 전달하는 경우, 사용자가 허용 범위를 초과하는 데이터를 입력하면 ORA-12899가 발생합니다. 특히 UI에서는 “최대 10자”로 제한했더라도, API를 직접 호출하거나 배치 프로그램에서 데이터를 처리할 때 검증 로직을 우회하는 경우가 많습니다. 이로 인해 운영 환경에서 갑작스럽게 에러가 발생하고, 데이터 적재 실패로 이어지는 심각한 장애를 유발할 수 있습니다.
3. 데이터 마이그레이션 또는 ETL 과정에서의 데이터 불일치
소스 시스템과 타겟 Oracle 시스템 간의 컬럼 정의가 서로 다를 때 마이그레이션 과정에서 ORA-12899가 대량으로 발생할 수 있습니다. 예를 들어, MySQL의 VARCHAR(50)은 문자 기준이지만 Oracle의 VARCHAR2(50)은 기본적으로 바이트 기준으로 동작하기 때문에, 동일한 “50”이라는 숫자라도 실제 수용 가능한 데이터 크기가 다릅니다. ETL 도구를 사용하더라도 문자셋 변환 과정에서 데이터 팽창(Character Expansion)이 일어나 예상치 못한 에러가 발생하는 경우가 많습니다.
해결 방법
원인 1 해결: 컬럼 크기 확인 및 변경
우선 에러가 발생한 컬럼의 현재 정의를 확인합니다.
-- 에러 발생 테이블의 컬럼 정보 확인
SELECT column_name,
data_type,
data_length,
char_length,
char_used
FROM user_tab_columns
WHERE table_name = 'YOUR_TABLE_NAME'
AND column_name = 'YOUR_COLUMN_NAME';
CHAR_USED 컬럼이 B이면 바이트 시맨틱, C이면 문자 시맨틱입니다. 컬럼 크기를 늘려야 한다면 아래와 같이 ALTER TABLE을 사용합니다.
-- 컬럼 크기 확장 (바이트 기준)
ALTER TABLE your_table MODIFY (your_column VARCHAR2(100 BYTE));
-- 컬럼 크기 확장 (문자 기준 - 멀티바이트 환경 권장)
ALTER TABLE your_table MODIFY (your_column VARCHAR2(100 CHAR));
> 주의: Oracle에서 VARCHAR2 컬럼의 크기는 늘릴 수만 있고 줄일 수는 없습니다. (데이터가 있는 경우)
원인 2 해결: 애플리케이션에서 SUBSTR 또는 데이터 정제 적용
긴급한 상황에서 데이터를 잘라서 넣어야 한다면 SUBSTR을 활용할 수 있습니다. 단, 이는 임시방편이며 근본 원인을 해결해야 합니다.
-- BYTE 기준으로 잘라서 INSERT
INSERT INTO your_table (your_column)
VALUES (SUBSTRB('입력할_긴_문자열_데이터', 1, 10));
-- CHAR 기준으로 잘라서 INSERT
INSERT INTO your_table (your_column)
VALUES (SUBSTR('입력할_긴_문자열_데이터', 1, 10));
-- 업데이트 시에도 동일하게 적용
UPDATE your_table
SET your_column = SUBSTRB(your_column, 1, 10)
WHERE LENGTHB(your_column) > 10;
원인 3 해결: 마이그레이션 전 사전 검증 쿼리
마이그레이션 전에 소스 데이터가 타겟 컬럼에 들어갈 수 있는지 미리 확인합니다.
-- 소스 데이터 중 타겟 컬럼 크기를 초과하는 행 사전 확인
SELECT COUNT(*) AS violation_count,
MAX(LENGTHB(your_column)) AS max_byte_length,
MAX(LENGTH(your_column)) AS max_char_length
FROM source_table
WHERE LENGTHB(your_column) > 50; -- 타겟 컬럼 바이트 크기
-- 위반 데이터 샘플 확인
SELECT your_column,
LENGTHB(your_column) AS byte_len,
LENGTH(your_column) AS char_len
FROM source_table
WHERE LENGTHB(your_column) > 50
FETCH FIRST 10 ROWS ONLY;
현재 DB 문자셋 확인 방법
-- 데이터베이스 문자셋 및 NLS 설정 확인
SELECT parameter, value
FROM nls_database_parameters
WHERE parameter IN ('NLS_CHARACTERSET', 'NLS_NCHAR_CHARACTERSET', 'NLS_LENGTH_SEMANTICS');
-- 세션 레벨 NLS 설정 확인
SELECT parameter, value
FROM nls_session_parameters
WHERE parameter = 'NLS_LENGTH_SEMANTICS';
-- 세션 레벨 길이 시맨틱 변경 (CHAR 기준으로 변경)
ALTER SESSION SET NLS_LENGTH_SEMANTICS = CHAR;
예방 방법
1. 테이블 설계 시 CHAR 시맨틱을 기본으로 사용하기
멀티바이트 문자셋(AL32UTF8) 환경에서 VARCHAR2 컬럼을 선언할 때는 반드시 CHAR 시맨틱을 명시적으로 지정하는 것을 팀 내 개발 표준으로 정의하십시오. VARCHAR2(100 CHAR)으로 선언하면 영문이든 한글이든 관계없이 100문자까지 저장이 보장됩니다. 또한, 데이터베이스 또는 테이블스페이스 레벨에서 NLS_LENGTH_SEMANTICS = CHAR를 설정해두면 개발자가 별도로 명시하지 않아도 기본적으로 문자 시맨틱이 적용됩니다.
-- 권장: 테이블 생성 시 CHAR 시맨틱 명시
CREATE TABLE member_info (
member_id NUMBER PRIMARY KEY,
member_name VARCHAR2(50 CHAR) NOT NULL, -- 한글 50자 보장
address VARCHAR2(200 CHAR), -- 주소 200자 보장
email VARCHAR2(100 BYTE) -- 이메일은 영문이므로 BYTE도 무방
);
2. CHECK 제약 조건과 트리거를 활용한 사전 방어
데이터가 컬럼에 들어오기 전에 CHECK 제약 조건이나 BEFORE INSERT/UPDATE 트리거를 통해 길이를 사전에 검증하는 방어 로직을 구축하십시오. 이는 애플리케이션 레이어의 검증 로직이 우회되더라도 데이터베이스 레벨에서 무결성을 보장합니다.
-- CHECK 제약 조건으로 바이트 길이 제한 (LENGTHB 활용)
ALTER TABLE your_table
ADD CONSTRAINT chk_column_length
CHECK (LENGTHB(your_column) <= 90);
-- BEFORE INSERT/UPDATE 트리거로 자동 정제 처리
CREATE OR REPLACE TRIGGER trg_member_name_check
BEFORE INSERT OR UPDATE ON member_info
FOR EACH ROW
BEGIN
IF LENGTHB(:NEW.member_name) > 150 THEN
RAISE_APPLICATION_ERROR(-20001,
'회원명이 허용 바이트 수를 초과했습니다: ' ||
LENGTHB(:NEW.member_name) || ' bytes');
END IF;
END;
/
관련 에러
- ORA-01401:
inserted value too large for column— 구버전 Oracle(8i 이하)에서 ORA-12899와 동일한 상황에서 발생하던 에러로, 현재는 ORA-12899로 대체되었습니다. - ORA-06502:
PL/SQL: numeric or value error: character string buffer too small— PL/SQL 변수에 허용 크기를 초과하는 값을 할당할 때 발생하며, ORA-12899와 유사한 맥락에서 자주 함께 나타납니다. - ORA-01438:
value larger than specified precision allowed for this column— NUMBER 타입 컬럼에서 정밀도(precision)를 초과하는 숫자를 입력할 때 발생하며, ORA-12899의 숫자형 버전이라고 볼 수 있습니다. - ORA-00910:
specified length too long for its datatype— DDL 실행 시 데이터 타입의 최대 허용 길이를 초과하는 컬럼 크기를 정의할 때 발생합니다.
주요 DBMS error code를 정리하는 시리즈입니다.
블로그 홈에서 다른 에러도 확인하세요.
본 포스트는 AI가 생성한 기술 가이드입니다. 운영 환경 적용 전 충분한 검토를 권장합니다.