[Oracle] ORA-20000: ORU-10027: buffer overflow, DBMS_OUTPUT 버퍼

728x90

상황 요약

업무에서 프로시저를 실행하는 중에 ORA-20000, ORU-10027 버퍼 오버플로우 에러가 발생했습니다.

 

DBMS_OUTPUT.ENABLE(NULL) 을 수행하고 다시 프로시저를 실행하니 문제 없이 잘 해결되었다고 해요.

 

하지만 NULL로 변경하게 되면 버퍼 상한선을 없애기 때문에 DB의 성능에 영향을 줄 수 있게 됩니다.

DBMS_OUTPUT 패키지란?

DBMS_OUTPUT 패키지는 PL/SQL 블록(BEGIN ~ END)이나 프로시저, 함수 등 SUB PROGRAM 및 패키지, 트리거등에서 메시지를 출력할 수 있는 기능을 제공하는 오라클 패키지입니다.

 

DBMS_OUTPUT.PUT_LINE를 통해 출력 메시지를 PGA 내부 DBMS_OUTPUT 버퍼에 저장하고

DBMS_OUTPUT.GET_LINE을 통해 버퍼에서 읽어올 수 있죠.

DBMS_OUTPUT.ENABLE(NULL)

DBMS_OUTPUT.ENABLE(NULL) 은 PL/SQL에서 DBMS_OUTPUT.PUT_LINE로 출력하는 내용을 버퍼에 제한 없이 담도록 설정하는 용도입니다.

 

DBMS_OUTPUT 패키지는 PL/SQL 블록에서 실행 중 생성한 문자열을 DB 서버 측 버퍼(PGA 내부)에 저장하고, 나중에 클라이언트(SQL*Plus, SQL Developer 등)가 이를 읽어 출력할 수 있게 합니다.

 

여기서 DB 서버의 PGA 내부 버퍼의 상한선은 기본적으로 20,000 바이트이지만, DBMS_OUTPUT.ENABLE(buffer_size)를 통해 변경할 수 있습니다.

 

이때 buffer_size로 NULL 값을 주면 버퍼의 제한이 사라지는 거죠.

 

ENABLE 호출은 현재 세션에서만 적용됩니다.

주의 사항

하지만 buffer_size를 NULL로 설정하는 건 당연히 임시 방편일 뿐입니다.

 

성능에 영향을 줄 수 있기 때문인데요.

  • 대량의 로그를 버퍼에 담으면 메모리 사용량 증가
  • 특히 NULL 설정 시 서버 메모리 부담 가능

PGA의 주요 구성(Dedicated Server 기준)은 아래와 같습니다.

PGA
 ├── SQL Work Areas
 │    ├─ Sort Area (ORDER BY, GROUP BY, Hash Join 등에서 사용)
 │    ├─ Hash Area (해시 연산 시 사용)
 │    ├─ Bitmap merge area
 │    └─ 기타 작업 공간
 └── UGA (User Global Area)
      ├─ 세션 변수, 패키지 상태
      ├─ PL/SQL Collections
      └─ DBMS_OUTPUT 버퍼  ← 여기가 무제한 커짐

 

DBMS_OUTPUT 버퍼가 커지면 UGA가 확장되며

그만큼 SQL Work Areas의 영역이 줄어서 세션의 SQL 정렬, 조인 성능이 저하되겠죠.

 

또한 전체 PGA 관점으로 봤을 때도 버퍼 상한선을 두지 않으면 PGA가 무제한으로 커질 수 있어서

전체 가용 메모리를 잠식하고, 그게 곧 성능 저하나 장애로 이어질 수 있습니다.

권장 해결 방안

일단 디버깅 용도가 아니라면 최대한 DBMS_OUTPUT 사용은 최소화해야 합니다.

 

DBMS_OUTPUT을 사용할 때는

  • ENABLE(NULL) 대신 적절한 상한 사용(예: 5~20MB), 작업 끝나면 DISABLE
    (DISABLE 시 버퍼를 purge 하는 작업이 동반)
  • AP/드라이버에서 주기적 GET_LINES로 드레인(버퍼를 자주 비워 overflow를 예방)
  • 로그량(출력량) 줄이기(레벨/필터/샘플링, 루프 로그 집계)

대량 로그는 로그 테이블에 적재(필요 시 자율 트랜잭션 사용)하거나, 애플리케이션 레벨 로깅으로 분리해서

DBMS_OUTPUT 의존을 최소화할 수도 있습니다.

PGA를 늘려주는 게 하나의 방법이 될 수 있을까?

부분적으로만 도움이 될 수 있지만, 해결책은 아닙니다.

 

DBMS_OUTPUT 버퍼 오버플로우는 버퍼 크기 제한(ENABLE 값) 때문에 나는 것이지,

PGA가 작아서 나는 건 아니라서요.

 

아마 PGA가 부족했다면 alert log에 메모리 부족(ORA-04030) 에러가 발생했을 겁니다.

참고) 버퍼를 비운다는 의미는?

DBMS_OUTPUT 버퍼는 DB 서버 쪽 세션 UGA 안에 있고,

 

이 버퍼가 “비워지는 시점”은 AP(클라이언트) 쪽에서 DBMS_OUTPUT.GET_LINE 또는 DBMS_OUTPUT.GET_LINES(또는 내부적으로 동작하는 API)를 호출해서 읽었을 때입니다.

 

이때 버퍼 내용이 네트워크로 전송되고 읽힌 부분은 버퍼에서 제거됩니다.

읽지 않으면 계속 남아 있어서 메모리를 계속 점유하고요.

 

요약하자면,

  • 버퍼는 DB 서버 메모리 안에서만 쌓이고, AP가 읽기 전에는 절대 자동으로 비워지지 않음
  • ENABLE(NULL)로 무제한 버퍼를 켜면, AP가 읽기 전까지는 계속 늘어날 수 있음
  • AP가 결과를 자주 읽어주면(드레인) → 버퍼가 계속 비워져서 UGA가 폭증하지 않음

참고) 클라이언트(AP) - 서버(DB) 사이 동작 방식

동작 흐름

  1. AP에서 프로시저 호출
    • AP 서버(JDBC, ODP.NET 등)에서 CALL my_proc() 같은 식으로 실행
    • 프로시저 내부에서 DBMS_OUTPUT.PUT_LINE 호출이 발생
  2. 출력 내용 저장
    • DBMS_OUTPUT의 버퍼는 DB 서버 쪽 세션 메모리(UGA) 에 저장됩니다.
      • Dedicated Server → PGA(해당 세션 전용 메모리)
      • Shared Server → SGA(공유 메모리, 주로 Large Pool)
    • 버퍼 크기 제한
      • DBMS_OUTPUT.ENABLE(buffer_size)에서 지정한 크기까지만 저장 가능
      • 기본값은 약 20,000 바이트
      • NULL이면 제한 없음(실제로는 Oracle 내부 한계까지)
    • 버퍼 초과 시 문제
      • 버퍼가 꽉 차면 ORU-10027: buffer overflow 오류 발생
      • 이유: DB 서버의 세션 버퍼(UGA)가 더 이상 내용을 담을 수 없기 때문
  3. AP에서 결과 읽기
    • 프로시저 실행이 끝난 뒤, AP 서버에서 DBMS_OUTPUT.GET_LINES(또는 드라이버 내부 로직)를 호출해 버퍼 내용을 가져옴(UGA의 버퍼가 비워짐)
    • 이때 네트워크로 전송 후 AP에서 로그로 찍거나 화면에 출력
728x90