ORA-00600 [3005]로 DB가 안 열릴 때 — 컨트롤파일 재생성 복구 기록
Oracle 10.2.0.3 (32-bit Windows) / NOARCHIVELOG 환경에서 ALTER DATABASE OPEN이 ORA-00600: internal error code, arguments: [3005], [1], [345], [3], [0], [0], [], [] 로 실패하던 DB를 컨트롤파일 재생성으로 살린 기록입니다. 중간에 판단을 한 번 잘못했고, 그 부분도 그대로 남겼습니다.
1. 상황
- Oracle Database 10g Enterprise Edition 10.2.0.3.0 — 32-bit Windows
- NOARCHIVELOG 모드
- 데이터파일 21개, 온라인 redo 3그룹(각 500MB)
- 마지막 백업 없음
STARTUP 하면 MOUNT까지는 올라가는데 OPEN에서 죽습니다.
데이터베이스가 마운트되었습니다.
ORA-00600: 내부 오류 코드, 인수 : [3005], [1], [345], [3], [0], [0], [], []
2. ORA-00600은 인자가 전부다
ORA-00600은 "커널 내부에서 뭔가 잘못됐다"는 것 외에 아무 의미가 없습니다. 첫 번째 인자가 사실상 진짜 에러 코드이고, 나머지는 컨텍스트입니다.
alert log 위치:
SHOW PARAMETER background_dump_dest; -- 또는 diagnostic_dest
$ORACLE_BASE/admin/<SID>/bdump/alert_<SID>.log
인자 해석
인자 값 의미
| 1번 | 3005 | 오류 식별자 (redo 계열) |
| 2번 | 1 | thread 1 |
| 3번 | 345 | 시퀀스 345 |
| 4번 | 3 | 그룹 3 |
당시 v$log는 이랬습니다.
GROUP# SEQUENCE# BYTES STATUS FIRST_TIME
1 343 524288000 INACTIVE 26/07/25
3 342 524288000 INACTIVE 26/07/16
2 344 524288000 CURRENT 26/08/03
CURRENT가 344, 라운드로빈상 다음 차례는 그룹 3(342를 담고 있던 가장 오래된 그룹) → 시퀀스 345. 인자 [345], [3]과 정확히 일치합니다.
즉, OPEN 과정에서 redo thread를 열며 그룹 3에 시퀀스 345를 할당하는 순간 실패하고 있었습니다.
3. 먼저 복구가 필요한 상태인지 확인
SELECT log_mode, open_mode, checkpoint_change# FROM v$database;
SELECT * FROM v$recover_file;
SELECT status, COUNT(*), MIN(checkpoint_change#), MAX(checkpoint_change#)
FROM v$datafile_header GROUP BY status;
SELECT MIN(checkpoint_change#), MAX(checkpoint_change#) FROM v$datafile;
결과:
LOG_MODE OPEN_MODE CHECKPOINT_CHANGE#
NOARCHIVELOG MOUNTED 3.4146E10
v$recover_file → 선택된 레코드가 없습니다.
STATUS COUNT(*) MIN(CKPT) MAX(CKPT)
ONLINE 21 3.4146E10 3.4146E10
v$recover_file이 비어 있고 21개 파일의 checkpoint SCN이 전부 같습니다. 여기서 "일관 상태니 복구 불필요"라고 판단했는데, 이게 나중에 틀린 것으로 드러납니다. (→ 6절)
한 가지 팁: 3.4146E10 같은 지수 표기는 수십만 단위 차이를 가려버립니다.
SET NUMWIDTH 20
SELECT MIN(checkpoint_change#), MAX(checkpoint_change#),
COUNT(DISTINCT checkpoint_change#)
FROM v$datafile_header;
4. 1차 시도 — 로그 클리어 (실패)
그룹 3의 물리 파일 문제일 수 있으니 비워봅니다.
SELECT group#, status, type, member FROM v$logfile ORDER BY group#;
세 그룹 모두 STATUS 공백(정상), 경로는 C:\ORACLE10G\ORADATA\REDO0[1-3].LOG.
ALTER DATABASE CLEAR LOGFILE GROUP 3;
-- 데이타베이스가 변경되었습니다.
ALTER DATABASE OPEN;
-- ORA-00600: ... [3005], [1], [345], [3], [0], [0], [], []
로그를 비웠는데 인자가 완전히 동일합니다.
→ 물리 redo 파일이 아니라 컨트롤파일 안의 redo thread 레코드가 깨진 것. 그룹 3의 내용을 지워도 컨트롤파일이 여전히 "345를 그룹 3에"라는 잘못된 상태를 고집하고 있습니다.
5. 2차 시도 — 컨트롤파일 재생성
5-1. 정보 확보 (MOUNT 상태에서)
SET LINESIZE 200 PAGESIZE 500
SELECT file#, name FROM v$datafile ORDER BY file#;
SELECT name FROM v$tempfile; -- ★ 반드시 기록
SELECT name FROM v$controlfile;
v$tempfile은 꼭 적어두세요. 컨트롤파일을 재생성하면 tempfile 정보가 사라져서 나중에 수동으로 다시 추가해야 합니다.
5-2. trace 스크립트 뽑기
udump 폴더를 뒤질 필요 없이 경로를 직접 지정할 수 있습니다.
ALTER DATABASE BACKUP CONTROLFILE TO TRACE AS 'C:\oracle10g\cf_raw.sql';
5-3. 콜드 백업
SHUTDOWN IMMEDIATE
데이터파일이 여러 드라이브에 흩어져 있으면 전부 복사해야 합니다. 이 사례는 C:\ORACLE10G\ORADATA\에 3개, D:\ORADATA\에 18개였습니다.
여기까지가 되돌릴 수 있는 마지막 지점입니다.
5-4. 스크립트 편집
cf_raw.sql 안에는 두 벌이 들어 있습니다.
-- Set #1. NORESETLOGS case ← 온라인 로그가 살아있을 때
-- Set #2. RESETLOGS case ← 온라인 로그가 손상됐을 때
이번엔 Set #2를 썼습니다. 그리고 CREATE CONTROLFILE ~ ; 한 덩어리만 남기고 STARTUP NOMOUNT, RECOVER DATABASE, ALTER DATABASE OPEN RESETLOGS, ALTER TABLESPACE TEMP ADD TEMPFILE 줄은 전부 제거합니다. 이 명령들은 결과를 보면서 직접 칠 겁니다.
CREATE CONTROLFILE REUSE DATABASE "ORCL" RESETLOGS NOARCHIVELOG
MAXLOGFILES 16
MAXLOGMEMBERS 3
MAXDATAFILES 100
MAXINSTANCES 8
MAXLOGHISTORY 292
LOGFILE
GROUP 1 'C:\ORACLE10G\ORADATA\REDO01.LOG' SIZE 500M,
GROUP 2 'C:\ORACLE10G\ORADATA\REDO02.LOG' SIZE 500M,
GROUP 3 'C:\ORACLE10G\ORADATA\REDO03.LOG' SIZE 500M
DATAFILE
'C:\ORACLE10G\ORADATA\SYSTEM01.DBF',
'C:\ORACLE10G\ORADATA\UNDOTBS01.DBF',
'C:\ORACLE10G\ORADATA\SYSAUX01.DBF',
'D:\ORADATA\APP_DAT1.DBF',
...
CHARACTER SET KO16KSC5601
;
체크포인트 두 가지:
- DATAFILE 개수가 실제와 일치하는지 세어볼 것. 빠진 파일은 그대로 유실됩니다.
- CHARACTER SET은 절대 임의로 바꾸지 말 것.
메모장으로 저장할 땐 파일 형식을 "모든 파일"로 바꾸세요. 안 그러면 cf.sql.txt가 됩니다.
5-5. 실행
STARTUP NOMOUNT
@C:\oracle10g\cf.sql
-- 제어 파일이 생성되었습니다. → 자동으로 MOUNT 상태
6. 여기서 판단 착오 — FUZZY를 안 봤다
3절에서 "SCN이 전부 같으니 복구 불필요"라고 봤기 때문에, 복구 프롬프트에서 그냥 CANCEL을 쳤습니다.
RECOVER DATABASE USING BACKUP CONTROLFILE UNTIL CANCEL;
ORA-00279: change 34145857632 (08/03/2026 22:00:04) needed for thread 1
ORA-00289: 제안 : C:\ORACLE10G\RDBMS\ARC00344_1024935211.001
ORA-00280: change 34145857632 for thread 1 is in sequence #344
로그 지정: cancel
ORA-01547: 경고: RECOVER 성공했지만 OPEN RESETLOGS 시 아래 오류 발생
ORA-01194: 파일 1은 더 많은 복구가 필요합니다
ORA-01110: 데이터 파일 1: 'C:\ORACLE10G\ORADATA\SYSTEM01.DBF'
ORA-01112: 미디어 복구가 시작되지 않았습니다
v$datafile_header의 checkpoint SCN이 전부 같다고 해서 일관 상태인 게 아닙니다. FUZZY 플래그가 YES면 redo 적용이 더 필요합니다. 이걸 확인했어야 했습니다.
SELECT DISTINCT fuzzy, status FROM v$datafile_header;
v$recover_file이 비어 있던 것도, 원래 컨트롤파일 기준으로는 "미디어 복구 대상 파일이 없다"는 뜻이지 "redo 적용이 끝났다"는 뜻이 아닙니다.
7. 해결 — 온라인 redo 로그를 직접 지정
ORA-00280을 다시 읽어보면 답이 있습니다.
change 34145857632 for thread 1 is in sequence #344
필요한 redo가 시퀀스 344, 즉 CURRENT였던 REDO02.LOG 안에 그대로 있습니다. NOARCHIVELOG라 아카이브 파일(ARC00344_...)은 존재하지 않지만, 온라인 로그 파일 경로를 직접 입력하면 됩니다.
RECOVER DATABASE USING BACKUP CONTROLFILE UNTIL CANCEL;
프롬프트에서 CANCEL 대신:
로그 지정: C:\ORACLE10G\ORADATA\REDO02.LOG
Log applied.
Media recovery complete.
ALTER DATABASE OPEN RESETLOGS;
-- 데이타베이스가 변경되었습니다.
ALTER TABLESPACE TEMP ADD TEMPFILE 'C:\ORACLE10G\ORADATA\TEMP01.DBF' SIZE 500M REUSE;
정상 오픈됐습니다.
⚠️ 이 방법은 온라인 redo 로그 파일이 살아있어야 성립합니다. "redo 파일을 .old로 옮겨두라"는 조언을 그대로 따랐다가 이 단계에서 막힐 뻔했습니다. RESETLOGS 절차에서 온라인 로그를 치우기 전에, 그 안의 redo가 필요한지 먼저 확인하세요.
8. 오픈 후 정리
-- 즉시 콜드 백업 (RESETLOGS 이전 백업은 더 이상 쓸 수 없음)
SHUTDOWN IMMEDIATE
-- → ORADATA 전체 복사
-- 무결성 확인
SELECT owner, object_type, COUNT(*) FROM dba_objects
WHERE status='INVALID' GROUP BY owner, object_type;
SELECT tablespace_name, status FROM dba_tablespaces;
-- INVALID 객체 재컴파일
@?/rdbms/admin/utlrp.sql
alert log에 ORA-600이 재발하지 않는지 며칠 지켜보는 것도 필요합니다.
9. 정리하며
진단 흐름
- ORA-00600은 인자를 읽는 것에서 시작. [3005], [1], [345], [3]은 "thread 1, 그룹 3, 시퀀스 345"로 곧장 해석됨
- v$log와 대조해 인자가 가리키는 지점을 특정
- CLEAR LOGFILE로 물리 파일 요인을 배제 → 컨트롤파일 문제로 좁혀짐
- 컨트롤파일 재생성
- 필요한 redo는 온라인 로그에서 직접 공급
얻은 교훈
- checkpoint_change#가 같다 ≠ 일관 상태. FUZZY를 같이 봐야 한다
- ORA-00280의 "is in sequence #N"은 버리는 정보가 아니라 해결의 실마리다
- 복구 절차에서 파일을 치우기 전에, 그 파일이 필요한지부터 확인한다
- 데이터파일이 여러 드라이브에 흩어져 있으면 콜드 백업 때 전부 챙긴다
근본 문제는 따로 있었다
이번에 정말 위험했던 건 ORA-600 자체가 아니라 NOARCHIVELOG + 백업 부재였습니다. 온라인 로그에 시퀀스 344가 남아 있었던 건 상당 부분 운이었습니다. 로그 스위치 간격이 7/16 → 7/25 → 8/3로 길었던 덕에 필요한 redo가 덮어쓰이지 않았을 뿐, 트랜잭션이 조금만 많았다면 344는 이미 순환되어 사라졌을 겁니다.
- ARCHIVELOG 모드 전환
- RMAN 정기 백업 구성
- 10.2.0.3 / 32-bit Windows는 지원 종료 — 패치 경로가 없으므로 마이그레이션 계획 수립
참고
- ORA-00600의 정확한 인자 의미는 My Oracle Support의 ORA-600/ORA-7445 Lookup Tool에서 조회할 수 있습니다. 이 글의 [3005] 해석은 인자 패턴과 v$log 대조로 역산한 것입니다.
- 운영 DB라면 어떤 조치든 콜드 백업 확보 후 진행하세요. 특히 NOARCHIVELOG 환경에서 RESETLOGS는 되돌릴 수 없습니다.