Oracle ORA-06500 오류 원인과 해결 방법 완벽 가이드

ORA-06500
2026년 08월 27일 | DBMS Error 가이드

이 글에서 다루는 내용

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

ORA-06500 PL/SQL: storage error 는?

ORA-06500은 PL/SQL 엔진이 내부적으로 필요한 메모리를 할당받지 못했을 때 발생하는 스토리지 관련 심각한 오류입니다. 주로 PGA(Program Global Area) 메모리 부족, 컬렉션(Collection) 또는 대용량 변수의 과도한 메모리 사용, 혹은 재귀 호출의 깊이가 너무 깊어지는 경우 발생합니다. 이 오류는 Oracle이 PL/SQL 블록 실행 중 내부 자료구조를 위한 메모리를 더 이상 확보할 수 없을 때 트리거되며, 방치할 경우 세션 또는 인스턴스 안정성에 영향을 줄 수 있습니다.


주요 발생 원인

  • PGA 메모리 부족 및 메모리 한계 초과

PGA(Program Global Area)는 각 서버 프로세스가 사용하는 전용 메모리 영역으로, PL/SQL 실행 컨텍스트, 로컬 변수, 커서 데이터 등을 저장합니다. PGA_AGGREGATE_TARGET 또는 PGA_AGGREGATE_LIMIT 파라미터로 설정된 PGA 한도에 도달하거나, 시스템 전체의 가용 메모리가 고갈된 경우 ORA-06500이 발생합니다. 특히 대규모 배치 작업이나 병렬 DML 작업 중에 다수의 세션이 동시에 대량의 PGA를 소비할 때 빈번하게 나타납니다.

  • 무제한 컬렉션(Collection) 또는 대형 LOB 변수 사용

PL/SQL에서 VARRAY, Nested Table, Associative Array 등의 컬렉션을 크기 제한 없이 무한정 확장하거나, CLOB, BLOB 등의 대형 LOB 데이터를 통째로 변수에 담을 경우 메모리 사용량이 폭발적으로 증가합니다. 특히 루프(LOOP) 안에서 컬렉션에 계속 데이터를 추가하면서 중간에 메모리를 해제하지 않으면 PGA가 빠르게 소진되어 ORA-06500으로 이어집니다. 실무에서는 수십만 건 이상의 행을 한 번에 컬렉션에 올리는 패턴이 가장 흔한 원인입니다.

  • 무한 재귀 호출(Infinite Recursion) 또는 지나치게 깊은 호출 스택

PL/SQL 프로시저나 함수가 자기 자신 또는 다른 프로그램을 재귀적으로 호출할 때, 종료 조건이 잘못 설정되거나 아예 없는 경우 호출 스택이 계속 쌓이면서 스택 메모리가 고갈됩니다. Oracle은 재귀 깊이 제한이 있지만, 그 한계에 도달하기 전에 메모리가 먼저 소진되면 ORA-06500이 발생할 수 있습니다. 복잡한 트리 구조의 계층형 데이터를 재귀로 처리하는 로직에서 자주 목격됩니다.


해결 방법

원인 1: PGA 메모리 부족 해결

현재 PGA 사용 현황을 먼저 확인하고, 필요에 따라 파라미터를 조정합니다.

-- 현재 PGA 사용 현황 확인
SELECT
    s.sid,
    s.serial#,
    s.username,
    p.pga_used_mem / 1024 / 1024   AS pga_used_mb,
    p.pga_alloc_mem / 1024 / 1024  AS pga_alloc_mb,
    p.pga_max_mem / 1024 / 1024    AS pga_max_mb
FROM v$session s
JOIN v$process p ON s.paddr = p.addr
WHERE s.username IS NOT NULL
ORDER BY p.pga_alloc_mem DESC;

-- PGA Aggregate Target 현황 확인
SHOW PARAMETER pga_aggregate_target;
SHOW PARAMETER pga_aggregate_limit;

-- PGA 한도 증가 (DBA 권한 필요, 시스템 메모리에 맞게 조정)
ALTER SYSTEM SET pga_aggregate_target = 4G SCOPE=BOTH;
ALTER SYSTEM SET pga_aggregate_limit  = 8G SCOPE=BOTH;

-- 통계 뷰로 PGA 과다 사용 쿼리 추적
SELECT sql_id, sql_text, sharable_mem, persistent_mem, runtime_mem
FROM v$sql
ORDER BY runtime_mem DESC
FETCH FIRST 10 ROWS ONLY;

원인 2: 컬렉션 메모리 최적화

컬렉션을 사용할 때는 BULK COLLECT에 LIMIT 절을 반드시 사용하고, 처리 후 메모리를 명시적으로 해제합니다.

-- 잘못된 패턴: 전체 데이터를 한 번에 컬렉션으로 로드 (ORA-06500 유발)
DECLARE
    TYPE t_emp_tab IS TABLE OF employees%ROWTYPE;
    l_emp_data t_emp_tab;
BEGIN
    -- 수백만 건을 한 번에 메모리에 올리면 위험
    SELECT * BULK COLLECT INTO l_emp_data FROM employees;
    -- 처리 로직...
END;
/

-- 올바른 패턴: LIMIT 절로 청크(Chunk) 단위 처리
DECLARE
    TYPE t_emp_tab IS TABLE OF employees%ROWTYPE;
    l_emp_data t_emp_tab;
    CURSOR c_emp IS SELECT * FROM employees;
    c_limit CONSTANT PLS_INTEGER := 1000; -- 한 번에 1,000건씩 처리
BEGIN
    OPEN c_emp;
    LOOP
        FETCH c_emp BULK COLLECT INTO l_emp_data LIMIT c_limit;
        EXIT WHEN l_emp_data.COUNT = 0;

        -- 각 청크 처리
        FOR i IN 1 .. l_emp_data.COUNT LOOP
            -- 비즈니스 로직 수행
            NULL;
        END LOOP;

        -- 처리 후 컬렉션 메모리 명시적 해제
        l_emp_data.DELETE;
        COMMIT; -- 필요 시 중간 커밋으로 undo 세그먼트 압박 감소

    END LOOP;
    CLOSE c_emp;
END;
/

-- LOB 처리 시 임시 LOB 사용 후 반드시 해제
DECLARE
    l_clob CLOB;
BEGIN
    DBMS_LOB.CREATETEMPORARY(l_clob, TRUE);
    -- LOB 처리 로직
    DBMS_LOB.APPEND(l_clob, 'Large text data...');
    -- 사용 완료 후 즉시 해제
    DBMS_LOB.FREETEMPORARY(l_clob);
END;
/

원인 3: 재귀 호출 오류 수정

재귀 프로시저에는 반드시 명확한 종료 조건과 깊이 제한을 추가합니다.

-- 잘못된 재귀 패턴 (종료 조건 결함으로 ORA-06500 유발 가능)
CREATE OR REPLACE PROCEDURE bad_recursive_proc(p_id IN NUMBER) IS
BEGIN
    -- 종료 조건이 불완전하거나 잘못된 경우
    bad_recursive_proc(p_id + 1); -- 무한 재귀
END;
/

-- 올바른 재귀 패턴: 종료 조건 + 최대 깊이 제한
CREATE OR REPLACE PROCEDURE safe_recursive_proc(
    p_id    IN NUMBER,
    p_depth IN NUMBER DEFAULT 0
) IS
    c_max_depth CONSTANT PLS_INTEGER := 100; -- 최대 재귀 깊이 설정
BEGIN
    -- 깊이 제한 체크
    IF p_depth > c_max_depth THEN
        RAISE_APPLICATION_ERROR(-20001,
            'Maximum recursion depth exceeded: ' || p_depth);
    END IF;

    -- 종료 조건 명확히 정의
    IF p_id <= 0 THEN
        RETURN;
    END IF;

    -- 실제 처리 로직
    DBMS_OUTPUT.PUT_LINE('Processing ID: ' || p_id || ', Depth: ' || p_depth);

    -- 재귀 호출
    safe_recursive_proc(p_id - 1, p_depth + 1);
END;
/

-- 재귀 대신 계층형 쿼리(CONNECT BY)로 대체 (메모리 효율적)
SELECT
    LEVEL,
    employee_id,
    manager_id,
    first_name || ' ' || last_name AS emp_name
FROM employees
START WITH manager_id IS NULL
CONNECT BY PRIOR employee_id = manager_id
ORDER SIBLINGS BY employee_id;

예방 방법

  • PGA 모니터링 자동화 및 임계값 알람 설정

운영 환경에서는 PGA 사용량을 지속적으로 모니터링하고, 일정 임계값(예: PGA_AGGREGATE_TARGET의 80%)을 초과할 경우 알람이 발생하도록 Oracle Enterprise Manager 또는 커스텀 모니터링 스크립트를 구성해야 합니다. 또한 새로운 PL/SQL 코드를 배포하기 전에 반드시 개발/테스트 환경에서 대용량 데이터 기준으로 메모리 사용량을 프로파일링하는 절차를 수립하세요. DBMS_HPROF(Hierarchical Profiler) 또는 DBMS_PROFILER를 활용하면 어느 프로시저에서 메모리를 과다 사용하는지 상세히 분석할 수 있습니다.

  • 컬렉션 사용 코딩 표준 수립 및 코드 리뷰 강화

PL/SQL 개발 표준에 “BULK COLLECT 사용 시 LIMIT 절 필수”, “처리 완료된 컬렉션은 즉시 DELETE 또는 TRIM 호출”, “단일 컬렉션의 최대 허용 레코드 수 지정(예: 10,000건 이하)” 등의 규칙을 명문화하고, 코드 리뷰 체크리스트에 포함시킵니다. 재귀 프로시저의 경우 최대 재귀 깊이를 상수로 정의하고, 가능하면 재귀 방식보다 CONNECT BY 계층형 쿼리 또는 반복(LOOP) 방식으로 로직을 재설계하는 것을 권장합니다.


관련 에러

  • ORA-04031: Shared Pool 또는 Large Pool의 메모리 부족. ORA-06500이 PGA 영역의 문제라면, ORA-04031은 SGA 영역(Shared Pool)의 메모리 부족 오류입니다.
  • ORA-06533: Subscript beyond count. 컬렉션의 유효 범위를 벗어난 접근으로, 컬렉션 관련 코드에서 ORA-06500과 함께 나타날 수 있습니다.
  • ORA-06502: PL/SQL: numeric or value error. 변수 크기 초과 또는 형변환 오류로 발생하며, 메모리 처리 오류와 연관될 수 있습니다.
  • ORA-04036: PGA memory used by the instance exceeds PGA_AGGREGATE_LIMIT. PGA 총량 제한 초과 시 발생하며, ORA-06500의 직접적인 원인이 되기도 합니다.

DBMS 에러 코드 시리즈

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

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

댓글 남기기