2026년 08월 07일 | DBMS Error 가이드
이 글에서 다루는 내용
ORA-02020 에러의 원인 분석, 해결 SQL, 예방 방법을 실무 관점에서 정리합니다.
ORA-02020 too many database links in use 는?
ORA-02020 에러는 Oracle 데이터베이스에서 동시에 사용할 수 있는 데이터베이스 링크(Database Link)의 수가 초기화 파라미터 OPEN_LINKS에 설정된 최댓값을 초과했을 때 발생합니다. 하나의 세션에서 여러 원격 데이터베이스에 동시에 접속하거나, 분산 쿼리(Distributed Query)를 과도하게 사용하는 환경에서 주로 나타납니다. 특히 ERP 시스템, 데이터 통합 플랫폼, 또는 마이크로서비스 아키텍처와 연동된 Oracle 환경에서 자주 발생하며, 방치할 경우 해당 세션의 쿼리가 완전히 실패하거나 트랜잭션이 롤백되는 심각한 장애로 이어질 수 있습니다.
주요 발생 원인
OPEN_LINKS파라미터 기본값 초과
Oracle의 OPEN_LINKS 파라미터는 단일 세션에서 동시에 열 수 있는 데이터베이스 링크의 최대 개수를 제어합니다. 기본값은 4로 설정되어 있으며, 이 값이 실제 업무 요건보다 낮게 설정된 경우 분산 쿼리를 처리하는 도중 ORA-02020이 발생합니다. 예를 들어 5개의 원격 데이터베이스를 동시에 조인하는 쿼리를 실행하면 기본값으로는 반드시 에러가 발생합니다.
- 데이터베이스 링크가 명시적으로 닫히지 않아 누적되는 문제
애플리케이션 코드나 PL/SQL 프로시저에서 데이터베이스 링크를 사용한 후 ALTER SESSION CLOSE DATABASE LINK 명령어로 명시적으로 닫지 않으면, 세션이 유지되는 동안 링크가 계속 열린 상태로 남아 있습니다. 장시간 실행되는 배치 프로그램이나 커넥션 풀을 사용하는 웹 애플리케이션에서 특히 문제가 됩니다. 결국 시간이 지남에 따라 누적된 열린 링크의 수가 OPEN_LINKS 제한을 초과하게 됩니다.
- 분산 쿼리 또는 PL/SQL 내 다중 DB 링크 중첩 사용
복잡한 분산 트랜잭션 환경에서 하나의 PL/SQL 블록 또는 패키지 내부에서 여러 DB 링크를 동시에 사용하는 경우, 각 링크에 대한 연결이 순차적으로 누적됩니다. 특히 루프(LOOP) 구조 안에서 여러 DB 링크를 교차로 사용하거나, 패키지 수준의 커서(Cursor)가 DB 링크를 통해 원격 테이블을 열어 두는 경우 이 문제가 빈번하게 발생합니다. 이는 코드 설계 단계에서 분산 링크 사용 전략을 수립하지 않은 경우 발생하는 구조적 문제입니다.
해결 방법
1. OPEN_LINKS 파라미터 값 증가
현재 설정된 OPEN_LINKS 값을 확인하고, 업무 요건에 맞게 증가시킵니다. 이 파라미터는 동적으로 변경할 수 없으므로 SPFILE을 수정한 후 데이터베이스를 재시작해야 합니다.
-- 현재 OPEN_LINKS 파라미터 값 확인
SHOW PARAMETER OPEN_LINKS;
-- SPFILE을 통해 파라미터 변경 (DB 재시작 필요)
ALTER SYSTEM SET OPEN_LINKS = 10 SCOPE = SPFILE;
-- OPEN_LINKS_PER_INSTANCE 파라미터도 함께 확인 (인스턴스 전체 제한)
SHOW PARAMETER OPEN_LINKS_PER_INSTANCE;
-- 필요 시 인스턴스 전체 제한도 조정
ALTER SYSTEM SET OPEN_LINKS_PER_INSTANCE = 64 SCOPE = SPFILE;
-- 데이터베이스 재시작 후 변경 확인
-- STARTUP / SHUTDOWN IMMEDIATE 수행 후
SHOW PARAMETER OPEN_LINKS;
> ⚠️ OPEN_LINKS 최대값은 255입니다. 무분별하게 높이면 메모리 리소스가 낭비될 수 있으므로, 실제 사용 패턴을 분석한 후 적절한 값으로 설정하십시오.
2. 사용 완료된 DB 링크 명시적 종료
PL/SQL이나 애플리케이션에서 DB 링크 사용 후 명시적으로 닫아 누적을 방지합니다.
-- 현재 세션에서 열려 있는 DB 링크 확인
SELECT DB_LINK, OWNER_ID, LOGGED_ON, HETEROGENEOUS, PROTOCOL, OPEN_CURSORS, IN_TRANSACTION
FROM V$DBLINK;
-- 특정 DB 링크를 명시적으로 닫기
ALTER SESSION CLOSE DATABASE LINK remote_db_link;
-- PL/SQL 예제: DB 링크 사용 후 명시적으로 닫는 패턴
DECLARE
v_count NUMBER;
BEGIN
-- 원격 DB에서 데이터 조회
SELECT COUNT(*) INTO v_count
FROM employees@remote_db_link
WHERE department_id = 10;
DBMS_OUTPUT.PUT_LINE('Count: ' || v_count);
-- 사용 완료 후 DB 링크 명시적 종료
EXECUTE IMMEDIATE 'ALTER SESSION CLOSE DATABASE LINK remote_db_link';
EXCEPTION
WHEN OTHERS THEN
-- 예외 발생 시에도 DB 링크 닫기 시도
BEGIN
EXECUTE IMMEDIATE 'ALTER SESSION CLOSE DATABASE LINK remote_db_link';
EXCEPTION
WHEN OTHERS THEN NULL;
END;
RAISE;
END;
/
3. 분산 쿼리 리팩토링: 다중 DB 링크 사용 최소화
여러 DB 링크를 동시에 사용하는 쿼리는 단계적으로 분리하거나, 글로벌 임시 테이블(Global Temporary Table)을 활용하여 원격 데이터를 로컬로 가져온 후 처리합니다.
-- [문제 있는 패턴] 한 쿼리에서 여러 DB 링크 동시 참조
SELECT a.employee_id, b.department_name, c.location_city, d.country_name, e.region_name
FROM employees@db_link_1 a
JOIN departments@db_link_2 b ON a.department_id = b.department_id
JOIN locations@db_link_3 c ON b.location_id = c.location_id
JOIN countries@db_link_4 d ON c.country_id = d.country_id
JOIN regions@db_link_5 e ON d.region_id = e.region_id;
-- 위 쿼리는 OPEN_LINKS=4 환경에서 ORA-02020 발생!
-- [개선된 패턴] 글로벌 임시 테이블을 활용한 단계적 처리
-- Step 1: 각 원격 데이터를 로컬 임시 테이블에 적재
CREATE GLOBAL TEMPORARY TABLE gtt_employees
(employee_id NUMBER, department_id NUMBER)
ON COMMIT DELETE ROWS;
CREATE GLOBAL TEMPORARY TABLE gtt_departments
(department_id NUMBER, department_name VARCHAR2(100), location_id NUMBER)
ON COMMIT DELETE ROWS;
-- 원격 데이터 로컬로 가져오기 (DB 링크 사용 후 즉시 닫기)
INSERT INTO gtt_employees
SELECT employee_id, department_id FROM employees@db_link_1;
EXECUTE IMMEDIATE 'ALTER SESSION CLOSE DATABASE LINK db_link_1';
INSERT INTO gtt_departments
SELECT department_id, department_name, location_id FROM departments@db_link_2;
EXECUTE IMMEDIATE 'ALTER SESSION CLOSE DATABASE LINK db_link_2';
COMMIT;
-- Step 2: 로컬 임시 테이블 간 조인 (DB 링크 불필요)
SELECT e.employee_id, d.department_name
FROM gtt_employees e
JOIN gtt_departments d ON e.department_id = d.department_id;
4. 현재 세션의 DB 링크 사용 현황 모니터링
-- 인스턴스 전체에서 열려 있는 DB 링크 현황 확인
SELECT s.sid, s.serial#, s.username, s.program,
d.db_link, d.logged_on, d.open_cursors
FROM v$session s
JOIN v$dblink d ON s.saddr = d.saddr
ORDER BY s.sid;
-- OPEN_LINKS 제한에 근접한 세션 탐지
SELECT sid, COUNT(*) AS open_link_count
FROM (
SELECT s.sid
FROM v$session s
JOIN v$dblink d ON s.saddr = d.saddr
)
GROUP BY sid
HAVING COUNT(*) >= (SELECT value - 1 FROM v$parameter WHERE name = 'open_links')
ORDER BY open_link_count DESC;
예방 방법
- DB 링크 사용 표준화 및 코딩 컨벤션 수립
팀 내 개발 표준에 “DB 링크 사용 후 반드시 ALTER SESSION CLOSE DATABASE LINK 호출”을 명문화하고, 코드 리뷰 체크리스트에 포함시키십시오. 장기 실행 배치 프로세스나 커넥션 풀 환경에서는 DB 링크 사용 직후 닫는 패턴을 템플릿화하여 모든 개발자가 일관되게 적용하도록 합니다. 또한 OPEN_LINKS_PER_INSTANCE 값을 주기적으로 모니터링하는 스크립트를 스케줄러(DBMS_SCHEDULER)에 등록하여 임계치 도달 전에 선제적으로 대응하십시오.
- 분산 아키텍처 설계 시 DB 링크 의존도 최소화
신규 시스템 설계 단계에서부터 DB 링크 대신 Oracle Advanced Queuing(AQ), Oracle GoldenGate, 또는 REST API 기반 데이터 통합 방식을 우선 검토하십시오. 불가피하게 DB 링크를 사용해야 한다면, 동시에 열리는 링크의 수를 아키텍처 다이어그램에 명시하고 OPEN_LINKS 파라미터 설정 기준을 문서화하십시오. 정기 데이터베이스 헬스체크(주 1회 권장) 시 V$DBLINK 뷰를 통해 불필요하게 열려 있는 링크가 없는지 점검하는 것도 중요한 예방 활동입니다.
관련 에러
- ORA-02019:
connection description for remote database not found— DB 링크 자체가 존재하지 않거나 TNS 설정이 잘못된 경우 발생하며, ORA-02020과 함께 분산 데이터베이스 환경에서 자주 쌍으로 나타납니다. - ORA-02021:
DDL operations is not allowed on a remote database— DB 링크를 통해 원격 DB에서 DDL을 시도할 때 발생합니다. - ORA-02050:
transaction rolled back, some remote DBs may be in-doubt— 분산 트랜잭션 처리 중 일부 원격 DB에서 커밋/롤백이 불완전하게 처리될 때 발생하며, ORA-02020으로 인한 강제 종료 후 후속으로 발생할 수 있습니다. - ORA-12541:
TNS: no listener— DB 링크가 참조하는 원격 리스너가 응답하지 않을 때 발생하며, 분산 환경 트러블슈팅 시 ORA-02020과 함께 점검해야 할 에러입니다.
주요 DBMS error code를 정리하는 시리즈입니다.
블로그 홈에서 다른 에러도 확인하세요.
본 포스트는 AI가 생성한 기술 가이드입니다. 운영 환경 적용 전 충분한 검토를 권장합니다.