Oracle

게시글 보기
작성자 유건데이타 등록일 2015-05-18
제목 DATA BLOCK CORRUPTION : ORA-01578 해결 방법 ORA-1578
DATA BLOCK CORRUPTION : ORA-1578 해결 방법
=========================================

모든 오라클 데이타 블럭은 sequence 번호(seq)와 incarnation 번호(inc)를
갖고 있다. ORA-1578 에러는 seq=0 이고 inc <> 0 (새로운 블럭이 아님)일 때
발생한다. ORA-1578 에러는 ORA-600[3339] 에러와 함께 발생하곤 한다.

ORA-1578 에러가 발생하면 corruption이 발생한 화일 번호와 블럭 번호를
알려준다. 여기서는 이 때의 화일번호를 f, 블럭번호를 b 라고 부르기로 한다.

<해결 방법>

1) 우선 해야 할 일은 어떠한 오브젝트가 corrupt 되었는가를 알아내는 것이다.
다음의 스크립트를 이용하면 알 수 있다.

SQL>select segment_name, segment_type
from dba_extents
where file_id = f and
b between block_id and block_id + blocks - 1;

2) 만약 해당 세그먼트가 인덱스이면 drop 시키고 다시 생성하면 된다.

3) 만약 해당 세그먼트가 테이블이면 corrupt된 블럭의 데이타는 손상된 것이다.

4) 만약 해당 테이블이 들어있는 export 화일이 있다면 손상된 테이블을 drop
시키고 import 받는 것이 제일 간단한 방법이다. 하지만, 만약 export 받은
화일이 없거나 backup해 놓은 화일도 없다면 해당 테이블에 인덱스가 생성되어
있는 경우에 한해서 다음의 방법을 사용해서 복구를 하도록 한다.

5) 해당 테이블에 대한 인덱스가 생성되어 있다면 이를 이용해서 corrupt된
블럭을 피해갈 수 있다. 이 방법은 다음과 같다.

- empno, ename, deptno 를 컬럼으로 가지는 emp 테이블이 corrupt 되었다고
가정하자. 그리고, empno 컬럼에 인덱스가 생성되어 있다고 하자. 클러스터화
되지 않은 모든 테이블은 Unique한 rowid를 가진다.
rowid를 varchar2/hexadecimal 형식으로 표현하려면 rowidtochar 함수를 이용
한다.

SQL> select rowidtochar(rowid) from emp;

rowid는 총 18자로 block address(8자), dot(1자), row address(4자),
dot(1자), file address(4자)로 구성되어 있다.

SQL> select empno, rowid
from emp
where empno > 0

위의 스크립트를 실행시키면 다음과 같은 결과를 얻게 된다.

EMPNO ROWID
----------- --------------------
100 00000003.0000.0006
101 00000003.0001.0006
102 00000003.0002.0006
103 00000003.0003.0006
.
.
500 00000004.0000.000A
501 00000004.0001.000A
.
.
755 0000001A.0005.000A
756 0000001A.000C.000A

만약 인덱스가 character 컬럼에 대한 것이었다면 위의 query 문장을 다음과 같
이 바꿀 수 있다.

SQL> select empno, rowid
from emp
where empno > '';

예를 들어 다음과 같은 에러 메시지가 떨어졌다고 하자.

01578, 00000, "ORACLE data block corrupted (file # 10, block # 4)

그러면, 다음의 스크립트를 사용하여 손상된 블럭에 있는 employee 에 대한
empno를 구할 수 있다.

SQL> select empno from emp
where empno > 0
and rowidtochar(rowid) like '00000004.%.000A';

EMPNO ROWID
----------- ------------------------------------
500 00000004.0000.000A
501 00000004.0001.000A

이제 emp 테이블과 같은 구조를 갖는 새로운 테이블을 만든다.

SQL> create table temp
as select * from emp
where 1 = 2;

그런 다음 손상된 부분을 피해서 새로운 테이블에 손상된 테이블의 데이타를
추가한다.

SQL> insert into temp select * from emp where empno < 500;
SQL> insert into temp select * from emp where empno > 501;

손상된 테이블을 drop 시키고 temp 테이블의 이름을 emp로 변경한다.
그리고, 백업된 자료나 문서 자료를 통하여 손상된 부분에 대한 정보를 추가한다.

6) 손상된 블럭에 여러 개의 row가 존재하고 있다면 다음의 방법을 이용한다.

SQL> create table empnos as
select empno from emp
where empno > 0
and rowidtochar(rowid) not like '00000004.%.000A';

이 스크립트를 이용하면 손상된 block에 포함되지 않는 empno들을 알 수 있다.
다음의 스크립트를 계속 실행시켜 복구를 한다.

SQL> create table temp as select * from emp where 1 = 2;
SQL> insert into temp
select emp.empno, emp.ename, emp.deptno
from emp, empnos
where emp.empno > 0
and emp.empno = empnos.empno;

7) 만약 Data Dictionary의 table이나 index에서 손상된 block이 발생했다면
지원을 요청해야 한다.
Comment
등록된 코멘트가 없습니다.