ORA-00022 invalid session ID 는?
ORA-00022 에러는 Oracle 데이터베이스에서 세션 ID가 유효하지 않을 때 발생하는 오류입니다. 주로 DBMS_SYSTEM.SET_SQL_TRACE_IN_SESSION, ALTER SYSTEM KILL SESSION, DBMS_SESSION 패키지 등을 사용할 때 존재하지 않거나 이미 종료된 세션 ID를 참조하면 발생합니다. 실무에서는 DBA가 특정 세션을 강제 종료하거나 트레이스를 활성화하는 과정에서 세션 정보가 변경되었음에도 불구하고 오래된 SID 값을 그대로 사용할 경우 빈번하게 발생합니다.
주요 발생 원인
1. 이미 종료된 세션에 대한 KILL SESSION 시도
가장 흔한 원인으로, DBA가 V$SESSION을 조회하여 SID와 SERIAL# 값을 확인한 후 세션을 종료하려는 사이에 해당 세션이 이미 스스로 종료된 경우입니다. 특히 쿼리 조회 시점과 ALTER SYSTEM KILL SESSION 명령 실행 시점 사이에 시간 차이가 발생하면 세션 정보가 무효화되어 이 에러가 트리거됩니다. 배치 작업이나 짧은 수명의 커넥션 풀 세션에서 특히 자주 발생합니다.
2. 잘못된 SID 또는 SERIAL# 조합 입력
ALTER SYSTEM KILL SESSION 명령은 SID와 SERIAL# 두 값을 조합하여 세션을 고유하게 식별합니다. SID만 맞고 SERIAL#이 틀리거나, 두 값 모두 잘못 입력한 경우 Oracle은 해당 세션을 찾지 못해 ORA-00022를 반환합니다. 특히 RAC 환경에서는 INST_ID(인스턴스 ID)까지 함께 지정해야 하므로, 단일 인스턴스 기준의 명령을 RAC에 그대로 사용할 경우 이 오류가 발생할 수 있습니다.
3. DBMS_SYSTEM 또는 DBMS_SESSION 패키지 사용 시 세션 정보 불일치
DBMS_SYSTEM.SET_SQL_TRACE_IN_SESSION 또는 DBMS_SESSION 관련 프로시저를 호출할 때 유효하지 않은 세션 ID를 넘기면 ORA-00022가 발생합니다. 특히 자동화 스크립트나 모니터링 툴에서 주기적으로 세션 목록을 캐싱하여 사용할 경우, 캐시가 갱신되기 전에 세션이 종료되면 이 오류가 반복적으로 발생할 수 있습니다.
해결 방법
원인 1: 이미 종료된 세션 KILL 시도 해결
세션을 종료하기 전 반드시 실시간으로 세션 존재 여부를 확인하고, 확인 즉시 명령을 실행하는 습관이 필요합니다.
-- 1단계: 현재 활성 세션 목록 실시간 조회
SELECT sid, serial#, username, status, machine, program, sql_id
FROM v$session
WHERE status = 'ACTIVE'
AND username IS NOT NULL
ORDER BY sid;
-- 2단계: 특정 세션 존재 여부 확인 후 KILL
DECLARE
v_sid NUMBER := 123; -- 종료하려는 SID
v_serial NUMBER := 4567; -- 해당 SERIAL#
v_count NUMBER;
BEGIN
-- 세션이 여전히 존재하는지 확인
SELECT COUNT(*)
INTO v_count
FROM v$session
WHERE sid = v_sid
AND serial# = v_serial;
IF v_count > 0 THEN
EXECUTE IMMEDIATE
'ALTER SYSTEM KILL SESSION ''' || v_sid || ',' || v_serial || ''' IMMEDIATE';
DBMS_OUTPUT.PUT_LINE('세션 종료 완료: SID=' || v_sid || ', SERIAL#=' || v_serial);
ELSE
DBMS_OUTPUT.PUT_LINE('세션이 이미 종료되었습니다. SID=' || v_sid);
END IF;
EXCEPTION
WHEN OTHERS THEN
IF SQLCODE = -22 THEN
DBMS_OUTPUT.PUT_LINE('ORA-00022: 세션이 이미 종료되었거나 유효하지 않습니다.');
ELSE
RAISE;
END IF;
END;
/
원인 2: 잘못된 SID/SERIAL# 조합 해결
SID와 SERIAL#을 함께 정확히 조회하여 사용하고, RAC 환경에서는 INST_ID도 반드시 포함합니다.
-- 단일 인스턴스: 정확한 SID와 SERIAL# 조회
SELECT sid,
serial#,
username,
status,
osuser,
machine,
TO_CHAR(logon_time, 'YYYY-MM-DD HH24:MI:SS') AS logon_time
FROM v$session
WHERE username = 'APPUSER' -- 특정 사용자 세션 필터링
AND status != 'KILLED';
-- 단일 인스턴스 세션 종료
ALTER SYSTEM KILL SESSION '123,4567' IMMEDIATE;
-- RAC 환경: INST_ID 포함하여 세션 조회
SELECT inst_id, sid, serial#, username, status, machine
FROM gv$session
WHERE username IS NOT NULL
AND status != 'KILLED'
ORDER BY inst_id, sid;
-- RAC 환경 세션 종료 (INST_ID 포함)
ALTER SYSTEM KILL SESSION '123,4567,@2' IMMEDIATE;
-- 형식: 'SID, SERIAL#, @INST_ID'
-- 특정 SQL을 실행 중인 세션 찾아서 종료 준비
SELECT s.inst_id,
s.sid,
s.serial#,
s.username,
s.status,
q.sql_text
FROM gv$session s
JOIN gv$sql q ON s.sql_id = q.sql_id
AND s.inst_id = q.inst_id
WHERE q.sql_text LIKE '%특정키워드%';
원인 3: DBMS_SYSTEM 패키지 사용 시 해결
-- SQL Trace 활성화 전 세션 유효성 검증 포함 프로시저
CREATE OR REPLACE PROCEDURE safe_enable_trace (
p_sid IN NUMBER,
p_serial IN NUMBER
)
AS
v_count NUMBER;
BEGIN
-- 세션 존재 여부 사전 확인
SELECT COUNT(*)
INTO v_count
FROM v$session
WHERE sid = p_sid
AND serial# = p_serial
AND status != 'KILLED';
IF v_count = 0 THEN
RAISE_APPLICATION_ERROR(-20001,
'SID=' || p_sid || ', SERIAL#=' || p_serial || ' 세션이 존재하지 않습니다.');
END IF;
-- SQL Trace 활성화
DBMS_SYSTEM.SET_SQL_TRACE_IN_SESSION(
sid => p_sid,
serial => p_serial,
sql_trace => TRUE
);
DBMS_OUTPUT.PUT_LINE('SQL Trace 활성화 완료: SID=' || p_sid);
EXCEPTION
WHEN OTHERS THEN
IF SQLCODE = -22 THEN
DBMS_OUTPUT.PUT_LINE('ORA-00022: 세션 추적 중 세션이 종료되었습니다.');
ELSE
DBMS_OUTPUT.PUT_LINE('에러 발생: ' || SQLERRM);
RAISE;
END IF;
END safe_enable_trace;
/
-- 사용 예시
EXEC safe_enable_trace(123, 4567);
예방 방법
1. 세션 조회와 작업 사이의 시간 간격 최소화 및 동적 SQL 활용
세션 정보를 조회하는 시점과 실제 작업을 수행하는 시점 사이의 시간 간격을 최소화해야 합니다. 특히 반복적으로 세션을 관리하는 자동화 스크립트를 작성할 때는 아래와 같이 세션 조회와 종료를 단일 트랜잭션 내에서 동적으로 처리하고, WHEN OTHERS에서 ORA-00022를 명시적으로 핸들링하여 스크립트가 비정상 종료되지 않도록 설계하는 것이 Best Practice입니다.
-- 장시간 실행 세션 자동 정리 스크립트 예시 (재발 방지용)
BEGIN
FOR r IN (
SELECT sid, serial#
FROM v$session
WHERE status = 'ACTIVE'
AND username IS NOT NULL
AND last_call_et > 3600 -- 1시간 이상 실행 중인 세션
) LOOP
BEGIN
EXECUTE IMMEDIATE
'ALTER SYSTEM KILL SESSION '''
|| r.sid || ',' || r.serial# || ''' IMMEDIATE';
EXCEPTION
WHEN OTHERS THEN
IF SQLCODE IN (-22, -30) THEN
-- ORA-00022 또는 ORA-00030: 이미 종료된 세션, 무시하고 진행
NULL;
ELSE
RAISE;
END IF;
END;
END LOOP;
END;
/
2. 모니터링 및 세션 관리 툴에서 세션 캐시 사용 금지
자체 개발한 모니터링 스크립트나 세션 관리 툴에서 V$SESSION 또는 GV$SESSION 결과를 캐싱하여 재사용하지 않도록 합니다. 세션 정보는 매번 실시간으로 조회해야 하며, 특히 RAC 환경에서는 반드시 GV$SESSION을 사용하고 INST_ID를 포함한 완전한 세션 식별자를 사용하는 정책을 팀 전체에 공유하고 문서화해야 합니다. Oracle Enterprise Manager(OEM) 또는 검증된 서드파티 툴을 사용하면 이러한 세션 관리 오류를 내부적으로 처리해주므로 실무에서 적극 권장됩니다.
관련 에러
-
ORA-00030:
ALTER SYSTEM KILL SESSION명령에서 세션이 이미 종료되었거나 존재하지 않을 때 발생하며, ORA-00022와 유사한 맥락에서 함께 나타나는 경우가 많습니다. -
ORA-00031: 세션에 KILL 마크가 이미 설정되어 있을 때 발생합니다. 세션이 KILLED 상태로 대기 중인 경우
IMMEDIATE옵션을 사용하거나 OS 레벨에서 프로세스를 직접 종료해야 합니다. - ORA-02049: 분산 트랜잭션 관련 세션 잠금 대기 시간 초과 에러로, 세션 강제 종료 시도와 연관되어 나타날 수 있습니다.
- ORA-00028: 현재 세션이 DBA에 의해 강제 종료되었을 때 해당 세션의 클라이언트 측에서 수신하는 에러 코드입니다.











