Trouble Shooting

ORA-00600: internal error code, arguments: [qosdExpStatRead: expcnt mismatch]

돼지와함께춤을 2026. 3. 23. 15:37

1. 장애 개요

운영 중 아래 오류 발생:

ORA-00600: internal error code, arguments: [qosdExpStatRead: expcnt mismatch]

 

  • DBMS_SCHEDULER 사용자 Job 수행 중 발생
  • Job 내부에서 DBMS_STATS.FLUSH_DATABASE_MONITORING_INFO 호출
  • 이후 DBMS_STATS 관련 기능 전반 실패
  • 사용자 Job 외에도 15분 마다 발생(백그라운드 통계관련 프로세스로 추정)

2. 원인 분석

해당 오류의 핵심 원인은 옵티마이저 통계 메타데이터 불일치 .

 

구체적으로는 아래 두 내부 테이블 간 데이터 불일치:

  • SYS.EXP_OBJ$
  • SYS.EXP_STAT$

3. 진단 쿼리

문제 데이터는 다음 쿼리로 확인 가능하다.

WITH b AS (
  SELECT COUNT(*) cnt, objn, snapshot_id
  FROM sys.exp_stat$
  GROUP BY objn, snapshot_id
)
SELECT *
FROM sys.exp_obj$ a, b
WHERE a.objn = b.objn
  AND a.snapshot_id = b.snapshot_id
  AND a.exp_cnt <> b.cnt;

 

 

4. 조치 방법

통계 재수집 혹은 만으로 통계import로 조치하려 했으나 dbms_stat 패키지 사용이 불가하였음

① 불일치 데이터 삭제

DELETE FROM sys.exp_stat$
WHERE snapshot_id = [snap_id]
  AND objn = [obj_num];

② 메타데이터 정합성 맞춤

UPDATE sys.exp_obj$
SET exp_cnt = 0
WHERE snapshot_id = [snap_id]
  AND objn = [obj_num];

③ 대상 테이블 통계 삭제

EXEC DBMS_STATS.DELETE_TABLE_STATS([schema],[table], FORCE=>TRUE);

④ 통계 재수집

EXEC DBMS_STATS.GATHER_TABLE_STATS(
	OWNNAME=>[schema],
	TABNAME=>[table],
    DEGREE=> [parallel degree],
    ESTIMATE_PERCENT=>[],
	FORCE=> TRUE,
    CASCADE=> TRUE
);

 

5. 결과

  • ORA-600 오류 해결
  • DBMS_STATS 정상 동작 복구
  • Scheduler Job 정상 수행

 

6. 오류 재현 테스트 (신규 테이블 기반)

최신 버전(Oracle 19c)에서도 특정 조건 하에 해당 오류가 재현됨을 확인하였다.

[단계 1: 테스트 환경 구축]

CREATE TABLE [schema].[table] (
    ID NUMBER,
    VAL1 NUMBER,
    VAL2 NUMBER,
    TEXT_DATA VARCHAR2(100)
);

INSERT INTO [schema].[table]
SELECT LEVEL, MOD(LEVEL, 100), MOD(LEVEL, 50), RPAD('A', 50, 'B')
FROM DUAL CONNECT BY LEVEL <= 10000;
COMMIT;

-- OBJECT_ID 확인 (예: 349764)
SELECT OBJECT_ID FROM DBA_OBJECTS 
WHERE OWNER = [schema] AND OBJECT_NAME = [table];
-- 349764

 

[단계 2: Expression Statistics 생성 유도] 옵티마이저가 계산식을 학습하도록 쿼리를 반복 수행한 후 메모리 정보를 디스크로 밀어넣는다.

-- 식(Expression) 사용 쿼리 반복 실행 (내부 딕셔너리에 등록될 기회를 줌)
-- 옵티마이저에게 'VAL1 + VAL2'라는 식을 학습시킴
SELECT /*+ MONITOR */ COUNT(*) 
FROM [schema].[table] WHERE (VAL1 + VAL2) > 50;

SELECT *
FROM   DBA_EXPRESSION_STATISTICS 
WHERE TABLE_NAME = '[table]';
-- [schema]	[table]	18316653909056587559	LATEST	21900	0.0000011103939567795		"VAL1"+"VAL2" 	2026/03/24 10:47:49	2026/03/24 10:48:58

-- 메타데이터 생성 확인, 아직 생성 안됨
SELECT * FROM sys.exp_stat$ WHERE OBJN = 349764; 
SELECT * FROM sys.exp_obj$ WHERE OBJN = 349764;
-- NO ROWS

-- 메모리에 있는 통계 정보를 딕셔너리 테이블(SYS.EXP_STAT$ 등)로 강제 저장
EXEC DBMS_STATS.FLUSH_DATABASE_MONITORING_INFO;

-- 메타데이터 생성 확인
SELECT * FROM sys.exp_stat$ WHERE OBJN = 349764; 
--15958839778340835652	349764		21900	1	2026/03/24 10:52:02	2026/03/24 10:52:02	
SELECT * FROM sys.exp_obj$ WHERE OBJN = 349764; 
--349764	1	1

 

[단계 3: 데이터 조작을 통한 Crash 유도]

-- 실제 통계 데이터는 1개이나, 관리 대장(EXP_OBJ$)의 카운트를 강제로 조작
UPDATE SYS.EXP_OBJ$ 
SET EXP_CNT = EXP_CNT + 5 
WHERE OBJN = 349764;
COMMIT;

--  딕셔너리 캐시 정화 (SGA에 예전 값이 남지 않도록)
ALTER SYSTEM FLUSH SHARED_POOL;

 

[단계 4: 결과 확인]

-- 통계 정보를 참조하는 쿼리 실행 시 즉각 발생
SELECT /*+ DYNAMIC_SAMPLING(4) */ COUNT(*) 
FROM [schema].[table] WHERE (VAL1 + VAL2) > 50;

EXEC DBMS_STATS.FLUSH_DATABASE_MONITORING_INFO;
-- 결과: ORA-00600 [qosdExpStatRead: expcnt mismatch] 발생 확인

결론 

  • Oracle 19c 환경에서도 Expression Statistics Usage(ESU) 기능이 활성화되어 있다면 본 장애는 언제든 발생 가능하다.
  • 특히 대량의 DML이나 빈번한 통계 Flush 작업 중 예기치 못한 인터럽트가 발생할 경우 메타데이터 불일치가 생길 수 있다.
  • 조치 시 SYS 테이블을 직접 수정해야 하므로, 반드시 사전 진단 쿼리를 통해 정확한 OBJN과 SNAPSHOT_ID를 특정해야 한다.