溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

ORACLE壞塊是如何產(chǎn)生的

發(fā)布時(shí)間:2021-11-06 17:29:19 來源:億速云 閱讀:162 作者:柒染 欄目:建站服務(wù)器

本篇文章為大家展示了ORACLE壞塊是如何產(chǎn)生的,內(nèi)容簡(jiǎn)明扼要并且容易理解,絕對(duì)能使你眼前一亮,通過這篇文章的詳細(xì)介紹希望你能有所收獲。

Oracle數(shù)據(jù)庫出現(xiàn)壞塊現(xiàn)象是指:在Oracle數(shù)據(jù)庫的一個(gè)或多個(gè)數(shù)據(jù)塊(一個(gè)數(shù)據(jù)塊的容量在創(chuàng)建數(shù)據(jù)庫時(shí)由db_block_size參數(shù)指定,缺省為8K)內(nèi)出現(xiàn)內(nèi)容混亂的現(xiàn)象。由于正常的數(shù)據(jù)塊都有固定的合法內(nèi)容格式,壞塊的出現(xiàn),導(dǎo)致數(shù)據(jù)庫進(jìn)程無法正常解析數(shù)據(jù)塊的內(nèi)容,進(jìn)而使數(shù)據(jù)庫進(jìn)程報(bào)錯(cuò)乃至掛起,并級(jí)聯(lián)導(dǎo)致整個(gè)數(shù)據(jù)庫實(shí)例出現(xiàn)異常。

 

一.壞塊的產(chǎn)生原因

 

壞塊產(chǎn)生的原因大致有以下幾種:

1.1 硬件問題

Oracle進(jìn)程在處理一個(gè)數(shù)據(jù)塊時(shí),首先將其讀入物理內(nèi)存空間,在處理完成后,再由特定進(jìn)程將其寫回磁盤;如果在這個(gè)過程中,出現(xiàn)內(nèi)存故障,CPU計(jì)算失誤,都會(huì)導(dǎo)致內(nèi)存數(shù)據(jù)塊的內(nèi)容混亂,最后反映到寫回磁盤的數(shù)據(jù)塊內(nèi)容有誤。同樣,如果存儲(chǔ)子系統(tǒng)出現(xiàn)異常,數(shù)據(jù)塊損壞也就隨之出現(xiàn)了。

 

1.2 操作系統(tǒng)BUG

由于Oracle進(jìn)程對(duì)數(shù)據(jù)塊的讀寫,都是以操作系統(tǒng)內(nèi)核調(diào)用(system call)的方式完成的,如果操作系統(tǒng)在內(nèi)核調(diào)用存在問題,必然導(dǎo)致Oracle進(jìn)程寫入非法的內(nèi)容。

 

1.3 操作系統(tǒng)的I/O錯(cuò)誤或緩沖問題

 

1.4 內(nèi)存或paging問題

 

Oracle軟件BUG

Oracle軟件特定版本上,可能出現(xiàn)導(dǎo)致數(shù)據(jù)塊的內(nèi)容出現(xiàn)異常BUG。

 

1.5 非Oracle進(jìn)程擾亂Oracle共享內(nèi)存區(qū)域

如上文所述,在當(dāng)數(shù)據(jù)塊的內(nèi)容被讀入主機(jī)的物理內(nèi)存時(shí),如果其他非Oracle進(jìn)程,對(duì)Oracle使用的共享內(nèi)存區(qū)域形成了擾亂,最終導(dǎo)致寫回磁盤的數(shù)據(jù)塊內(nèi)容混亂。

 

1.6 異常關(guān)機(jī),掉電,終止服務(wù)

異常關(guān)機(jī),掉電,終止服務(wù)使進(jìn)程異常終止,而破壞數(shù)據(jù)塊的完整性,導(dǎo)致壞塊產(chǎn)生。

注:這也是為什么突然斷電會(huì)導(dǎo)致數(shù)據(jù)庫無法啟動(dòng)

 

由上可見,壞塊的形成原因復(fù)雜。當(dāng)出現(xiàn)壞塊時(shí),為了找到確切的原因,需要大量的分析時(shí)間和排查操作,甚至需要多次重現(xiàn)才能找出根本原因。但當(dāng)故障發(fā)生在生產(chǎn)系統(tǒng)上,我們?yōu)榱藴p少停機(jī)時(shí)間,會(huì)盡快實(shí)施應(yīng)急權(quán)變措施以保證系統(tǒng)的可用性,這樣就破壞了故障現(xiàn)場(chǎng),對(duì)根本原因的分析因而也更加困難了。

 

二.壞塊的預(yù)防

 

壞塊問題破壞性大,但并非不可預(yù)防。

 

2.1 在Metalink.oracle.com網(wǎng)站,Oracle定期發(fā)布基于特定軟件版本的“已知問題(known issues)說明”。對(duì)于可能導(dǎo)致壞塊的Oracle軟件BUG,在Oracle公司內(nèi)部,是作為高嚴(yán)重級(jí)別的問題進(jìn)行處理,在“已知問題(known issues)說明”中,這些BUG以嚴(yán)重(Noticable)問題標(biāo)出(標(biāo)記為*或+),部分問題,Oracle還會(huì)發(fā)布警告(Alert)通告。在文檔中,Oracle會(huì)提供相應(yīng)的補(bǔ)丁或應(yīng)對(duì)措施。

 

2.2 Oracle提供備份恢復(fù)工具-Recovery Manager,提供了掃描文件檢查壞塊的功能。

在Recovery Manager界面中,使用:

RMAN> BACKUP CHECK LOGICAL VALIDATE DATAFILE n ;

 

可以檢查數(shù)據(jù)文件是否包含壞塊,同時(shí)并不產(chǎn)生實(shí)際的備份輸出。

 

2.3 Dbv工具檢查

注:因?yàn)閐bv要求file后面跟的必須是一個(gè)文件擴(kuò)展名,所以如果用裸設(shè)備存儲(chǔ)

的,就必須使用ln鏈接裸設(shè)備到一個(gè)文件,然后再用dbv對(duì)這個(gè)鏈接文件進(jìn)行檢

查。

 

ANALYZE TABLE tablename VALIDATE STRUCTURE CASCADE

它執(zhí)行壞塊的檢查,但是不會(huì)標(biāo)記壞塊為corrupt,檢測(cè)的結(jié)果保存在USER_DUMP_DEST目錄下的用戶trace文件中。

 

2.4 利用exp工具導(dǎo)出整個(gè)數(shù)據(jù)庫可以檢測(cè)壞塊

對(duì)以下情況的壞塊是檢測(cè)不出來的:

 HWM以上的壞塊是不會(huì)發(fā)現(xiàn)的

 索引中存在的壞塊是不會(huì)發(fā)現(xiàn)的

 數(shù)據(jù)字典中的壞塊是不會(huì)發(fā)現(xiàn)的

 

結(jié)合數(shù)據(jù)庫性能綜合考慮db_block_checksum和db_blockchecking參數(shù)。

 

當(dāng)我們使用Recovery Manager進(jìn)行實(shí)際的數(shù)據(jù)庫備份時(shí),同時(shí)也就進(jìn)行了壞塊

檢查。但要注意的是,在線使用Recovery Manager掃描壞塊和備份時(shí),需要數(shù)

據(jù)庫運(yùn)行在歸檔模式(archive log),否則只能在數(shù)據(jù)庫未打開的情況下進(jìn)行。

 

對(duì)于操作系統(tǒng)問題和硬件故障,則需要相應(yīng)廠商的配合支持。同時(shí),避免在數(shù)

據(jù)庫主機(jī)運(yùn)行其他用戶進(jìn)程,避免異常停機(jī),也會(huì)減少壞塊發(fā)生的幾率。

 

壞塊故障的識(shí)別

遇到壞塊問題時(shí),數(shù)據(jù)庫的異常表現(xiàn)通常有:

報(bào)告ORA-01578錯(cuò)誤。

報(bào)告Ora-1110錯(cuò)誤。

報(bào)告ORA-00600錯(cuò)誤,其中,第一個(gè)參數(shù)為2000-8000,Cache layer 2000 – 4000,Transaction layer 4000 – 6000,Data layer 6000 - 8000。

Trace文件中出現(xiàn)Corrupt block dba: 0x160c5958 . found。

分析對(duì)象失敗。

后臺(tái)進(jìn)程,如DBWR,LGWR出現(xiàn)長(zhǎng)時(shí)間異常等待,如“LGWR wait for redo copy”。

 

 

四.Oracle數(shù)據(jù)塊損壞恢復(fù)總結(jié)

 

可以用DBV 命令來檢測(cè)是否有壞塊:

 

在恢復(fù)前使用DBV命令檢查數(shù)據(jù)文件是否存在壞塊

dbv file=d:\oracle\oradata\mydb\RONLY.DBF blocksize=8192

 

查看數(shù)據(jù)壞塊所在數(shù)據(jù)文件號(hào)及塊號(hào)可以對(duì)表進(jìn)行一次全表掃描,如:

select count(*) from tablename;

 

 

 

4.1 沒有備份的情況下:

4.1.1、使用exp/imp恢復(fù)

在這種情況下肯定會(huì)造成數(shù)據(jù)的丟失,在這種情況下應(yīng)采取將數(shù)據(jù)導(dǎo)出然后重建表再進(jìn)行導(dǎo)入的方法,來盡量恢復(fù)損壞數(shù)據(jù)塊中的數(shù)據(jù),但是在有壞塊的情況下是不允許導(dǎo)出的,如下命令:

Exp test/test file=t.dmp tables=t;

 

導(dǎo)出命令在執(zhí)行中會(huì)報(bào)ORA-01578錯(cuò)誤,在這錯(cuò)誤提示中會(huì)提示那個(gè)文件號(hào)的文件以及這個(gè)文件中的哪個(gè)塊被損壞,如:ORA—01578:ORACLE 數(shù)據(jù)塊損壞(文件號(hào) 4,塊號(hào) 35)

針對(duì)以上的提示首先查詢那些對(duì)象被損壞:

 

Select tablespace_name,segment_type,owner,segment_name From dba_extents Where file_id=4 and 35 between block_id and block_id+blocks-1;

 

如果被損壞的塊是索引,通??梢酝ㄟ^索引重建來解決,如果損壞的是數(shù)據(jù)(segment_type為table),那么通過設(shè)置如下內(nèi)部事件使得Exp操作跳過壞塊。

Alter session set events=’10231 trace name context forever,level 10’;

 

然后重新執(zhí)行導(dǎo)出命令,導(dǎo)出相關(guān)的表,然后執(zhí)行Drop Table命令刪除相關(guān)表,之后重建表最后導(dǎo)入數(shù)據(jù)。

 

4.1.2、使用DBMS_REPAIR恢復(fù)

用DBMS_REPAIR當(dāng)然也會(huì)丟失數(shù)據(jù)。這里不做詳細(xì)的介紹,有興趣的可以查看oracle的在線文檔

 

 

4.2 使用Rman進(jìn)行恢復(fù):

首先要存在Rman的最新備份集,然后執(zhí)行如下命令:

RMAN>backup validate datafile 4;

 

檢查4號(hào)數(shù)據(jù)文件是否存在壞塊

執(zhí)行查詢:

select * from v$database_block_corruption where file#=4;

 

如果4號(hào)文件存在壞塊的話,那么將在結(jié)果集中有所顯示,會(huì)顯示損壞的塊號(hào),根據(jù)顯示結(jié)果執(zhí)行如下命令進(jìn)行恢復(fù):

RMAN>blockrecover datafile 4 block 35 from backupset;

 

該命令執(zhí)行后即可恢復(fù)壞塊,并且不會(huì)造成數(shù)據(jù)丟失,但是要求數(shù)據(jù)庫必須要運(yùn)行在歸檔模式下,否則RMAN無法發(fā)揮作用,而且通過RMAN做過最新的數(shù)據(jù)庫備份

 

 

4.3 使用bbed恢復(fù)

使用bbed恢復(fù)時(shí)必須有數(shù)據(jù)文件的拷貝。

bbed就是英文block browse edit的縮寫,用來直接查看和修改數(shù)據(jù)文件數(shù)據(jù)的一個(gè)工具。

 

BBED在windows 8i中在$ORACLE_HOME/bin下可以找到,9i中似乎未隨軟件發(fā)布,故

在windows沒有這個(gè)工具,linux下需要編譯:

然后把$ORACLE_HOME/rdbms/lib加到環(huán)境變量的PATH里面,就可以直接在命令中bbed了。

BBED的缺省口令為blockedit,

For Oracle Internal Use only 請(qǐng)謹(jǐn)慎使用Oracle不做技術(shù)支持。

 

 

五.如何查找壞塊所含的數(shù)據(jù)表名稱和數(shù)據(jù)的rowid

5.1. 首先肯定知道那個(gè)數(shù)據(jù)文件壞了,查出該文件的file_id,relative_fno,tablespace_name

 

  利用dba_data_files可以查詢file_id(整個(gè)數(shù)據(jù)庫唯一序號(hào)),RELATIVE_FNO(相對(duì)一個(gè)表空間內(nèi)的序號(hào))

 

5.2. 找到壞塊的ID(可以運(yùn)行dbverify實(shí)現(xiàn)),假設(shè)找到的壞塊ID為1234。

5.3.運(yùn)行下面的查詢,根據(jù),壞塊的file_id,block id查找該塊對(duì)應(yīng)的owner,segment_type,

segment_name等信息

 

    select owner,file_id,segment_name, segment_type, block_id, blocks

  from dba_extents

  where  file_id=13 and block_id<=1234 and (block_id + blocks- 1) >= 1234;

 

 

5.4. 根據(jù)壞塊的file_id,owner,segment_name,block_id,如果是數(shù)據(jù)表的話,用下面的查詢來得到對(duì)應(yīng)壞塊的rowid

 

  假設(shè)owner  :  DAVE

 

      segment_name:  BL

 

      file_id     :  13

 

      block_id    :  162

 

  運(yùn)行下面的查詢來獲得該塊所含的rowid(如果沒有索引,可能就不能用下面的方式了):

 

select /*+ index(DAVE, i_test)?*/ rowid

 from DAVE.BL

  where  dbms_rowid.rowid_to_absolute_fno(rowid,'DAVE','BL')=13

  and  dbms_rowid.rowid_block_number(rowid)=162;   

 

六,如何模擬壞塊

 

DBA 的基本知識(shí),制造壞塊的方法很多的,可以用ultraedit,也可以用dd命令,同時(shí)也呆以用orapatch工具

 

6.1 orapatch 工具:
$orapatch open tools001.dbf write
patch>set hex --要用十六進(jìn)制
patch>display 177 --orapatch以512字節(jié)為工作模式,假定想破壞第11個(gè)block即為:8k/512*11+1(file header)
patch>find 00400003 --選一個(gè)要編輯的點(diǎn)
patch>modify 00400002 --破壞
patch>exit

 

6.2 用編輯器打開 datafile 以 8192 字節(jié)為一大小(db 的block是 8192)
下面是一個(gè) block 的開始的 20個(gè)字節(jié)和結(jié)尾的 4 個(gè)字節(jié)
06 02 00 00 08 00 c0 02 6c 43 0d 00 00 00 01 02
00 00 00 00 -- block head

06 02 6c 43 -- block tail 這里有 scn(6c 43) 的情況和 block (06)的類型 (01) 和 head 的 seq: 0x01 對(duì)應(yīng),只要改block尾部的4個(gè)字節(jié)中的或block開始的對(duì)應(yīng)字節(jié)任何一個(gè)就一定會(huì)有 ora-1578,但如果數(shù)據(jù)庫有 ora-1578的 error不一定是這樣引起的

btw : UE不是很好 用winhex吧 不錯(cuò)喔

 

6.3 BBED 工具

 

 

七. 如何利用dbms_repair來標(biāo)記和跳過壞塊

但是當(dāng)數(shù)據(jù)量很大,或7*24的系統(tǒng)時(shí),我們使用dbms_repair來處理。dbms_repair是從oracle8i開始提供的。

 

準(zhǔn)備工作:

create tablespace block datafile '/u01/block.dbf' size 5M;

create table DMM tablespace block as select * from all_tables;

commit;

CREATE INDEX indx_dmm on DMM(TABLE_NAME);

select count(*) from DMM;

  COUNT(*)

----------

12896

 

 

7.1.創(chuàng)建管理表:

SQL> conn sys/admin as sysdba;

已連接。

SQL> exec DBMS_REPAIR.ADMIN_TABLES('REPAIR_TABLE',1,1,'USERS');

PL/SQL procedure successfully completed

SQL> exec DBMS_REPAIR.ADMIN_TABLES('ORPHAN_TABLE',2,1,'USERS');

PL/SQL procedure successfully completed

 

7.2.檢查壞塊:dbms_repair.check_object

 

/* Formatted on 2009-12-16 23:41:32 (QP5 v5.115.810.9015) */

Set serveroutput on;

DECLARE

   cc  NUMBER;

BEGIN

   DBMS_REPAIR.check_object (schema_name => 'SYS', -- 注意此處是用戶名

                             object_name     => 'DMM',

                             corrupt_count   => cc);

   DBMS_OUTPUT.put_line ( TO_CHAR (cc));

END;

 

正常情況下輸入為0.

 

如果有壞塊,可以在創(chuàng)建的REPAIR_TABLE中查看塊損壞信息:   

 

/* Formatted on 2009-12-17 13:18:19 (QP5 v5.115.810.9015) */

SELECT   object_name,

         relative_file_id,

         block_id,

         marked_corrupt,

         corrupt_description,

         repair_description,

         CHECK_TIMESTAMP

  FROM   repair_table;                                                                                                                                                                                                        

                                                                                                                                           

 

注意:在8i下,check_object只會(huì)檢查壞塊,MARKED_CORRUPT為false,故需要執(zhí)行第三步: 定位壞塊,fix_corrupt_blocks定位 ,修改MARKED_CORRUPT為true,同時(shí)更新CHECK_TIMESTAMP。9i以后經(jīng)過check_object,MARKED_CORRUPT的值已經(jīng)標(biāo)識(shí)為TRUE了。所以可以直接進(jìn)行第四步了。

 

 

7.3.定位壞塊:dbms_repair.fix_corrupt_blocks     

只有將壞塊信息寫入定義的REPAIR_TABLE后,才能定位壞塊。 

/* Formatted on 2009-12-17 13:29:01 (QP5 v5.115.810.9015) */

DECLARE

   cc   NUMBER;

BEGIN

   DBMS_REPAIR.fix_corrupt_blocks (schema_name   => 'SYS',

                                   object_name   => 'DMM',

                                   fix_count     => cc);

   DBMS_OUTPUT.put_line (a => TO_CHAR (cc));

END;

 

 

7.4.跳過壞塊:

我們前面雖然定位了壞塊,但是,如果我們?cè)L問table:

SQL> select count(*) from SYS.DMM;

 

 

ORA-01578: ORACLE 數(shù)據(jù)塊損壞(文件號(hào)14,塊號(hào)154)

ORA-01110: 數(shù)據(jù)文件 14: 'D: \BLOCK.DBF'

 

還是會(huì)得到錯(cuò)誤信息。 這里需要用skip_corrupt_blocks來跳過壞塊:

 

/* Formatted on 2009-12-17 13:30:17 (QP5 v5.115.810.9015) */

exec dbms_repair.skip_corrupt_blocks(schema_name => 'SYS',object_name => 'DMM',flags => 1);

 

 

SQL> select count(*) from SYS.DMM;

 

  COUNT(*)

----------

     12850

丟失了12896-12850=46行數(shù)據(jù)。

 

 

7.5.處理index上的無效鍵值;dump_orphan_keys

 

/* Formatted on 2009-12-17 13:34:55 (QP5 v5.115.810.9015) */

DECLARE

   cc   NUMBER;

BEGIN

   DBMS_REPAIR.dump_orphan_keys (schema_name         => 'SYS',

                                 object_name         => 'INDX_DMM',

                                 object_type         => 2,

                                 repair_table_name   => 'REPAIR_TABLE',

                                 orphan_table_name   => 'ORPHAN_TABLE',

                                 key_count           => CC);

END;

 

通過以下命令可以知道丟失行的信息:

SQL> SELECT * FROM ORPHAN_TABLE;

 

我們根據(jù)這個(gè)結(jié)果來考慮是否需要rebuild index.

7.6.重建freelist:rebuild_freelists

 

/* Formatted on 2009-12-17 13:37:57 (QP5 v5.115.810.9015) */

exec dbms_repair.rebuild_freelists(schema_name => 'SYS',object_name => 'DMM');

 

八. 設(shè)置內(nèi)部事件使exp跳過壞塊

我們可以用設(shè)置event的方法來處理壞塊:先模擬出壞塊,然后用dbv檢查,此時(shí),不用dbms_repair,而用下面的方法:

 

8.1. 先exp該表試驗(yàn)一下

在這種情況下,如果有備份,需要從備份中恢復(fù),如果沒有備份,那么壞塊部分的數(shù)據(jù)肯定要丟失了

在這個(gè)時(shí)候?qū)С鍪遣辉试S的:
E:\>exp system/admin file=t.dmp tables=t

報(bào)錯(cuò)如下:
即將導(dǎo)出指定的表通過常規(guī)路徑 ...
. . 正在導(dǎo)出表 T
EXP-00056: 遇到 ORACLE 錯(cuò)誤 1578
ORA-01578: ORACLE 數(shù)據(jù)塊損壞(文件號(hào)4,塊號(hào)35)
ORA-01110: 數(shù)據(jù)文件 4: 'E:\ORACLE\ORADATA\EYGLE\BLOCK.DBF'
導(dǎo)出成功終止,但出現(xiàn)警告。

 

8.2. 對(duì)于不同的情況需要區(qū)別對(duì)待 ,如果損失不是數(shù)據(jù)而是重要的oracle內(nèi)部信息,則不能用set event

 

首先你需要檢查損壞的對(duì)象,使用以下SQL:

/* Formatted on 2009-12-17 14:00:42 (QP5 v5.115.810.9015) */

SELECT   tablespace_name,

         segment_type,

         owner,

         segment_name

  FROM   dba_extents

 WHERE   file_id = 4 AND 35 BETWEEN block_id AND block_id + blocks - 1;




 


8.3. 如果損失的是數(shù)據(jù),ok,可以設(shè)置內(nèi)部事件,使exp跳過這些損壞的block

 

10231事件指定數(shù)據(jù)庫在進(jìn)行全表掃描時(shí)跳過損壞的塊

ALTER SYSTEM SET EVENTS='10231 trace name context forever,level 10' ;

然后我們可以導(dǎo)出未損壞的數(shù)據(jù)
E:\> exp system/admin file=t.dmp tables=t

即將導(dǎo)出指定的表通過常規(guī)路徑 ...
. . 正在導(dǎo)出表 T 8036 行被導(dǎo)出
在沒有警告的情況下成功終止導(dǎo)出。

然后我們可以drop table,recreate,然后導(dǎo)入數(shù)據(jù)


8.4. 重建表,再導(dǎo)入

SQL> connect sys/admin as sysdba
已連接。
SQL> drop table t;
表已丟棄。
E:\>imp system/admin file=t.dmp tables=t

. 正在將system的對(duì)象導(dǎo)入到 system
. . 正在導(dǎo)入表 "T" 8036行被導(dǎo)入
成功終止導(dǎo)入,但出現(xiàn)警告。

E:\>exit
SQL> select count(*) from t;

COUNT(*)
----------
8036

完成數(shù)據(jù)恢復(fù).

 

損失的行數(shù)可以從2個(gè)行數(shù)相減計(jì)算:
8192 - 8036 = 156 行數(shù)據(jù)

 

 

8.5如果要取消events設(shè)置,做以下操作:

1. 如果你在初始化參數(shù)中設(shè)置的
注釋之

2. 如果在命令行設(shè)置的
alter system set events='10231 trace name context off';

上述內(nèi)容就是ORACLE壞塊是如何產(chǎn)生的,你們學(xué)到知識(shí)或技能了嗎?如果還想學(xué)到更多技能或者豐富自己的知識(shí)儲(chǔ)備,歡迎關(guān)注億速云行業(yè)資訊頻道。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI