2026년 08월 28일 | DBMS Error 가이드
이 글에서 다루는 내용
ORA-06505 에러의 원인 분석, 해결 SQL, 예방 방법을 실무 관점에서 정리합니다.
ORA-06505 PL/SQL: variable requires more than 32767 bytes of contiguous memory 는?
ORA-06505는 PL/SQL에서 변수에 32,767바이트(약 32KB)를 초과하는 연속 메모리 공간을 할당하려 할 때 발생하는 에러입니다. 이는 Oracle PL/SQL 엔진이 단일 스칼라 변수(VARCHAR2, RAW 등)에 허용하는 최대 메모리 한계를 초과했음을 의미합니다. 주로 대용량 문자열 조작, 동적 SQL 생성, 또는 외부 데이터를 PL/SQL 변수에 담으려 할 때 자주 목격되는 에러입니다.
주요 발생 원인
1. VARCHAR2 변수의 32,767바이트 한계 초과
PL/SQL의 VARCHAR2 타입은 최대 32,767바이트까지만 저장할 수 있습니다. 데이터베이스 테이블의 VARCHAR2 컬럼(최대 4,000바이트 또는 확장 모드에서 32,767바이트)과 달리, PL/SQL 내부에서도 이 한계를 넘는 데이터를 단일 VARCHAR2 변수에 할당하면 ORA-06505가 발생합니다. 특히 문자열 연결(concatenation) 연산이 반복될 때 변수 크기가 예상치 못하게 커져서 에러가 유발되는 경우가 많습니다.
2. DBMS_SQL 또는 동적 SQL 생성 시 초과
복잡한 비즈니스 로직을 동적 SQL로 구성할 때, SQL 문자열을 하나의 VARCHAR2 변수에 누적 저장하다 보면 32,767바이트를 쉽게 초과할 수 있습니다. 특히 IN 절에 수천 개의 값을 동적으로 추가하거나, 대형 CASE WHEN 구문을 프로그래밍 방식으로 생성하는 경우에 빈번하게 발생합니다. 이런 패턴은 코드 리뷰 단계에서 발견하지 못하고 운영 환경에서 데이터가 충분히 쌓인 후에야 에러로 나타나는 경우가 많아 주의가 필요합니다.
3. 대용량 데이터를 LONG 또는 RAW 타입으로 처리할 때
레거시 시스템에서 LONG 타입 컬럼의 데이터를 PL/SQL 변수로 읽어 처리하거나, 바이너리 데이터를 RAW 변수에 할당할 때도 이 에러가 발생합니다. RAW 타입 역시 PL/SQL에서 32,767바이트 한계를 가지며, 이미지나 문서 파일을 RAW 변수에 통째로 담으려는 시도는 거의 대부분 이 에러를 유발합니다. 데이터 마이그레이션이나 ETL 작업 중 자주 나타나는 패턴입니다.
해결 방법
해결책 1: CLOB 타입으로 변환
가장 직접적인 해결책은 VARCHAR2 변수를 CLOB(Character Large Object) 타입으로 교체하는 것입니다. CLOB은 최대 4GB까지 저장할 수 있어 대용량 텍스트 처리에 적합합니다.
-- 문제가 발생하는 코드 (32,767바이트 초과 시 ORA-06505 발생)
DECLARE
v_large_text VARCHAR2(32767);
v_result VARCHAR2(32767);
BEGIN
-- 이 부분에서 32,767바이트 초과 시 에러 발생
SELECT large_column INTO v_large_text FROM big_table WHERE id = 1;
END;
/
-- 해결: CLOB 타입으로 변경
DECLARE
v_large_text CLOB;
v_result CLOB;
BEGIN
-- CLOB으로 선언하면 최대 4GB까지 처리 가능
SELECT large_clob_column INTO v_large_text FROM big_table WHERE id = 1;
-- CLOB 데이터 조작 예시
DBMS_LOB.APPEND(v_result, v_large_text);
DBMS_OUTPUT.PUT_LINE('데이터 길이: ' || DBMS_LOB.GETLENGTH(v_large_text) || ' bytes');
END;
/
해결책 2: 동적 SQL 생성 시 CLOB 사용
동적 SQL을 생성할 때는 VARCHAR2 대신 CLOB을 사용하고, EXECUTE IMMEDIATE와 함께 활용합니다.
-- 문제 코드: VARCHAR2로 동적 SQL 구성 시 한계 초과
DECLARE
v_sql VARCHAR2(32767);
BEGIN
v_sql := 'SELECT * FROM orders WHERE order_id IN (';
-- 수천 개의 값을 추가하다 보면 32,767바이트 초과
FOR i IN 1..5000 LOOP
v_sql := v_sql || i || ',';
END LOOP;
v_sql := RTRIM(v_sql, ',') || ')';
EXECUTE IMMEDIATE v_sql; -- ORA-06505 발생 가능
END;
/
-- 해결 코드: CLOB 사용 + DBMS_SQL 패키지 활용
DECLARE
v_sql CLOB;
v_cursor INTEGER;
v_rows INTEGER;
BEGIN
-- CLOB으로 대용량 SQL 구성
DBMS_LOB.CREATETEMPORARY(v_sql, TRUE);
DBMS_LOB.APPEND(v_sql, 'SELECT order_id, order_date FROM orders WHERE order_id IN (');
FOR i IN 1..5000 LOOP
IF i > 1 THEN
DBMS_LOB.APPEND(v_sql, ',');
END IF;
DBMS_LOB.APPEND(v_sql, TO_CLOB(i));
END LOOP;
DBMS_LOB.APPEND(v_sql, ')');
-- DBMS_SQL을 이용한 실행
v_cursor := DBMS_SQL.OPEN_CURSOR;
DBMS_SQL.PARSE(v_cursor, v_sql, DBMS_SQL.NATIVE);
v_rows := DBMS_SQL.EXECUTE(v_cursor);
DBMS_SQL.CLOSE_CURSOR(v_cursor);
-- 임시 LOB 해제
DBMS_LOB.FREETEMPORARY(v_sql);
DBMS_OUTPUT.PUT_LINE('처리 완료: ' || v_rows || '행');
EXCEPTION
WHEN OTHERS THEN
IF DBMS_SQL.IS_OPEN(v_cursor) THEN
DBMS_SQL.CLOSE_CURSOR(v_cursor);
END IF;
DBMS_LOB.FREETEMPORARY(v_sql);
RAISE;
END;
/
해결책 3: 데이터를 청크(Chunk) 단위로 분할 처리
데이터를 반드시 VARCHAR2로 처리해야 하는 레거시 환경이라면, 데이터를 일정 크기로 나누어 처리하는 방식을 사용합니다.
-- CLOB 데이터를 VARCHAR2 청크로 나누어 처리하는 예시
DECLARE
v_clob CLOB;
v_chunk VARCHAR2(4000); -- 안전한 크기로 청크 설정
v_offset INTEGER := 1;
v_chunk_size INTEGER := 4000;
v_total_len INTEGER;
BEGIN
-- CLOB 데이터 로드
SELECT clob_column INTO v_clob FROM document_table WHERE doc_id = 100;
v_total_len := DBMS_LOB.GETLENGTH(v_clob);
DBMS_OUTPUT.PUT_LINE('총 데이터 크기: ' || v_total_len || ' bytes');
-- 청크 단위로 분할 처리
WHILE v_offset <= v_total_len LOOP
-- DBMS_LOB.SUBSTR로 안전하게 추출
v_chunk := DBMS_LOB.SUBSTR(v_clob, v_chunk_size, v_offset);
-- 각 청크에 대한 처리 로직
-- 예: 특정 패턴 검색, 변환 작업 등
IF INSTR(v_chunk, 'ERROR') > 0 THEN
DBMS_OUTPUT.PUT_LINE('오프셋 ' || v_offset || '에서 ERROR 발견');
END IF;
v_offset := v_offset + v_chunk_size;
END LOOP;
DBMS_OUTPUT.PUT_LINE('청크 처리 완료');
END;
/
해결책 4: BLOB 타입 활용 (바이너리 데이터)
바이너리 데이터를 처리할 때는 RAW 대신 BLOB을 사용합니다.
-- RAW 변수 한계 초과 시 → BLOB으로 전환
DECLARE
v_blob BLOB;
v_raw_chunk RAW(2000); -- 작은 단위로만 RAW 사용
v_offset INTEGER := 1;
v_amount INTEGER := 2000;
v_total INTEGER;
BEGIN
-- BLOB 데이터 읽기
SELECT binary_data INTO v_blob
FROM file_storage
WHERE file_id = 999;
v_total := DBMS_LOB.GETLENGTH(v_blob);
DBMS_OUTPUT.PUT_LINE('파일 크기: ' || v_total || ' bytes');
-- RAW를 작은 청크로 나누어 처리
WHILE v_offset <= v_total LOOP
DBMS_LOB.READ(v_blob, v_amount, v_offset, v_raw_chunk);
-- 각 RAW 청크 처리 (예: 파일 쓰기, 변환 등)
v_offset := v_offset + v_amount;
END LOOP;
DBMS_OUTPUT.PUT_LINE('BLOB 처리 완료');
END;
/
예방 방법
1. 코딩 표준에서 대용량 데이터 타입 가이드라인 수립
프로젝트 초기부터 32,767바이트를 초과할 가능성이 있는 데이터는 반드시 CLOB/BLOB 타입으로 선언하도록 코딩 표준에 명시해야 합니다. VARCHAR2는 단순 문자열 처리에만 사용하고, 동적 SQL이나 누적 문자열 연산이 필요한 경우 처음부터 CLOB을 사용하도록 리뷰 체크리스트에 포함시키세요. 또한 코드 리뷰 단계에서 VARCHAR2 변수에 문자열을 반복 연결하는 패턴을 발견하면 반드시 CLOB 전환 여부를 검토해야 합니다.
2. 단위 테스트 시 경계값(Boundary) 데이터 포함
개발 및 테스트 환경에서 단위 테스트를 수행할 때, 실제 운영 환경의 최대 데이터 크기를 반영한 경계값 테스트 케이스를 반드시 포함하세요. 운영 환경에서는 시간이 지남에 따라 데이터가 축적되어 처음에는 정상이었던 코드도 나중에 에러를 유발할 수 있습니다. 특히 동적 SQL 생성 로직은 IN 절 값 개수 최대치, 가장 긴 레코드 기준으로 테스트하여 잠재적인 ORA-06505를 사전에 발견하고 수정하는 것이 중요합니다.
관련 에러
- ORA-06502:
PL/SQL: numeric or value error: character string buffer too small— VARCHAR2 변수에 할당하려는 값이 선언된 크기보다 클 때 발생하며, ORA-06505와 함께 자주 등장하는 에러입니다. - ORA-01489:
result of string concatenation is too long— SQL 레이어에서 문자열 연결 결과가 최대 허용 크기를 초과할 때 발생합니다. - ORA-22813:
operand value exceeds system limits— LOB 타입 처리 중 시스템 한계를 초과할 때 발생하며, CLOB/BLOB 연산에서 주의가 필요합니다. - ORA-04031:
unable to allocate N bytes of shared memory— SGA 메모리 부족으로 발생하며, 대용량 PL/SQL 처리와 관련하여 간접적으로 연관될 수 있습니다.
주요 DBMS error code를 정리하는 시리즈입니다.
블로그 홈에서 다른 에러도 확인하세요.
본 포스트는 AI가 생성한 기술 가이드입니다. 운영 환경 적용 전 충분한 검토를 권장합니다.