使用Oradebug修改Oracle SCN

realkid4發表於2016-10-26

 

Oracle SCN對於資料庫執行、維護而言是至關重要的因素。在啟動從mountopen過程中,主要是各種檔案的SCN進行比較的行為。通常情況下,我們是不需要介入到Oracle SCN的取值和設定,甚至錯誤的干預可能會引起嚴重執行事故。

 

在之前的文章中,筆者介紹過使用隱含引數和跟蹤事件來推動Oracle SCN前進的方法。但是,在11.2.0.2之後的版本中,Oracle關閉了這個通道,這種方法不在有效。在高版本情況下,我們是可以透過oradebug工具對SCN進行修改。

 

注意:這種方法比較危險,請不要在投產環境下進行測試。

 

1、實驗環境說明

 

筆者使用Oracle 11g進行測試,版本為11.2.0.4。對應作業系統是Linux 6.5 64bit版本。

 

 

SQL> select * from v$version;

 

BANNER

--------------------------------------------------------------------------------

Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production

PL/SQL Release 11.2.0.4.0 - Production

CORE    11.2.0.4.0      Production

TNS for Linux: Version 11.2.0.4.0 - Production

NLSRTL Version 11.2.0.4.0 – Production

 

 

我們先聊聊OracleSCN。在資料庫內部,SCN是一個單向遞增的數字編號,控制檔案、資料檔案、線上Redo日誌、歸檔日誌和備份集合中,都包括這個數字編號。在內部檔案中,SCN是透過BaseWrap兩個部分進行儲存。BaseSCN編號的基礎位,是透過32位二進位制位進行儲存。一旦超過這32位長度,系統會自動在Wrap進位。也就是說,Wrap表示的超過4G個數的進位次數。

 

使用Oracle oradebug修改SCN,可以在兩個場景下進行,就是Oracle啟動Open狀態和Mount狀態。下面分別進行說明。

 

2Open狀態下SCN修改

 

Open狀態,系統的SCN是在不斷的向前推動,即使對外沒有事務操作,系統內部SCN編號也在不斷的前進。我們先將資料庫進入open狀態。

 

 

SQL> alter database open;

Database altered.

 

SQL> select CHECKPOINT_CHANGE#, current_scn from v$database;

 

CHECKPOINT_CHANGE# CURRENT_SCN

------------------ -----------

           1753982     1754355

 

SQL> select dbms_flashback.get_system_change_number from dual;

 

GET_SYSTEM_CHANGE_NUMBER

------------------------

                 1754364

 

 

此時,從系統中提取出的SCN編號約為1754364,顯然沒有超過wrap的進位4G,變化為16進位制如下:

 

 

SQL> select to_char(1754364, 'XXXXXXXX') from dual;

 

TO_CHAR(1754364,'XXXXXXXX')

---------------------------

   1AC4FC

 

 

使用oradebug檢視記憶體中SCN對應的變數。

 

 

SQL> oradebug setmypid

Statement processed.

SQL> oradebug dumpvar sga kcsgscn_                      

kcslf kcsgscn_ [06001AE70, 06001AEA0) = 001AC52A 00000000 00000000 00000000 00000065 00000000 00000000 00000000 00000000 00000000 6001AB50 00000000

 

 

其中,0x001AC52A近似SCNBase部分。注意:Linux系統是Little位的作業系統,Base在前,Wrap在後。

 

 

SQL> select to_number('1AC52A','xxxxxx') from dual;

 

TO_NUMBER('1AC52A','XXXXXX')

----------------------------

                     1754410

 

 

下面計劃將Base修改為1800000,檢視16進製取值。

 

 

SQL> select to_char(1800000, 'XXXXXXXX') from dual;

 

TO_CHAR(1800000,'XXXXXXXX')

---------------------------

   1B7740

 

 

使用poke命令將計算好的值寫入進去。

 

 

SQL> oradebug poke 0x06001AE70 4 0x001B7740

BEFORE: [06001AE70, 06001AE74) = 001AC66F

AFTER:  [06001AE70, 06001AE74) = 001B7740

SQL> oradebug DUMPvar SGA kcsgscn_

kcslf kcsgscn_ [06001AE70, 06001AEA0) = 001B7745 00000000 00000000 00000000 00000164 00000000 00000000 00000000 00000000 00000000 6001AB50 00000000

SQL>

 

 

poke命令中,第一位引數是對應寫入的記憶體位數,第二位引數是寫入長度,第三位引數是寫入取值。預設寫入取值是10進位制,我們在這裡指定寫入16進位制。

 

每一個取值段,用816進位制對應,對應到數字位數是4位。此時檢視Oracle情況。

 

 

SQL> select CHECKPOINT_CHANGE#, current_scn from v$database;

 

CHECKPOINT_CHANGE# CURRENT_SCN

------------------ -----------

           1753982     1800400

 

SQL> select dbms_flashback.get_system_change_number from dual;

 

GET_SYSTEM_CHANGE_NUMBER

------------------------

                 1800402

 

 

SQL> select file#, checkpoint_change# from v$datafile;

 

     FILE# CHECKPOINT_CHANGE#

---------- ------------------

         1            1753982

         2            1753982

         3            1753982

         4            1753982

         5            1753982

         6            1753982

         7            1753982

 

7 rows selected

 

SQL> select file#, checkpoint_change# from v$datafile_header;

 

     FILE# CHECKPOINT_CHANGE#

---------- ------------------

         1            1753982

         2            1753982

         3            1753982

         4            1753982

         5            1753982

         6            1753982

         7            1753982

 

7 rows selected

 

 

從上面看,記憶體和控制檔案中新的取值已經寫入進去了。但是各個檔案的頭塊和檢查點還沒有反應過來。此時可以使用checkpoint強制寫入。

 

 

SQL> alter system checkpoint;

System altered.

 

SQL> select file#, checkpoint_change# from v$datafile;

 

     FILE# CHECKPOINT_CHANGE#

---------- ------------------

         1            1800422

         2            1800422

         3            1800422

         4            1800422

         5            1800422

         6            1800422

         7            1800422

 

7 rows selected

 

SQL> select file#, checkpoint_change# from v$datafile_header;

 

     FILE# CHECKPOINT_CHANGE#

---------- ------------------

         1            1800422

         2            1800422

         3            1800422

         4            1800422

         5            1800422

         6            1800422

         7            1800422

 

7 rows selected

 

SQL> select CHECKPOINT_CHANGE#, current_scn from v$database;

 

CHECKPOINT_CHANGE# CURRENT_SCN

------------------ -----------

           1800422     1800433

 

 

此時,關閉重啟系統也不會有問題。篇幅原因,不進行具體展示。那麼,很多時候SCN錯誤是會影響到開啟資料庫的,我們可能都不能進入open狀態。從mount狀態下我們怎麼修改SCN編號。

 

3Mount狀態修改SCN編號

 

我們測試進入mount狀態。

 

 

SQL> startup mount

ORACLE instance started.

 

Total System Global Area 3540881408 bytes

Fixed Size                  2258320 bytes

Variable Size             855640688 bytes

Database Buffers         2667577344 bytes

Redo Buffers               15405056 bytes

Database mounted.

 

 

此時,oradebug命令匯出記憶體取值。

 

 

SQL> oradebug setmypid

Statement processed.

SQL> oradebug DUMPvar SGA kcsgscn_

kcslf kcsgscn_ [06001AE70, 06001AEA0) = 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 6001AB50 00000000

 

 

注意:在mount狀態下,記憶體中的SCN取值都是0,包括basewrap兩部分。我們這次修改wrap01。這個過程中,我們需要寫入basewrap兩個部分,如果我們只寫入了wrap部分,base部分保持0,那麼系統執行的時候,會從base0開始。

 

此時,需要檢視一下當前檔案裡面SCN是多少。

 

 

SQL> select file#, checkpoint_change# from v$datafile;

 

     FILE# CHECKPOINT_CHANGE#

---------- ------------------

         1            1800920

         2            1800920

         3            1800920

         4            1800920

         5            1800920

         6            1800920

         7            1800920

 

7 rows selected

 

SQL> select file#, checkpoint_change# from v$datafile_header;

 

     FILE# CHECKPOINT_CHANGE#

---------- ------------------

         1            1800920

         2            1800920

         3            1800920

         4            1800920

         5            1800920

         6            1800920

         7            1800920

 

7 rows selected

 

SQL> select CHECKPOINT_CHANGE#, current_scn from v$database;

 

CHECKPOINT_CHANGE# CURRENT_SCN

------------------ -----------

           1800920           0

 

 

計算1800920對應到16進製取值為:0x001B7AD8。下面分別寫入basewrap取值。

 

 

SQL> oradebug DUMPvar SGA kcsgscn_

kcslf kcsgscn_ [06001AE70, 06001AEA0) = 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 6001AB50 00000000

SQL> oradebug poke 0x06001AE70 4 0x001B7AD8

BEFORE: [06001AE70, 06001AE74) = 00000000

AFTER:  [06001AE70, 06001AE74) = 001B7AD8

SQL> oradebug poke 0x06001AE74 4 0x00000001

BEFORE: [06001AE74, 06001AE78) = 00000000

AFTER:  [06001AE74, 06001AE78) = 00000001

SQL> oradebug DUMPvar SGA kcsgscn_

kcslf kcsgscn_ [06001AE70, 06001AEA0) = 001B7AD8 00000001 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 6001AB50 00000000

 

 

啟動資料庫。

 

 

SQL> alter database open;

Database altered.

 

SQL> select CHECKPOINT_CHANGE#, current_scn from v$database;

 

CHECKPOINT_CHANGE# CURRENT_SCN

------------------ -----------

        4296768217  4296768485

 

SQL> select file#, checkpoint_change# from v$datafile_header;

 

     FILE# CHECKPOINT_CHANGE#

---------- ------------------

         1         4296768217

         2         4296768217

         3         4296768217

         4         4296768217

         5         4296768217

         6         4296768217

         7         4296768217

 

7 rows selected

 

SQL> select file#, checkpoint_change# from v$datafile;

 

     FILE# CHECKPOINT_CHANGE#

---------- ------------------

         1         4296768217

         2         4296768217

         3         4296768217

         4         4296768217

         5         4296768217

         6         4296768217

         7         4296768217

 

7 rows selected

 

 

顯然在open的時候,寫入的checkpoint在所有檔案中。寫入的wrap頭也比較清晰。

 

 

SQL> select 4296768217/(4*1024*1024*1024) from dual;

 

4296768217/(4*1024*1024*1024)

-----------------------------

              1.0004193095956

 

SQL> oradebug DUMPvar SGA kcsgscn_

kcslf kcsgscn_ [06001AE70, 06001AEA0) = 001B7C1D 00000001 00000000 00000000 00000047 00000000 00000000 00000000 00000000 00000000 6001AB50 00000000

 

 

4、結論

 

使用oradebug直接修改記憶體SCN,是我們在故障修復時候非常快捷的方法。不過,快捷建立在對內部機制清晰理解的前提之下。所以,無論何種場景進行修復,有備份、可恢復是我們工作的基本前提。

 


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/17203031/viewspace-2127169/,如需轉載,請註明出處,否則將追究法律責任。

相關文章