결과는 corruption 난 block의 data까지 예전 export file 에서 살려냈습니다.
방법은 간단...
corrupt난 A table 의 index에는 pk값이 남아 있습니다. 즉 index까지는 access할수 있습니다. pk컬럼값을 아는 이상 예전 exp file에서 임시 table을 다른 유저에서 구축한 다음.. pk 값으로 임시 table에서 해당 row값을 꺼내면 됩니다
MOS 참고
Extracting Data from a Corrupt Table using ROWID Range Scans in Oracle8 and higher (문서 ID 61685.1)
Salvaging data from a TABLE in Oracle8 onwards ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ This article is an extension to Note:28814.1 which discusses the options available for handling block corruptions in Oracle. Here we describe how to retrieve data from a table which contains a corrupt block (or blocks) in Oracle8/8i releases. *** This article does NOT cover Oracle7 - see Note:34371.1 instead *** In order to use the steps here you need to have a list of all corrupt File/Blocks in the table. Ideally you should have the following information to hand: - Original Error - Absolute File# - Referred to as <AFN> in this article - Relative File# - Referred to as <RFN> in this article - Block# - Referred to as <BL> in this article - Object Type - eg: TABLE , TABLE PARTITION or CLUSTER - Object Owner.Name - Related Objects - eg: Indexes, Foreign key constraints , Partition Name etc.. If not then see Note:28814.1 for details of how to get this information. There are several ways to extract data from a corrupt table: - (1) Use a special event which can SKIP over corrupt blocks. This is by far the simplest option to extract table data and is discussed in Note:33405.1. Note that this event can only be used if the corrupt block reports ORA-1578. - (2) Use a ROWID range scan to select around a corrupt block. This method is discussed in this article, along with notes on how to select data that was in the corrupt block from any indexed columns. - (3) There are various salvage programs / PLSQL scripts which can be used to salvage data from a table. These can take longer to set up and use than the above methods but can often cope with various kinds of corruption. These are listed in Note:28814.1 and are not covered here. Using ROWID Range Scans in Oracle8: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The ROWID in Oracle8/8i is externalised as an 18 digit character string with the format 'OOOOOOFFFBBBBBBSSS' where: OOOOOO = is a base 64 encoding of the 32-bit dataobj# (Data object number was introduced in 8.0 to track versions of the same segment because certain operations can change the version. It is used to discover stale ROWIDs and stale undo records) FFF = is a base 64 encoding of the relative file number BBBBBB = is a base 64 encoding of the block number SSS = is a base 64 encoding of the slot (row) number Note that the ROWID contains the relative file number which is distinct from the absolute file number and new for Oracle8. A relative file number is relative to the tablespace (meaning a tablespace can have a first, second, third file, etc.) and an absolute file number is absolute in the whole system. Two different files may have the same relative number. Eg: If we issued "SELECT ACCT_NO, ROWID from EXAMPLE;" we would get something like: ACCT_NO ROWID ---------- ------------------ 12345 AAAAh3AAGAAACJAAAA 19283 AAAAh3AAGAAACJAAAB 22345 AAAAh4AAFAAAAADAAA 60372 AAAAh4AAFAAAAADAAB This format is called the extended ROWID character format. In order to create a ROWID string you must have all of the components. Then you can use the following function in the DBMS_ROWID package: function ROWID_CREATE(rowid_type IN number, object_number IN number, relative_fno IN number, block_number IN number, row_number IN number) return ROWID; -- rowid_type - type (restricted=0/extended=1) -- object_number - data object number -- relative_fno - relative file number -- block_number - block number in this file -- row_number - row number in this block To construct a ROWID for a ROWID range scan we use the following input to the ROWID_CREATE function: ROWID_TYPE: ~~~~~~~~~~~ This is 1 because we are using the extended rowid format. RELATIVE_FNO: ~~~~~~~~~~~~~ This should have been available when you came to this article. It can also be found from the DBA_EXTENTS view given the absolute file number and block number of the corrupt block: SELECT tablespace_name, relative_fno, segment_type, owner, segment_name, partition_name FROM dba_extents WHERE file_id = <AFN> AND <BL> between block_id and block_id + blocks -1 ; Remember that Oracle8 reports <RFN> in an ORA-1578 error, and <AFN> in the accompanying ORA-1110 error. OBJECT_NUMBER: ~~~~~~~~~~~~~ For a non-partitioned table, select the DATA_OBJECT_ID from DBA_OBJECTS for the problem table: SELECT data_object_id FROM dba_objects WHERE object_name = '<TABLE-NAME>' AND owner = '<TABLE-OWNER>' ; Note that a partitioned table has an object number for each partition. Select the DATA_OBJECT_ID from DBA_OBJECTS thus: SELECT data_object_id FROM dba_objects WHERE object_name = '<TABLE-NAME>' AND owner = '<TABLE-OWNER>' AND subobject_name = '<PARTITION-NAME>' ; BLOCK_NUMBER and ROW_NUMBER: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The block number of the corrupt block should be available before you came to this article. (Eg: It is reported in an ORA-1578 error, or as a Page Number by DBVerify). For a ROWID range scan we generally want to select all rows BEFORE the corrupt block, then all rows AFTER the corrupt block. The first row in a block is row zero (0) and so we want all rowids LESS THAN "Block <BL> row 0" and then GREATER THAN OR EQUAL TO "Block <BL>+1 row 0". You can now create the rowid strings to use in a predicate thus: The "LOW_RID" is the lowest rowid INSIDE the corrupt block: SELECT dbms_rowid.rowid_create(1,<DATA_OBJECT_ID>,<RFN>,<BL>,0) LOW_RID from DUAL; The "HI_RID" is the first rowid AFTER the corrupt block: SELECT dbms_rowid.rowid_create(1,<DATA_OBJECT_ID>,<RFN>,<BL>+1,0) HI_RID from DUAL; It is now possible to use CREATE TABLE AS SELECT or INSERT ... SELECT to get data without accessing the corrupt block using a query of the form: CREATE TABLE salvage_table AS SELECT /*+ ROWID(A) */ * FROM <owner.tablename> A WHERE rowid < '<low_rid>' ; INSERT INTO salvage_table SELECT /*+ ROWID(A) */ * FROM <owner.tablename> A WHERE rowid >= '<hi_rid>' ; (Note that "A" is being used as a table alias in the HINT and in the FROM clause, and that we want LESS THAN the "lo_rid" and GREATER THAN OR EQUAL TO the "hi_rid") For a table partition then only the problem partition need be selected from by using the PARTITION(xxx) option in the FROM clause: CREATE TABLE salvage_table AS SELECT /*+ ROWID(A) */ * FROM <owner.tablename> PARTITION (<partition_name>) A WHERE rowid < '<lo_rid>' ; INSERT INTO salvage_table SELECT /*+ ROWID(A) */ * FROM <owner.tablename> PARTITION (<partition_name>) A WHERE rowid >= '<hi_rid>' ; NOTE: Please note this procedure can't be used for tables that have columns defined as LONG. For tables with LONG you will have to use export/import. Export ca be run using WHERE clause option. Once the table data has been salvaged then the tables can be renamed, or partition exchanged with the table, to put the salvaged data into place. The next steps are then normally to: - See if any data can be extracted from the corrupt block itself, or from indexes pointing at the corrupt block. This is discussed briefly below. - Sort out indexes, constraints etc.. on the new table / partition This is not discussed here. If the corrupt block is the table segment header, this method won't work. You still have the option of using any indexes on the corrupt table to extract the data. Use the following query to determine if the affected block is the segment header : select file_id,block_id,blocks,extent_id from dba_extents where owner='<owner>' and segment_name='<table_name>' and segment_type='TABLE' order by extent_id; FILE_ID BLOCK_ID BLOCKS EXTENT_ID --------- --------- --------- --------- 8 94854 20780 0 <- EXTENT_ID ZERO is segment header Finding out about data in the Corrupt Block ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ If there are any indexes on the corrupt table then it is possible to get some information about what data was in the corrupt block from the index. This requires selecting indexed columns from the table for rowids in the corrupt block. We already know the ROWID range covered by the corrupt block from the SELECT dbms_rowid.rowid_create ... statements above. To extract the column data use one of the following forms of select statement: If the columns required at NOT NULLable you can use a fast full scan: SELECT /*+ INDEX_FFS(X <index_name>) */ <index_column1>, <index_column2> ... FROM <tablename> X WHERE rowid >= '<low_rid>' AND rowid < '<hi_rid>' ; If the columns required are NULLable then you cannot use an index fast full scan and must use a range scan. This requires you to know a minimum possible value for the leading index column to ensure you enable the index scan: SELECT /*+ INDEX(X <index_name>) */ <index_column1>, <index_column2> ... FROM <tablename> X WHERE rowid >= '<low_rid>' AND rowid < '<hi_rid>' AND <index_column1> >= <min_col1_value> ; Using this technique for all indexes on the table may be able to retrieve some of the data. See <View:DBA_IND_COLUMNS> for which columns make up each index. Example of using ROWID Range Scans in Oracle8/8i or higher ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ This example shows the main steps only (missing out index information) for an ORA-1578 error. This example would be better handled using the 10231 event but we show the ROWID range scan method here: SQL> select * from scott.partitionexample; ORA-01578: ORACLE data block corrupted (file # 7, block # 12698) ORA-01110: data file 7: '/oracle1/oradata/V816/oradata/V816/users01.dbf' >> <RFN> = 7 , <BL> = 12698 , <AFN> = 7 In this example the absolute and relative file numbers happen to be the same. SQL> SELECT tablespace_name, segment_type, owner, segment_name FROM dba_extents WHERE file_id =7 AND 12698 between block_id AND block_id + blocks - 1 ; TABLESPACE_NAME SEGMENT_TYPE OWNER SEGMENT_NAME --------------- ------------ ----- ------------ USERS TABLE PARTITION SCOTT PARTITIONEXAMPLE SQL> SELECT partition_name FROM dba_extents WHERE file_id =7 AND 12698 between block_id AND block _id + blocks - 1; PARTITION_NAME ------------------------------ PARTEX2 SQL> SELECT data_object_id FROM dba_objects WHERE object_name = 'PARTITIONEXAMPLE' and owner='SCOTT' AND subobject_name= 'PARTEX2'; DATA_OBJECT_ID --------------- 88145 >> Use the block number in the error first SQL> select dbms_rowid.rowid_create(1, 88145,7,12698,0) from dual; DBMS_ROWID.ROWID_C ------------------ AAAVhRAAHAAADGaAAA >> Use the block number +1 next SQL> select dbms_rowid.rowid_create(1, 88145,7,12699,0) from dual; DBMS_ROWID.ROWID_C ------------------ AAAVhRAAHAAADGbAAA >> Now we can use the ROWID in SELECT, CTAS, INSERT AS SELECT etc.. SQL> SELECT /*+ ROWID(A) */ * FROM scott.partitionexample A WHERE rowid < 'AAAVhRAAHAAADGaAAA'; COLUMN1 COLUMN2 ---------- ---------- 15 a ... No error as we do not access the corrupt block. >> We can also attempt to see what data WAS in the corrupt block. >> Eg: Assume we have an index "PARTEXAM" on "COLUMN1" of our >> "PARTITIONEXAMPLE" table, and COLUMN1 is NOT NULL then we can: SQL> SELECT /*+ INDEX_FFS(A PARTEXAM) */ column1 FROM scott.partitionexample A WHERE rowid >= 'AAAVhRAAHAAADGaAAA' AND rowid < 'AAAVhRAAHAAADGbAAA' ; COLUMN1 ---------- 25 ...
사업자 정보 표시
(주)블루원 | 김홍태 | 서울특별시 용산구 원효로 4가 135 금홍 2빌딩 | 사업자 등록번호 : 106-86-76684 | TEL : 02-3272-7200 | Mail : support_ora@blueone.co.kr | 통신판매신고번호 : 호 | 사이버몰의 이용약관 바로가기
'DB - ORACLE > Oracle Trouble Shooting' 카테고리의 다른 글
unix server uptime 확인 (0) | 2017.05.15 |
---|---|
ASM 환경에서 Hot Backup 사용 하여 Single DB로 복구 (0) | 2017.04.12 |
Oracle SGA 값을 증가 시킬 때 발생 장애 원인 (0) | 2016.01.29 |
오라클 시퀀스 초기화 방법 (0) | 2016.01.14 |
2중화 환경 1번 노드 오라클 클러스터 파일 유실 시 복구 방법 테스트 (0) | 2016.01.04 |