1. SCN的定義ios
SCN(System Change Number),也就是一般所說的系統改變號,是數據庫中很是重要的一個數據結構。算法
SCN用以標識數據庫在某個確切時刻提交的版本。在事務提交時,它被賦予一個惟一的標識事務的SCN。SCN同時被做爲Oracle數據庫的內部時鐘機制,可被看作邏輯時鐘,每一個數據庫都有一個全局的SCN生成器。sql
做爲數據庫內部的邏輯時鐘,數據庫事務依SCN而排序,Oracle也依據SCN來實現一致性讀(Read Consistency)等重要數據庫功能。另外對於分佈式事務(Distributed Transactions),SCN也極爲重要,這裏不作更多介紹。數據庫
SCN在數據庫中是惟一的,並隨時間而增長,可是可能並不連貫。除非重建數據庫,SCN的值永遠不會被重置爲0.bootstrap
一直以來,對於SCN有不少爭議,不少人認爲SCN是指System Commit Number,而一般SCN在提交時才變化,因此不少時候,這兩個名詞常常在文檔中反覆出現。即便在Oracle的官方文檔中,SCN也常以System Change/Commit Number兩種形式出現。session
究竟是哪一個詞其實不是很重要,重要的是須要知道SCN是Oracle內部的時鐘機制,Oracle經過SCN來維護數據庫的一致性,並經過SCN實施Oracle相當重要的恢復機制。數據結構
SCN在數據庫中是無處不在,常見的事務表、控制文件、數據文件頭、日誌文件、數據塊頭等都記錄有SCN值。架構
冠以不一樣前綴,SCN也有了不一樣的名稱,如檢查點SCN(Checkpint SCN)、Resetlogs SCN等。oracle
2.SCN的獲取方式app
能夠經過以下幾種方式得到數據庫的當前或近似SCN。
(1) 從Oracle 9i開始。
可使用dbms_flashback.get_system_change_number來得到:
SQL> select dbms_flashback.get_system_change_number from dual;
GET_SYSTEM_CHANGE_NUMBER
------------------------
888266
(2) Oracle 9i前。
能夠經過查詢x$ktuxe得到系統最接近當前值的SCN:
X$ktuxe的含義是[k]ernel [T]ransaction [U]ndo Transa[x]tion [E]ntry(table)
SQL>select max(ktuxecnw*power(2,32)+ktuxescnb) from x$ktuxe;
MAX(KTUXESCNW*POWER(2,32)+KTUXESCNB)
------------------------
28848232
3.SCN的進一步說明
系統當前SCN並非在任何的數據庫操做時都會改變,SCN一般在事務提交或回滾時改變。在控制文件、數據文件頭、數據庫、日誌文件頭、日誌文件change vector中都有SCN,但其做用各不相同。
(1) 數據文件頭中包含了該數據文件的Checkpoint SCN,表示該數據文件最近一次執行檢查點操做時的SCN。
從控制文件的dump文件中,能夠獲得一下內容:
DATA FILE #1:
(name #7) /opt/ora10g/oradata/ORCL/system01.dbf
creation size=0 block size=8192 status=0xe head=7 tail=7 dup=1
tablespace 0, index=1 krfil=1 prev_file=0
unrecoverable scn: 0x0000.00000000 01/01/1988 00:00:00
Checkpoint cnt:106 scn: 0x0000.000d845f 11/14/2011 15:24:50
Stop scn: 0xffff.ffffffff 11/14/2011 14:31:00
Creation Checkpointed at scn: 0x0000.00000009 06/30/2005 19:10:11
……
對於每個數據文件都包含一個這樣的條目,記錄該文件的檢查點SCN的值以及檢查點發生的時間,這裏的Checkpint SCN、Stop SCN以及Checkpoint CNT都是很是重要的數據結構,咱們將會在下面檢查點部分詳細介紹。
一樣能夠經過命令轉儲數據文件頭,觀察其具體信息及檢查點記錄等,從跟蹤文件中摘取system表空間的記錄做爲參考:
***************************************************************************
DATA FILE RECORDS
***************************************************************************
(size = 428, compat size = 428, section max = 100, section in-use = 4,
last-recid= 53, old-recno = 0, last-recno = 0)
(extent = 1, blkno = 11, numrecs = 100)
DATA FILE #1:
(name #7) /opt/ora10g/oradata/ORCL/system01.dbf
creation size=0 block size=8192 status=0xe head=7 tail=7 dup=1
tablespace 0, index=1 krfil=1 prev_file=0
unrecoverable scn: 0x0000.00000000 01/01/1988 00:00:00
Checkpoint cnt:106 scn: 0x0000.000d845f 11/14/2011 15:24:50
Stop scn: 0xffff.ffffffff 11/14/2011 14:31:00
Creation Checkpointed at scn: 0x0000.00000009 06/30/2005 19:10:11
thread:0 rba:(0x0.0.0)
enabled threads: 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
Offline scn: 0x0000.0006ce7a prev_range: 0
Online Checkpointed at scn: 0x0000.0006ce7b 11/10/2011 22:40:23
thread:1 rba:(0x1.2.0)
enabled threads: 01000000 00000000 00000000 00000000 00000000 00000000
Hot Backup end marker scn: 0x0000.00000000
aux_file is NOT DEFINED
(2) 日誌文件頭包含了Low SCN 和Next SCN。
Low SCN和 Next SCN這兩個SCN表示該日誌文件包含介於Low SCN到Next SCN的重作信息,對於Current的日誌文件(當前正在被使用的Redo Logfile),其最終SCN不可知,因此Next SCN被置爲無窮大,也就是ffffffff。
來看一下日誌文件的狀況:
SQL> select * from v$log;
GROUP# THREAD# SEQUENCE# BYTES MEMBERS ARC STATUS FIRST_CHANGE# FIRST_TIM
---------- ---------- ---------- ---------- ---------- --- ----------------------------- ---------
1 1 35 52428800 1 NO CURRENT 881890 14-NOV-11
2 1 33 52428800 1 YES INACTIVE 836815 12-NOV-11
3 1 34 52428800 1 YES INACTIVE 858362 12-NOV-11
SQL> select dbms_flashback.get_system_change_number from dual;
GET_SYSTEM_CHANGE_NUMBER
------------------------
889346
SQL> alter system switch logfile;
System altered.
SQL> select * from v$log;
GROUP# THREAD# SEQUENCE# BYTES MEMBERS ARC STATUS FIRST_CHANGE# FIRST_TIM
---------- ---------- ---------- ---------- ---------- --- ----------------------------- ---------
1 1 35 52428800 1 YES ACTIVE 881890 14-NOV-11
2 1 36 52428800 1 NO CURRENT 889353 14-NOV-11
3 1 34 52428800 1 YES INACTIVE 858362 12-NOV-11
能夠看到,SCN 889346顯然位於Log Group#爲1的日誌文件中,該日誌文件包含了SCN自881890 至889353 的Redo信息。Oracle在進行恢復時,就須要根據低SCN和高SCN來肯定須要的恢復信息位於哪個日誌或歸檔文件中。
若是經過控制文件轉儲,能夠在控制文件中找到關於日誌文件的信息:
SQL> alter session set events 'immediate trace name redohdr level 10';
Session altered.
LOG FILE #1:
(name #3) /opt/ora10g/oradata/ORCL/redo01.log
Thread 1 redo log links: forward: 2 backward: 0
siz: 0x19000 seq: 0x00000026 hws: 0x1 bsz: 512 nab: 0xffffffff flg: 0x8 dup: 1
Archive links: fwrd: 0 back: 0 Prev scn: 0x0000.000de15c
Low scn: 0x0000.000def9a 11/16/2011 16:06:06
Next scn: 0xffff.ffffffff 01/01/1988 00:00:00
LOG FILE #2:
(name #2) /opt/ora10g/oradata/ORCL/redo02.log
Thread 1 redo log links: forward: 3 backward: 1
siz: 0x19000 seq: 0x00000024 hws: 0x4 bsz: 512 nab: 0x5c6 flg: 0x1 dup: 1
Archive links: fwrd: 0 back: 0 Prev scn: 0x0000.000d74e2
Low scn: 0x0000.000d9209 11/14/2011 16:57:08
Next scn: 0x0000.000de15c 11/16/2011 15:01:07
LOG FILE #3:
(name #1) /opt/ora10g/oradata/ORCL/redo03.log
Thread 1 redo log links: forward: 0 backward: 2
siz: 0x19000 seq: 0x00000025 hws: 0x3 bsz: 512 nab: 0x37e3 flg: 0x1 dup: 1
Archive links: fwrd: 0 back: 0 Prev scn: 0x0000.000d9209
Low scn: 0x0000.000de15c 11/16/2011 15:01:07
Next scn: 0x0000.000def9a 11/16/2011 16:06:06
能夠注意到,Log File 1是當前的日誌文件,該文件擁有的Next SCN是無窮大。
一樣,能夠經過直接dump日誌文件的方式來進行轉儲;
SQL> select * from v$logfile;
GROUP# STATUS TYPE MEMBER
---------- ------- ---------------------------------------------------------------------------
3 ONLINE /opt/ora10g/oradata/ORCL/redo03.log
2 ONLINE /opt/ora10g/oradata/ORCL/redo02.log
1 ONLINE /opt/ora10g/oradata/ORCL/redo01.log
SQL> alter system dump logfile '/opt/ora10g/oradata/ORCL/redo01.log';
System altered.
DUMP OF REDO FROM FILE '/opt/ora10g/oradata/ORCL/redo01.log'
Opcodes *.*
RBAs: 0x000000.00000000.0000 thru 0xffffffff.ffffffff.ffff
SCNs: scn: 0x0000.00000000 thru scn: 0xffff.ffffffff
Times: creation thru eternity
FILE HEADER:
Compatibility Vsn = 169869568=0xa200100
Db ID=1294662348=0x4d2afacc, Db Name='ORCL'
Activation ID=1294635980=0x4d2a93cc
Control Seq=953=0x3b9, File size=102400=0x19000
File Number=1, Blksiz=512, File Type=2 LOG
descrip:"Thread 0001, Seq# 0000000038, SCN 0x0000000def9a-0xffffffffffff"
thread: 1 nab: 0xffffffff seq: 0x00000026 hws: 0x1 eot: 1 dis: 0
resetlogs count: 0x2db5af57 scn: 0x0000.0006ce7b (446075)
resetlogs terminal rcv count: 0x0 scn: 0x0000.00000000
prev resetlogs count: 0x2184ef74 scn: 0x0000.00000001 (1)
prev resetlogs terminal rcv count: 0x0 scn: 0x0000.00000000
Low scn: 0x0000.000def9a (913306) 11/16/2011 16:06:06
Next scn: 0xffff.ffffffff 01/01/1988 00:00:00
Enabled scn: 0x0000.0006ce7b (446075) 11/10/2011 22:40:23
Thread closed scn: 0x0000.000def9a (913306) 11/16/2011 16:06:06
Disk cksum: 0x5987 Calc cksum: 0x5987
Terminal recovery stop scn: 0x0000.00000000
Terminal recovery 01/01/1988 00:00:00
Most recent redo scn: 0x0000.00000000
Largest LWN: 0 blocks
End-of-redo stream : No
Unprotected mode
Miscellaneous flags: 0x0
這裏不打算詳細介紹具體命令的用戶及更進一步的內容,有興趣的朋友能夠由此開始進一步的探索。
使用Oradebug修改Oracle SCN
Oracle SCN對於數據庫運行、維護而言是相當重要的因素。在啓動從mount到open過程當中,主要是各類文件的SCN進行比較的行爲。一般狀況下,咱們是不須要介入到Oracle SCN的取值和設置,甚至錯誤的干預可能會引發嚴重運行事故。
在以前的文章中,筆者介紹過使用隱含參數和跟蹤事件來推進Oracle SCN前進的方法。可是,在11.2.0.2以後的版本中,Oracle關閉了這個通道,這種方法不在有效。在高版本狀況下,咱們是能夠經過oradebug工具對SCN進行修改。
注意:這種方法比較危險,請不要在投產環境下進行測試。
一、實驗環境說明
筆者使用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
咱們先聊聊Oracle的SCN。在數據庫內部,SCN是一個單向遞增的數字編號,控制文件、數據文件、在線Redo日誌、歸檔日誌和備份集合中,都包括這個數字編號。在內部文件中,SCN是經過Base和Wrap兩個部分進行保存。Base是SCN編號的基礎位,是經過32位二進制位進行保存。一旦超過這32位長度,系統會自動在Wrap進位。也就是說,Wrap表示的超過4G個數的進位次數。
使用Oracle oradebug修改SCN,能夠在兩個場景下進行,就是Oracle啓動Open狀態和Mount狀態。下面分別進行說明。
二、Open狀態下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近似SCN的Base部分。注意: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進制。
每個取值段,用8個16進制對應,對應到數字位數是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編號。
三、Mount狀態修改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,包括base和wrap兩部分。咱們此次修改wrap從0到1。這個過程當中,咱們須要寫入base和wrap兩個部分,若是咱們只寫入了wrap部分,base部分保持0,那麼系統運行的時候,會從base爲0開始。
此時,須要查看一下當前文件裏面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。下面分別寫入base和wrap取值。
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
四、結論
使用oradebug直接修改內存SCN,是咱們在故障修復時候很是快捷的方法。不過,快捷創建在對內部機制清晰理解的前提之下。因此,不管何種場景進行修復,有備份、可恢復是咱們工做的基本前提。
Oracle系統表 smon_scn_time 的說明
SMON_SCN_TIME表存放的是SCN和Time以前的映射關係。 該表由SMON 進程負責維護。
SQL> desc smon_scn_time
Name Null? Type
------------------------------------------------- ----------------------------
THREAD NUMBER
TIME_MP NUMBER
TIME_DP DATE
SCN_WRP NUMBER
SCN_BAS NUMBER
NUM_MAPPINGS NUMBER
TIM_SCN_MAP RAW(1200)
SCN NUMBER
ORIG_THREAD NUMBER
SQL> alter session set nls_date_format='yyyy-mm-ddhh24:mi:ss';
Session altered.
SQL> select time_dp,scn from smon_scn_time where rownum<5;
TIME_DP SCN
------------------- ----------
2013-03-15 10:31:04 2092348
2013-03-15 10:35:49 2092452
2013-03-15 10:41:00 2092581
2013-03-15 10:45:46 2092682
在Oracle 11g中,該表的建立SQL在$ORACLE_HOME/rdbms/admin/dtxnspc.bsq 文件中。
create table smon_scn_time (
thread number, /* thread, compatibility */
time_mp number, /* time this recent scn represents */
time_dp date, /* time as date, compatibility */
scn_wrpnumber, /*scn.wrp, compatibility */
scn_bas number, /* scn.bas, compatibility */
num_mappings number,
tim_scn_map raw(1200),
scnnumber default 0, /* scn*/
orig_thread number default 0 /* for downgrade */
) cluster smon_scn_to_time_aux (thread)
/
create unique index smon_scn_time_tim_idxon smon_scn_time(time_mp)
tablespace SYSAUX
/
create unique index smon_scn_time_scn_idxon smon_scn_time(scn)
tablespace SYSAUX
/
咱們能夠直接delete掉SMON_SCN_TIME表中的記錄:
SQL> delete from smon_scn_time;
2120 rows deleted.
SQL> commit;
Commit complete.
SQL> select count(1) from smon_scn_time;
COUNT(1)
----------
0
根據MOS文檔的說明:
How To Map SCN To Timestamp Before 10g? [ID365536.1]
SYS.SMON_SCN_TIMEwill have a maximum of 1440 rows and each record will be for a 5 minute period.Oracle maintains this information for a maximum of 5 days after which therecords will be recycled.
This means thatdata is stored 12 times per hour * 24 hours * 5 days = 1440 rows.
在Oracle 9i版本中,SMON_SCN_TIME 表中最多存放1440條記錄。 SMON 進程每隔5分鐘生成一次SCN和TIME 以前的映射,並更新到SMON_SCN_TIME表。該表的維護週期是5天。
所以該表最多存放的記錄是:12*24*5=1440條記錄。
超過1440條的記錄在下次循環中會被刪除。
在oracle 10g之後的版本,SMON_SCN_TIME表的維護策略發生了變化。
根據MOS文檔的說明:
High Executions Of Statement "deletefrom smon_scn_time..." [ID 375401.1]
The deletestatement deletes the oldest rows from smon_scn_time to clear space for newrows. SMON wakes up every 5 minutes and checks how many on-disk mappingswe have--the max is 144000.
--SMON進程每一個5分鐘喚醒一次來更新SCN和TIME之間的映射關係,而且檢查SMON_SCN_TIME表中的記錄數,該表的記錄數最大是144000條。
The new mappingsare then added for the last period (since SMON last updated), and if this isover 144000, SMON will then issue the delete statement:
delete fromsmon_scn_time where thread=0 and time_mp = (select min(time_mp) fromsmon_scn_time where thread=0)
--SMON進程會把最新的SCN_TIME映射關係寫入SMON_SCN_TIME表,若是該表的記錄數超過144000條,那麼就會執行上面的delete操做,刪除最先的記錄。
There will be anexecution of this each time SMON wakes to update smon_scn_time, and if onedeletion does not free enough mappings, then there will be multiple executions.
--SMON進程每次被喚醒都會更新SMON_SCN_TIME表,若是一次delete操做不能釋放足夠的空間映射空間,就會執行屢次delete操做。
能夠設置12500事件中止SMON進程對SMON_SCN_TIME。
具體操做以下:
SQL> select count(1) from smon_scn_time;
COUNT(1)
----------
2115
SQL> alter system set events '12500trace name context forever, level 10';
System altered.
SQL> select sysdate from dual;
SYSDATE
-------------------
2013-03-20 13:06:15
SQL> select count(1) from smon_scn_time;
COUNT(1)
----------
2115
SQL> alter system set events '12500 tracename context off';
System altered.
SQL> select sysdate from dual;
SYSDATE
-------------------
2013-03-20 13:19:58
SQL> select count(1) from smon_scn_time;
COUNT(1)
----------
2119
LOCK ON SYS.SMON_SCN_TIME [ID 747745.1]
Oracle 9i,SYS.SMON_SCN_TIME 被 SMON 進程已排它鎖佔用,而且鎖不能釋放,致使數據庫出現性能問題,而且SMON_SCN_TIME表中有大量的記錄。
SQL> selectcount(*) from sys.smon_scn_time;
COUNT(*)
----------
137545
1 row selected.
--正常狀況下,9i最多隻能保存1440條記錄。
SQL> select object_id from dba_objectswhere object_name = 'SMON_SCN_TIME';
OBJECT_ID
----------
575
1 row selected.
SQL> select * fromv$locked_object where object_id = 575;
XIDUSNXIDSLOT XIDSQN OBJECT_ID SESSION_ID
---------- ---------- ---------- ---------- ----------
ORACLE_USERNAME OS_USER_NAME PROCESS
------------------------------ ------------------------------ ------------
LOCKED_MODE
-----------
5 5 1494 575 164
dbadmin 4444350
3 <=Locked in row exclusive mode
設置12500事件,中止SMON 進程更新SMON_SCN_TIME表,而後手工刪除表中的記錄。
SQL> alter system set events '12500 tracename context forever, level 10';
SQL> delete from smon_scn_time;
SQL> commit;
SQL> alter system set events '12500 tracename context off';
Now restart the instance.
High Executions Of Statement "deletefrom smon_scn_time..." [ID 375401.1]
AWR報告顯示smon_scn_time的刪除操做頻繁的被執行。
delete fromsmon_scn_time where thread=0 and time_mp = (select min(time_mp) fromsmon_scn_time where thread=0);
致使這種現象的緣由是SMON_SCN_TIME表和表上的索引不一致。須要重建SMON_SCN_TIME上的索引。
SQL> analyze table smon_scn_timevalidate structure cascade;
analyze table smon_scn_time validate structure cascade
*
ERROR at line 1 :
ORA-01499: table/Index Cross Reference Failure - see trace file
connect / as sysdba
drop index smon_scn_time_scn_idx;
drop index smon_scn_time_tim_idx;
create unique index smon_scn_time_scn_idx on smon_scn_time(scn);
create unique index smon_scn_time_tim_idx on smon_scn_time(time_mp);
analyze table smon_scn_time validate structure cascade;
由oradebug poke推動scn理解scn base及scn wrap系列一
原文地址:由oradebug poke推動scn理解scn base及scn wrap系列一 做者:wisdomone1
在v$transaction會看到scn,其中又分爲scn base及scn wrap,這到底怎麼回事呢?並且不少ORA報錯與SCN有關,若是多瞭解一些SCN相關的知識,也便於咱們
分析解決問題。
1,oradebug poke能夠推動SCN,分爲在數據庫OPEN及MOUNT皆能夠
oradebug setmypid
oradebug DUMPvar SGA kcsgscn_
oradebug poke 0x060012658 4 1000
2,關於kcsgscn_變量我是在BAIDU上面查的,而關於SCN究竟是對應內存是哪塊區域,我是採用屢次運行oradebug DUMPvar SGA kcsgscn_,看哪些內存的值在變化,基本就是哪塊
3,oradebug poke 0x060012658 4 1000 就是推動SCN的命令,具體含義以下:
oradebug poke 內存地址 長度 要修改的內容 ,注意這個要修改的內容必須是十進制,若是是16進制會報上述的錯(這裏我採用了反向對比思惟),且這裏長度是前4個字節
4,若是是在OPEN狀態下推動SCN,oradebug DUMPvar SGA kcsgscn_是有值的,而在MOUNT由於數據庫沒有打開,所在是空的,全是0,那麼如何調整SCN,能夠基於每一個文件頭的BLOCK 1的數據結構kscnbas及kscnwrp進行調整
這個數據結構對應select file#,name,checkpoint_change# from v$datafile;
BBED> map
File: /home/ora10g/asia/asia/users01.dbf (0)
Block: 1 Dba:0x00000000
------------------------------------------------------------
Data File Header
struct kcvfh, 676 bytes @0
ub4 tailchk @8188
BBED> p kcvfh
struct kcvfhckp, 36 bytes @484
struct kcvcpscn, 8 bytes @484
ub4 kscnbas @484 0x028f5c58 --scn base
ub2 kscnwrp @488 0x0000 --scn wrap
5,select current_scn from v$database,這個SCN是一直在變化,能夠叫做內存SCN
6,scn是由scn base及scn wrap構成的,當scn base達到必定程度,scn wrap則會遞增,通常狀況下scn wrap是0,不會變化
7,scn base及scn wrap也是數據塊中的數據結構,可見scn base是4個字節,而scn wrap是2個字節
也就是說scn base要用4個字節用完,scn wrap就會遞增
依理推理,4個字節爲 power(2,32),也就是達到這個數據時,scn base就會歸0,scn wrap遞增1
8,基於 select file#,name,checkpoint_change# from v$datafile;和數據結構的scn base及scn wrap可知scn計算公式爲
scn=scn wrap * power(2,32)+scn base
9,進一步引伸,也能夠計算出爲scn最大值,由於scn base及scn wrap是由4個字節及4個字節構成的,而這些字節表示的數據範圍是有限的
10,若是太小調整scn遠小於checkpoint_change#,會引起ora-600 2662,固然解決也很容易,基於checkpoint_change#調大scn便可
不然2662會引起數據庫強制關閉
SQL> select * from v$version where rownum=1;
BANNER
----------------------------------------------------------------
Oracle Database 10g Enterprise Edition Release 10.2.0.5.0 - 64bi
---可見事務也有scn base及scn wrap的概念
SQL> desc v$transaction;
Name Null? Type
----------------- -------- ------------
ADDR RAW(8)
XIDUSN NUMBER
XIDSLOT NUMBER
XIDSQN NUMBER
UBAFIL NUMBER
UBABLK NUMBER
UBASQN NUMBER
UBAREC NUMBER
STATUS VARCHAR2(16)
START_TIME VARCHAR2(20)
START_SCNB NUMBER --scn base
START_SCNW NUMBER --scn wrap
START_UEXT NUMBER
START_UBAFIL NUMBER
START_UBABLK NUMBER
START_UBASQN NUMBER
START_UBAREC NUMBER
SES_ADDR RAW(8)
FLAG NUMBER
SPACE VARCHAR2(3)
RECURSIVE VARCHAR2(3)
NOUNDO VARCHAR2(3)
PTX VARCHAR2(3)
NAME VARCHAR2(256
)
PRV_XIDUSN NUMBER
PRV_XIDSLT NUMBER
PRV_XIDSQN NUMBER
PTX_XIDUSN NUMBER
PTX_XIDSLT NUMBER
PTX_XIDSQN NUMBER
DSCN-B NUMBER --scn base
DSCN-W NUMBER --scn wrap
USED_UBLK NUMBER
USED_UREC NUMBER
LOG_IO NUMBER
PHY_IO NUMBER
CR_GET NUMBER
CR_CHANGE NUMBER
START_DATE DATE
DSCN_BASE NUMBER --scn base
DSCN_WRAP NUMBER --scn wrap
START_SCN NUMBER
DEPENDENT_SCN NUMBER
XID RAW(8)
PRV_XID RAW(8)
PTX_XID RAW(8)
---普通數據塊也有scn base及scn wrap的概念,且scn base爲4個字節,scn wrap爲2個字節
BBED> map
File: /home/ora10g/asia/asia/users01.dbf (0)
Block: 12 Dba:0x00000000
------------------------------------------------------------
KTB Data Block (Table/Cluster)
struct kcbh, 20 bytes @0
struct ktbbh, 72 bytes @20
struct kdbh, 14 bytes @100
struct kdbt[1], 4 bytes @114
sb2 kdbr[32] @118
ub1 freespace[7814] @182
ub1 rowdata[192] @7996
ub4 tailchk @8188
BBED> p kcbh
struct kcbh, 20 bytes @0
ub1 type_kcbh @0 0x06
ub1 frmt_kcbh @1 0xa2
ub1 spare1_kcbh @2 0x00
ub1 spare2_kcbh @3 0x00
ub4 rdba_kcbh @4 0x0100000c
ub4 bas_kcbh @8 0x00048e91 --scn base
ub2 wrp_kcbh @12 0x0000 --scn wrap
ub1 seq_kcbh @14 0x02
ub1 flg_kcbh @15 0x06 (KCBHFDLC, KCBHFCKV)
ub2 chkval_kcbh @16 0x7e45
ub2 spare3_kcbh @18 0x0000
BBED>
---數據文件頭也有scn base及scn wrap的概念
BBED> map
File: /home/ora10g/asia/asia/users01.dbf (0)
Block: 1 Dba:0x00000000
------------------------------------------------------------
Data File Header
struct kcvfh, 676 bytes @0
ub4 tailchk @8188
BBED> p kcvfh
struct kcvfh, 676 bytes @0
struct kcvfhbfh, 20 bytes @0
ub1 type_kcbh @0 0x0b
ub1 frmt_kcbh @1 0xa2
ub1 spare1_kcbh @2 0x00
ub1 spare2_kcbh @3 0x00
ub4 rdba_kcbh @4 0x01000001
ub4 bas_kcbh @8 0x00000000
ub2 wrp_kcbh @12 0x0000
從上述咱們發現基本scn wrap全是0,那麼什麼時候scn會變成非0呢,我想到了推動SCN,而後對比DUMP數據塊,能夠了其原理了
SQL> select current_scn,checkpoint_change# from v$database;
CURRENT_SCN CHECKPOINT_CHANGE#
----------- ------------------
311981 296387
SQL> alter session set events 'immediate trace name adjust_scn level 1';
Session altered.
SQL> select current_scn,checkpoint_change# from v$database;
CURRENT_SCN CHECKPOINT_CHANGE#
----------- ------------------
311996 296387
可見上述推動SCN太慢了
SQL> select 311996-311981 from dual;
311996-311981
-------------
15
---且ALERT會報權限不足的錯誤信息
Mon Nov 30 23:46:36 EST 2015
Errors in file /home/ora10g/admin/asia/udump/asia_ora_23849.trc:
ORA-01031: insufficient privileges
---上述推動SCN方法太慢,咱們嘗試另外一種快速推動SCN的方法,不過要重啓庫到MOUNT狀態
SQL> shutdown immediate
Database closed.
Database dismounted.
ORACLE instance shut down.
SQL> startup mount
ORACLE instance started.
Total System Global Area 901775360 bytes
Fixed Size 2100424 bytes
Variable Size 226493240 bytes
Database Buffers 666894336 bytes
Redo Buffers 6287360 bytes
Database mounted.
---可見MOUNT狀態下CURRENT_SCN爲0,其它SCN列皆有值
SQL> select current_scn,checkpoint_change# from v$database;
CURRENT_SCN CHECKPOINT_CHANGE#
----------- ------------------
0 312204
SQL> select file#,name,checkpoint_change# from v$datafile;
FILE# NAME CHECKPOINT_CHANGE#
---------- -------------------------------------------------- ------------------
1 /home/ora10g/asia/asia/system01.dbf 312204
2 /home/ora10g/asia/asia/undotbs01.dbf 312204
3 /home/ora10g/asia/asia/sysaux01.dbf 312204
4 /home/ora10g/asia/asia/users01.dbf 312204
SQL> select file#,checkpoint_change# from v$datafile_header;
FILE# CHECKPOINT_CHANGE#
---------- ------------------
1 312204
2 312204
3 312204
4 312204
SQL> select to_char('312204','xxxxxxx') from dual;
TO_CHAR(
--------
4c38c
---bbed查看數據文件的SCN,可知是4c38c
struct kcvfhckp, 36 bytes @484
struct kcvcpscn, 8 bytes @484
ub4 kscnbas @484 0x0004c38c
ub2 kscnwrp @488 0x0000
---用10015事件推動SCN發現沒有變化,可見在MOUNT狀態下不生效推動SCN
SQL> alter session set events '10015 trace name adjust_scn level 1';
Session altered.
SQL> select current_scn,checkpoint_change# from v$database;
CURRENT_SCN CHECKPOINT_CHANGE#
----------- ------------------
0 312204
打開數據庫看看有無生效,也是沒有效果
SQL> alter database open;
Database altered.
SQL> select current_scn,checkpoint_change# from v$database;
CURRENT_SCN CHECKPOINT_CHANGE#
----------- ------------------
312409 312207
SQL> select file#,name,checkpoint_change# from v$datafile;
FILE# NAME CHECKPOINT_CHANGE#
---------- -------------------------------------------------- ------------------
1 /home/ora10g/asia/asia/system01.dbf 312207
2 /home/ora10g/asia/asia/undotbs01.dbf 312207
3 /home/ora10g/asia/asia/sysaux01.dbf 312207
4 /home/ora10g/asia/asia/users01.dbf 312207
---換另外一種方法,用ORADEBUG POKE推動SCN
SQL> shutdown immediate
Database closed.
Database dismounted.
ORACLE instance shut down.
SQL> startup mount
ORACLE instance started.
Total System Global Area 901775360 bytes
Fixed Size 2100424 bytes
Variable Size 226493240 bytes
Database Buffers 666894336 bytes
Redo Buffers 6287360 bytes
Database mounted.
SQL> oradebug setmypid
Statement processed.
SQL> oradebug DUMPvar SGA kcsgscn_
kcslf kcsgscn_ [060012658, 060012688) = 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 60012338 00000000
SQL>
SQL> select file#,name,checkpoint_change# from v$datafile;
FILE# NAME CHECKPOINT_CHANGE#
---------- -------------------------------------------------- ------------------
1 /home/ora10g/asia/asia/system01.dbf 312714
2 /home/ora10g/asia/asia/undotbs01.dbf 312714
3 /home/ora10g/asia/asia/sysaux01.dbf 312714
4 /home/ora10g/asia/asia/users01.dbf 312714
SQL> select to_char('312714','xxxxxx') from dual;
TO_CHAR
-------
4c58a
SQL> oradebug poke 0x060012658 8 0x0004c58a
BEFORE: [060012658, 060012660) = 00000000 00000000
AFTER: [060012658, 060012660) = 0004C58A 00000000
SQL> oradebug DUMPvar SGA kcsgscn
kcslf kcsgscn_ [060012658, 060012688) = 0004C58A 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 60012338 00000000
SQL>
SQL> alter database open;
Database altered.
SQL> select file#,name,checkpoint_change# from v$datafile;
FILE# NAME CHECKPOINT_CHANGE#
---------- -------------------------------------------------- ------------------
1 /home/ora10g/asia/asia/system01.dbf 312717
2 /home/ora10g/asia/asia/undotbs01.dbf 312717
3 /home/ora10g/asia/asia/sysaux01.dbf 312717
4 /home/ora10g/asia/asia/users01.dbf 312717
好像沒起做用
SQL> select current_scn,checkpoint_change# from v$database;
CURRENT_SCN CHECKPOINT_CHANGE#
----------- ------------------
312891 312717
---換個思路,試試在數據庫打開時推動SCN
SQL> select file#,name,checkpoint_change# from v$datafile;
FILE# NAME CHECKPOINT_CHANGE#
---------- -------------------------------------------------- ------------------
1 /home/ora10g/asia/asia/system01.dbf 313429
2 /home/ora10g/asia/asia/undotbs01.dbf 313429
3 /home/ora10g/asia/asia/sysaux01.dbf 313429
4 /home/ora10g/asia/asia/users01.dbf 313429
SQL> select current_scn,checkpoint_change# from v$database;
CURRENT_SCN CHECKPOINT_CHANGE#
----------- ------------------
313917 313429
SQL> select to_char('313917','xxxxxxxxxx') from dual;
TO_CHAR('31
-----------
4ca3d
---經間隔屢次運行以下ORADEBUG命令,我分析CURRENT_SCN就是內存中的第1部分(由於就這部分信息在變化,其它信息是固定的)
SQL> oradebug setmypid
Statement processed.
SQL> oradebug DUMPvar SGA kcsgscn_
kcslf kcsgscn_ [060012658, 060012688) = 0004CAD4 00000000 00000000 00000000 00000113 00000000 00000000 00000000 00000000 00000000 60012338 00000000
SQL>
SQL>
SQL>
SQL> oradebug DUMPvar SGA kcsgscn_
kcslf kcsgscn_ [060012658, 060012688) = 0004CAD6 00000000 00000000 00000000 00000114 00000000 00000000 00000000 00000000 00000000 60012338 00000000
SQL>
SQL>
SQL> oradebug DUMPvar SGA kcsgscn_
kcslf kcsgscn_ [060012658, 060012688) = 0004CAD7 00000000 00000000 00000000 00000115 00000000 00000000 00000000 00000000 00000000 60012338 00000000
SQL>
---因此咱們只要改第1部分信息的內容便可
SQL> oradebug poke 0x060012658 4 FFFFA3523
ORA-01858: a non-numeric character was found where a numeric was expected
SQL>
可見oradeug poke 的含義是oradebug poke 內存地址 長度 要修改的內容 ,注意這個要修改的內容必須是十進制,若是是16進制會報上述的錯(這裏我採用了反向對比思惟),且這裏長度是前4個字節
SQL> oradebug poke 0x060012658 4 1000
BEFORE: [060012658, 06001265C) = 0004CB41
AFTER: [060012658, 06001265C) = 000003E8
SQL> select to_number('3E8','xxxxxxxxx') from dual;
TO_NUMBER('3E8','XXXXXXXXX')
----------------------------
1000
---並且上述因爲把SCN改得太小,小於數據文件及控制文件的SCN,會報ORA-600 的2662錯誤,處理很簡單,快速基於checkpoint_change#把SCN變大便可,不然過會數據庫就會DOWN機
SQL> select current_scn,checkpoint_change# from v$database;
select current_scn,checkpoint_change# from v$database
*
ERROR at line 1:
ORA-00600: internal error code, arguments: [2662], [0], [71], [0], [333548],
[0], [], []
---基於上述分析,由於原來SCN是313917,咱們加到19999999999
SQL> oradebug setmypid
Statement processed.
SQL> select power(2,32) from dual;
POWER(2,32)
-----------
4294967296
若是把SCN調整爲上述的值,立刻ALAERT會報錯
SQL> oradebug DUMPvar SGA kcsgscn_
kcslf kcsgscn_ [060012658, 060012688) = 000565AE 00000000 00000000 00000000 00000075 00000000 00000000 00000000 00000000 00000000 60012338 00000000
SQL> oradebug poke 0x060012658 4 4294967296
BEFORE: [060012658, 06001265C) = 000565B3
AFTER: [060012658, 06001265C) = 00000000
Tue Dec 01 01:27:33 EST 2015
Errors in file /home/ora10g/admin/asia/bdump/asia_cjq0_27711.trc:
ORA-00604: error occurred at recursive SQL level 1
ORA-08176: consistent read failure; rollback data not available
--因此可見SCN也不能隨意去調太大,ORACLE內部確定有個控制算法的,不然會把庫搞DOWN掉
SQL> oradebug poke 0x060012658 4 42949670
BEFORE: [060012658, 06001265C) = 00000003
AFTER: [060012658, 06001265C) = 028F5C26
SQL> alter system checkpoint;
System altered.
SQL> alter system checkpoint;
System altered.
SQL> select file#,name,checkpoint_change# from v$datafile;
FILE# NAME CHECKPOINT_CHANGE#
---------- -------------------------------------------------- ------------------
1 /home/ora10g/asia/asia/system01.dbf 42949720
2 /home/ora10g/asia/asia/undotbs01.dbf 42949720
3 /home/ora10g/asia/asia/sysaux01.dbf 42949720
4 /home/ora10g/asia/asia/users01.dbf 42949720
---可見SCN已經調整爲指定的SCN了
SQL> select current_scn,checkpoint_change# from v$database;
CURRENT_SCN CHECKPOINT_CHANGE#
----------- ------------------
42949724 42949720
---換個思路繼糿研究SCN BASE及SCN WRAP,若是我一直增長SCN BASE,SCN WRAP會有變化呢,我理解確定是SCN BASE大到必定程度,SCN WRAP就會有變化
BBED> map
File: /home/ora10g/asia/asia/users01.dbf (0)
Block: 1 Dba:0x00000000
------------------------------------------------------------
Data File Header
struct kcvfh, 676 bytes @0
ub4 tailchk @8188
BBED> p kcvfh
struct kcvfhckp, 36 bytes @484
struct kcvcpscn, 8 bytes @484
ub4 kscnbas @484 0x028f5c58 --scn base
ub2 kscnwrp @488 0x0000
SQL> select to_number('&x','xxxxxxxx') from dual;
Enter value for x: 28f5c58
old 1: select to_number('&x','xxxxxxxx') from dual
new 1: select to_number('28f5c58','xxxxxxxx') from dual
TO_NUMBER('28F5C58','XXXXXXXX')
-------------------------------
42949720
BBED> set offset 484
OFFSET 484
BBED> dump count 5
File: /home/ora10g/asia/asia/users01.dbf (0)
Block: 1 Offsets: 484 to 488 Dba:0x00000000
------------------------------------------------------------------------
585c8f02 00
<32 bytes="" per="" line="">
SQL> select power(2,31) from dual;
POWER(2,31)
-----------
2147483648
SQL> select to_char('2147483648','xxxxxxxxx') from dual;
TO_CHAR('2
----------
80000000
BBED> modify /x 00000080
Warning: contents of previous BIFILE will be lost. Proceed? (Y/N) Y
File: /home/ora10g/asia/asia/users01.dbf (0)
Block: 1 Offsets: 484 to 488 Dba:0x00000000
------------------------------------------------------------------------
00000080 00
<32 bytes="" per="" line="">
--還要調整tailchk
能夠看到tailchk校驗由ub4 bas_kcbh的低4位+ub1 type_kcbh+ub1 seq_kcbh
BBED> p tailchk
ub4 tailchk @8188 0x00000b01
ub4 bas_kcbh @8 0x00000000
ub1 type_kcbh @0 0x0b
ub1 seq_kcbh @14 0x01
BBED> sum apply
Check value for File 0, Block 1:
current = 0x2dac, required = 0x2dac
---調整後
struct kcvfhckp, 36 bytes @484
struct kcvcpscn, 8 bytes @484
ub4 kscnbas @484 0x80000000
ub2 kscnwrp @488 0x0000
BBED> p tailchk
ub4 tailchk @8188 0x00000b01
SQL> conn scott/system
Connected.
SQL> create table t_modafter(a int);
Table created.
SQL> insert into t_modafter values(1);
1 row created.
SQL> commit;
Commit complete.
SQL> conn /as sysdba
Connected.
SQL> alter system checkpoint;
System altered.
SQL> alter system flush buffer_cache;
System altered.
---調整scn base到最大值-1
SQL> select power(2,32)-1 from dual;
POWER(2,32)-1
-------------
4294967295
SQL> select to_char('4294967295','xxxxxxxxxx') from dual;
TO_CHAR('42
-----------
ffffffff
---報錯能夠分2步進行,即先2個字節進行,而後再把餘下的2個字節修改完
BBED> modify /x ffffffff
BBED-00209: invalid number (ffffffff)
BBED> modify /x ffff
Warning: contents of previous BIFILE will be lost. Proceed? (Y/N) Y
File: /home/ora10g/asia/asia/users01.dbf (0)
Block: 1 Offsets: 484 to 488 Dba:0x00000000
------------------------------------------------------------------------
ffff0080 00
<32 bytes="" per="" line="">
BBED> set offset 486
OFFSET 486
BBED> dump
File: /home/ora10g/asia/asia/users01.dbf (0)
Block: 1 Offsets: 486 to 488 Dba:0x00000000
------------------------------------------------------------------------
008000
<32 bytes="" per="" line="">
BBED> modify /x ffff
File: /home/ora10g/asia/asia/users01.dbf (0)
Block: 1 Offsets: 486 to 488 Dba:0x00000000
------------------------------------------------------------------------
ffff00
<32 bytes="" per="" line="">
BBED> dump
File: /home/ora10g/asia/asia/users01.dbf (0)
Block: 1 Offsets: 484 to 486 Dba:0x00000000
------------------------------------------------------------------------
ffffff
<32 bytes="" per="" line="">
BBED> p kcvfh
struct kcvfhckp, 36 bytes @484
struct kcvcpscn, 8 bytes @484
ub4 kscnbas @484 0xffffffff scn_base已經調整爲 power(2,32)-1 ,其中32表明4個字節,每一個字節byte即8bit,因此就是32個bit,能夠表示的數據即power(2,32)
ub2 kscnwrp @488 0x0000
SQL> alter system flush buffer_cache;
System altered.
SQL> alter system checkpoint;
System altered.
BBED> p kcvfh
struct kcvfhckp, 36 bytes @484
struct kcvcpscn, 8 bytes @484
ub4 kscnbas @484 0x00000002
ub2 kscnwrp @488 0x0001 ---看到沒,SCN WRAP有值了,哈哈說明,SCN BASE大到必定程度,它就有值了
SQL> select file#,name,checkpoint_change# from v$datafile;
FILE# NAME CHECKPOINT_CHANGE#
---------- -------------------------------------------------- ------------------
1 /home/ora10g/asia/asia/system01.dbf 4294967298
2 /home/ora10g/asia/asia/undotbs01.dbf 4294967298
3 /home/ora10g/asia/asia/sysaux01.dbf 4294967298
4 /home/ora10g/asia/asia/users01.dbf 4294967298
可見scn=scn wrap * power(2,32)+scn base
SQL> select 1*4294967296+2 from dual;
1*4294967296+2
--------------
4294967298
也就是說scn wrap有值時,scn又開始從0開始計數,因而可知ORACLE設計的精妙所在,再深刻一些,也能夠知道SCN最大值是什麼,哈哈
SMON後臺進程的做用還包括維護SMON_SCN_TIME基表。
SMON_SCN_TIME基表用於記錄過去時間段中SCN(system change number)與具體的時間戳(timestamp)之間的映射關係,由於是採樣記錄這種映射關係,因此SMON_SCN_TIME能夠較爲較爲粗糙地(不精確地)定位某個SCN的時間信息。實際的SMON_SCN_TIME是一張cluster table簇表。
SMON_SCN_TIME時間映射表最大的用途是爲閃回類型的查詢(flashback type queries)提供一種將時間映射爲SCN的途徑(The SMON time mapping is mainly for flashback type queries to map a time to an SCN)。
Metalink文檔介紹了SMON更新SMON_SCN_TIME的規律:
另外從10g開始SMON也會清理SMON_SCN_TIME中的記錄了,SMON後臺進程會每5分鐘被喚醒一次,檢查SMON_SCN_TIME在磁盤上的映射記錄總數,若總數超過144000條,則會使用如下語句刪除最老的一條記錄(time_mp最小):
delete from smon_scn_time where thread = 0 and time_mp = (select min(time_mp) from smon_scn_time where thread = 0)
若僅僅刪除一條記錄不足以得到足夠的空間,那麼SMON會反覆屢次執行以上DELETE語句。
觸發場景
雖然Metalink文檔指出了在10g中SMON會以每6秒一次的頻率更新SMON_SCN_TIME基表,可是實際觀測能夠發現更新頻率與SCN的增加速率相關,在較爲繁忙的實例中SCN的上升極快時SMON可能會以6秒一次的最短間隔頻率更新 , 可是在空閒的實例中SCN增加較慢,則仍會以每5或10分鐘一次頻率更新,例如:
[oracle@vrh8 ~]$ ps -ef|grep smon|grep -v grep oracle 3484 1 0 Nov12 ? 00:00:02 ora_smon_G10R21 SQL> select * from v$version; BANNER ---------------------------------------------------------------- Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - 64bi PL/SQL Release 10.2.0.1.0 - Production CORE 10.2.0.1.0 Production TNS for Linux: Version 10.2.0.1.0 - Production NLSRTL Version 10.2.0.1.0 - Production SQL> select * from global_name; GLOBAL_NAME -------------------------------------------------------------------------------- www.askmaclean.com & www.askmaclean.com SQL> oradebug setospid 3484; Oracle pid: 8, Unix process pid: 3484, image: oracle@vrh8.oracle.com (SMON) SQL> oradebug event 10500 trace name context forever,level 10 : 10046 trace name context forever,level 12; Statement processed. SQL> SQL> oradebug tracefile_name; /s01/admin/G10R21/bdump/g10r21_smon_3484.trc /* 等待必定時間 */
找出SMON trace文件中insert數據到SMON_SCN_TIME的記錄:
grep -A20 "insert into smon_scn_time" /s01/admin/G10R21/bdump/g10r21_smon_3484.trc insert into smon_scn_time (thread, time_mp, time_dp, scn, scn_wrp, scn_bas, num_mappings, tim_scn_map) values (0, :1, :2, :3, :4, :5, :6, :7) END OF STMT PARSE #4:c=0,e=43,p=0,cr=0,cu=0,mis=0,r=0,dep=1,og=4,tim=1290280848899596 BINDS #4: kkscoacd Bind#0 oacdty=02 mxl=22(22) mxlc=00 mal=00 scl=00 pre=00 oacflg=00 fl2=0001 frm=00 csi=00 siz=24 off=0 kxsbbbfp=7fb29844edb8 bln=22 avl=06 flg=05 value=767145793 Bind#1 oacdty=12 mxl=07(07) mxlc=00 mal=00 scl=00 pre=00 oacflg=10 fl2=0001 frm=00 csi=00 siz=8 off=0 kxsbbbfp=7fff023ae780 bln=07 avl=07 flg=09 value="11/14/2011 0:3:13" Bind#2 oacdty=02 mxl=22(04) mxlc=00 mal=00 scl=00 pre=00 oacflg=10 fl2=0001 frm=00 csi=00 siz=24 off=0 kxsbbbfp=7fff023ae70c bln=22 avl=04 flg=09 value=954389 Bind#3 -- insert into smon_scn_time (thread, time_mp, time_dp, scn, scn_wrp, scn_bas, num_mappings, tim_scn_map) values (0, :1, :2, :3, :4, :5, :6, :7) END OF STMT PARSE #1:c=0,e=21,p=0,cr=0,cu=0,mis=0,r=0,dep=1,og=4,tim=1290281434933390 BINDS #1: kkscoacd Bind#0 oacdty=02 mxl=22(22) mxlc=00 mal=00 scl=00 pre=00 oacflg=00 fl2=0001 frm=00 csi=00 siz=24 off=0 kxsbbbfp=7fb29844edb8 bln=22 avl=06 flg=05 value=767146393 Bind#1 oacdty=12 mxl=07(07) mxlc=00 mal=00 scl=00 pre=00 oacflg=10 fl2=0001 frm=00 csi=00 siz=8 off=0 kxsbbbfp=7fff023ae780 bln=07 avl=07 flg=09 value="11/14/2011 0:13:13" Bind#2 oacdty=02 mxl=22(04) mxlc=00 mal=00 scl=00 pre=00 oacflg=10 fl2=0001 frm=00 csi=00 siz=24 off=0 kxsbbbfp=7fff023ae70c bln=22 avl=04 flg=09 value=954720 Bind#3 -- insert into smon_scn_time (thread, time_mp, time_dp, scn, scn_wrp, scn_bas, num_mappings, tim_scn_map) values (0, :1, :2, :3, :4, :5, :6, :7) END OF STMT PARSE #3:c=0,e=20,p=0,cr=0,cu=0,mis=0,r=0,dep=1,og=4,tim=1290281727955249 BINDS #3: kkscoacd Bind#0 oacdty=02 mxl=22(22) mxlc=00 mal=00 scl=00 pre=00 oacflg=00 fl2=0001 frm=00 csi=00 siz=24 off=0 kxsbbbfp=7fb29844e960 bln=22 avl=06 flg=05 value=767146993 Bind#1 oacdty=12 mxl=07(07) mxlc=00 mal=00 scl=00 pre=00 oacflg=10 fl2=0001 frm=00 csi=00 siz=8 off=0 kxsbbbfp=7fff023ae780 bln=07 avl=07 flg=09 value="11/14/2011 0:23:13" Bind#2 oacdty=02 mxl=22(04) mxlc=00 mal=00 scl=00 pre=00 oacflg=10 fl2=0001 frm=00 csi=00 siz=24 off=0 kxsbbbfp=7fff023ae70c bln=22 avl=04 flg=09 value=954926 Bind#3 insert into smon_scn_time (thread, time_mp, time_dp, scn, scn_wrp, scn_bas, num_mappings, tim_scn_map) values (0, :1, :2, :3, :4, :5, :6, :7) END OF STMT PARSE #4:c=0,e=30,p=0,cr=0,cu=0,mis=0,r=0,dep=1,og=4,tim=1290282313990553 BINDS #4: kkscoacd Bind#0 oacdty=02 mxl=22(22) mxlc=00 mal=00 scl=00 pre=00 oacflg=00 fl2=0001 frm=00 csi=00 siz=24 off=0 kxsbbbfp=7fb29844edb8 bln=22 avl=06 flg=05 value=767147294 Bind#1 oacdty=12 mxl=07(07) mxlc=00 mal=00 scl=00 pre=00 oacflg=10 fl2=0001 frm=00 csi=00 siz=8 off=0 kxsbbbfp=7fff023ae780 bln=07 avl=07 flg=09 value="11/14/2011 0:28:14" Bind#2 oacdty=02 mxl=22(04) mxlc=00 mal=00 scl=00 pre=00 oacflg=10 fl2=0001 frm=00 csi=00 siz=24 off=0 kxsbbbfp=7fff023ae70c bln=22 avl=04 flg=09 value=955036 Bind#3
能夠經過以上INSERT語句的TIME_DP綁定變量值中發現其更新SMON_SCN_TIME的時間規律,通常爲5或10分鐘一次。這說明SMON_SCN_TIME的更細頻率與數據庫實例的負載有關,其最短的間隔是每6秒一次,最長的間隔爲10分鐘一次。
因爲SMON_SCN_TIME的更新頻率問題可能引發ORA-01466錯誤,詳見:
Error ORA-01466 while executing a flashback query. [ID 281510.1]
因爲SMON_SCN_TIME的數據不一致可能引發ORA-00600[6711]或頻繁地執行」delete from smon_scn_time」刪除語句,詳見:
ORA-00600[6711]錯誤一例
High Executions Of Statement 「delete from smon_scn_time…」 [ID 375401.1]
SMON維護SMON_SCN_TIME時相關的Stack CALL,ktf_scn_time是更新SMON_SCN_TIME的主要函數:
ksedst ksedmp ssexhd kghlkremf kghalo kghgex kghalf kksLoadChild kxsGetRuntimeLock kksfbc kkspsc0 kksParseCursor opiosq0 opiall0 opikpr opiodr rpidrus skgmstack rpidru rpiswu2 kprball ktf_scn_time ktmmon ktmSmonMain ksbrdp opirip opidrv sou2o opimai_real main main_opd_entry
SMON 還可能使用如下SQL語句維護SMON_SCN_TIME字典基表:
select smontabv.cnt, smontab.time_mp, smontab.scn, smontab.num_mappings, smontab.tim_scn_map, smontab.orig_thread from smon_scn_time smontab, (select max(scn) scnmax, count(*) + sum(NVL2(TIM_SCN_MAP, NUM_MAPPINGS, 0)) cnt from smon_scn_time where thread = 0) smontabv where smontab.scn = smontabv.scnmax and thread = 0 insert into smon_scn_time (thread, time_mp, time_dp, scn, scn_wrp, scn_bas, num_mappings, tim_scn_map) values (0, :1, :2, :3, :4, :5, :6, :7) update smon_scn_time set orig_thread = 0, time_mp = :1, time_dp = :2, scn = :3, scn_wrp = :4, scn_bas = :5, num_mappings = :6, tim_scn_map = :7 where thread = 0 and scn = (select min(scn) from smon_scn_time where thread = 0) delete from smon_scn_time where thread = 0 and scn = (select min(scn) from smon_scn_time where thread = 0)
如何禁止SMON更新SMON_SCN_TIME基表
能夠經過設置診斷事件event=’12500 trace name context forever, level 10’來禁止SMON更新SMON_SCN_TIME基表(Setting the 12500 event at system level should stop SMON from updating the SMON_SCN_TIME table.):
SQL> alter system set events '12500 trace name context forever, level 10'; System altered.
通常咱們不推薦禁止SMON更新SMON_SCN_TIME基表,由於這樣會影響flashback Query閃回查詢的正常使用,可是在某些異常恢復的場景中SMON_SCN_TIME數據訛誤可能致使實例的Crash,那麼能夠利用以上12500事件作到不觸發SMON_SCN_TIME被更新。
如何手動清除SMON_SCN_TIME的數據
由於SMON_SCN_TIME不是bootstrap自舉核心對象,因此咱們能夠手動更新該表上的數據、及重建其索引。
如我在中介紹了由於SMON_SCN_TIME與其索引的數據不一致時,能夠經過重建索引來解決問題:
connect / as sysdba drop index smon_scn_time_scn_idx; drop index smon_scn_time_tim_idx; create unique index smon_scn_time_scn_idx on smon_scn_time(scn); create unique index smon_scn_time_tim_idx on smon_scn_time(time_mp); analyze table smon_scn_time validate structure cascade;
能夠在設置了12500事件後手動刪除SMON_SCN_TIME上的記錄,重啓實例後SMON會繼續正常更新SMON_SCN_TIME。除非是由於SMON_SCN_TIME表上的記錄與索引smon_scn_time_tim_idx或smon_scn_time_scn_idx上的不一致形成DELETE語句沒法有效刪除該表上的記錄:文檔說明了該問題,不然咱們沒有必要手動去清除SMON_SCN_TIME上的數據。
具體方法以下:
SQL> conn / as sysdba /* Set the event at system level */ SQL> alter system set events '12500 trace name context forever, level 10'; /* Delete the records from SMON_SCN_TIME */ SQL> delete from smon_scn_time; SQL> commit; SQL> alter system set events '12500 trace name context off'; 完成以上步驟後重啓實例restart instance shutdown immediate; startup;
原創 2017-11-23 周玉其
SCN能夠說是Oracle中一個很基礎的部分,但同時它也是一個很重要的。它是系統中維持數據的一致性和順序恢復的重要標誌,是數據庫很是重要的一種數據結構。
SCN介紹
請點擊此處輸入圖片描述
SCN即系統改變號(System Change Number),是在某個時間點定義數據庫已提交版本的時間戳標記。 Oracle爲每一個已提交的事務分配一個惟一的SCN。 SCN的值是對數據庫進行更改的邏輯時間點。 Oracle使用此編號記錄對數據庫所作的更改。在數據庫中,SCN也能夠說是無處不在,數據文件頭,控制文件,數據塊頭,日誌文件等等都標記着SCN。也正是這樣,數據庫的一致性維護和SCN密切相關。無論是數據的備份,恢復都是離不開SCN的。
SCN是一個6字節(48bit)的數字,其值爲281,474,976,710,656(2^48),分爲2個部分:
SCN_BASE是一個4字節(32bit)的數字
SCN_WRAP是一個2字節(16bit)的數字
每當SCN_BASE達到其最大值(2^32 = 4294967296)時,SCN_WRAP增長1,SCN_BASE將被重置爲0,一直持續到SCN_WRAP達到其最大值,即2^16 = 65536。
SCN =(SCN_WRAP * 4294967296)+ SCN_BASE
SCN隨着每一個事務的完成而增長。提交不會寫入數據文件,也不更新控制文件。當發生checkpoint時,控制文件更新,SCN被寫入到控制文件。
當前的SCN能夠經過如下查詢得到:
select dbms_flashback.get_system_change_number scn from dual;
select current_scn from v$database;
四種重要的SCN
請點擊此處輸入圖片描述
在理解這幾種SCN以前,咱們先看下oracle事務中的數據變化是如何寫入數據文件的:
第一步:事務開始;
第二步:在buffer cache中找到須要的數據塊,若是沒找到,從數據文件中載入buffer cache中;
第三步:事務修改buffer cache的數據塊,該數據被標識爲「髒數據」,並被寫入log buffer中;
第四步:事務提交,LGWR進程將log buffer中的「髒數據」的日誌條目寫入redo log file中;
第五步:當發生checkpoint,CKPT進程更新全部數據文件的文件頭中的信息,DBWn進程則負責將Buffer Cache中的髒數據寫入到數據文件中。
通過上述5個步驟,事務中的數據變化最終被寫入到數據文件中。可是,一旦在上述中間環節數據庫意外宕機了,在從新啓動時如何知道哪些數據已經寫入數據文件、哪些沒有寫呢?(一樣,在DG、streams中也存在相似疑問:redolog中哪些是上一次同步已經複製過的數據、哪些沒有)
SCN機制就能比較完善的解決上述問題。 SCN是一個數字,確切的說是一個只會增長、不會減小的數字。正是它這種只會增長的特性確保了 Oracle知道哪些應該被恢復、哪些應該被複制。
總共有4種SCN:
系統檢查點(System Checkpoint)SCN
數據文件檢查點(Datafile Checkpoint)SCN
結束SCN(Stop SCN)
開始SCN(Start SCN)
(1)System Checkpoint SCN
當checkpoint完成後,ORACLE將System Checkpoint SCN號存放在控制文件中。咱們能夠經過下面SQL語句查詢:
select checkpoint_change# from v$database;
(2)Datafile Checkpoint SCN
當checkpoint完成後,Oracle將Datafile Checkpoint SCN存放在控制文件中。咱們能夠經過下面SQL語句查詢全部數據文件的Datafile Checkpoinnt SCN。
select name,checkpoint_change# from v$datafile;
(3)Start SCN
Oracle將StartSCN存放在數據文件頭中。這個SCN用於檢查數據庫啓動過程是否須要作media recovery。咱們能夠經過如下SQL語句查詢:
select name,checkpoint_change# from v$datafile_header;
(4)Stop SCN
ORACLE將StopSCN存放在控制文件中。這個SCN號用於檢查數據庫啓動過程是否須要作instance recovery。咱們能夠經過如下SQL語句查詢:
select name,last_change# from v$datafile;
在數據庫正常運行的狀況下,對可讀寫的online數據文件,該SCN號爲NULL。
SCN與數據庫啓動:
在數據庫啓動過程當中,當System Checkpoint SCN、Datafile Checkpoint SCN和Start SCN都相同時,數據庫能夠正常啓動,不須要作media recovery。三者當中有一個不一樣時,則須要作media recovery.若是在啓動的過程當中,End SCN爲NULL,則須要作instance recovery。Oracle在啓動過程當中首先檢查是否須要media recovery,而後再檢查是否須要instance recovery。
SCN與數據庫關閉:
若是數據庫的正常關閉的話,將會觸發一個checkpoint,同時將數據文件的END SCN設置爲相應數據文件的Start SCN。當數據庫啓動時,發現它們是一致的,則不須要作instance recovery。在數據庫正常啓動後,ORACLE會將END SCN設置爲NULL.若是數據庫異常關閉的話,則END SCN將爲NULL。
Q&A
Q
爲何ORACLE在控制文件中記錄System checkpoint SCN 號的同時,還須要爲每一個數據文件記錄DatafileCheckpoint SCN?
A
若是有表空間read only,那麼該表空間的全部datafile的start SCN和stop SCN將被凍結,這個時候就跟System Checkpoint SCN不一致,但在庫open的時候是不須要作media recovery的,若是沒有DatafileCheckpoint SCN就沒法判斷這些datafile是不是最新的。
可能遇到的SCN問題
請點擊此處輸入圖片描述
首選咱們看幾個跟SCN有關的概念:
Reasonable SCNLimit(RSL)
RSL = (當前時間 - 1988年1月1日)*24*3600*SCN每秒最大可能增加速率
也就是從1988年1月1日開始,假如SCN按最大速率增加,當天理論上的最大值。
最大增加速率:在11.2.0.2以前是16384,在11.2.0.2及以後版本是32768
在11.2.0.2版本以後由_max_reasonable_scn_rate參數控制
請點擊此處輸入圖片描述
該參數不建議修改。
SCN Headroom
Headroom(天) = (Reasonable SCN Limit -CurrentSCN)/ SCN每秒最大可能增加速率/3600/24
也就是若是SCN按最大速率增加,達到當前理論最大值須要的天數。這個值能夠用來判斷SCN增加速率是否過快。
那麼,SCN Headroom若是獲取呢?
參考MOS: Bug 13498243 -"scnhealthcheck.sql" script (文檔 ID 13498243.8),打上該BUG的patch以後,將在$ORACLE_HOME/rdbms/admin中增長scnhealthcheck.sql文件,該文件就是用來檢查SCN是否正常。
另外還有一篇MOS文檔,專門對該腳本的輸出作了解釋。即Installing, Executing and Interpreting output from the"scnhealthcheck.sql" script (文檔 ID 1393363.1)。
執行該腳本,結果以下:
請點擊此處輸入圖片描述
這個結果咱們仍然沒法獲得該數據庫的具體SCN Headroom,下面這個SQL是從scnhealthcheck.sql中找到的,能夠直接查到SCN Headroom的值(indicator字段)。
請點擊此處輸入圖片描述
Q&A
Q
針對上面的查詢結果,是否是意味着過1647天以後,SCN就將達到最大值?
A
不會,由於1647天以後,Current SCN會變大,Reasonable SCN Limit一樣也會變大,正常狀況下,SCNHeadroon只會變大不會變小。
SCN headroom太小的問題
若是SCN正常增加,達到最大值大約能夠用500年,SCN headroom的值也會隨着時間的推移慢慢變大,可是可能因爲BUG、用特殊手段人爲調整、dblink傳播致使SCN增加出現異常。但若是出現SCN headroom太小,alert log會出現警告:Warning: The SCN headroom for this database is only NN days!
緣由定位:
1. 經過下面這篇文檔裏提供的腳本,該腳本相似於建立AWR,能夠按snap_id對dba_hist_sysstat裏的某個stat_name作統計,咱們這裏的Stat_name選擇calls to kcmgas。
How to Extract the Historical Values of aStatistic from the AWR Repository (文檔 ID 948272.1)
2. 經過查詢V$ARCHIVED_LOG單位時間內scn變化
3. 經過上面兩個方式得出的結果分析,若是是非持續突發增加,認爲極可能是經過dblink引發;
4. 同時比較awr報告中「callsto kcmgas」 和「user commits」,若是user commits也是高速增加,極可能是自身引發;
kcmgas是Oracle分配scn的函數,在一個空庫上作測試,能夠看出每分配一次scn,calls to kcmgas的統計增長1,因此calls to kcmgas的量能夠做爲scn的增加量來分析。
請點擊此處輸入圖片描述
ORA-19706: Invalid SCN錯誤
[1376995.1]裏的介紹,在2012年1月CPU或PSU裏增長_external_scn_rejection_threshold_hours參數,11.2.0.2及之後的版本,默認爲1天即24小時,其餘版本默認爲31天即744小時,至關於把拒絕外部SCN鏈接的閾值調大了,於是更加容易引起ORA-19706錯誤。該參數對數據庫自身產生的SCN遞增沒有影響。Bug 13554409 - Fix for bug13554409 [ID 13554409.8]的裏對該問題也有介紹。
ORA-19706錯誤:最多見的就是拒絕dblink鏈接的時候,如A庫跟B庫經過dblink鏈接,A的SCN有經過人爲調整增大許多,鏈接B庫的時候,Oracle會判斷該SCN傳播過來以後,若是會致使SCN headroom小於_external_scn_rejection_threshold_hours設置的閾值,則拒絕鏈接
相關參考:SCN、ORA-19706錯誤和_external_scn_rejection_threshold_hours參數
若是打完2012年1月CPU或PSU後遇到ORA-19706錯誤,對於如下這些版本的數據庫:
Oracle 10.2.0.5
Oracle 11.1.0.7
Oracle 11.2.0.2
Oracle 11.2.0.3
oracle建議給數據庫安裝2012年4月發佈的PSU,並在安裝該PSU的基礎上,安裝補丁13916709。若是是集羣架構,同時給集羣軟件最新安裝PSU。參數_external_scn_rejection_threshold_hours在2012年4月(包含2012年4月)之後發佈的PSU/CPU中,11.2.0.2及之後的版本,是1天即24小時,其餘版本是31天即744小時。其餘版本:先升級到高版本,再按照上面的方法處理。
總結
若是發現SCN有異常,須要及時經過上述方法來打上最新的PSU,同時儘可能少用DBLINK,從系統設計角度來說也是不推薦這種系統間強耦合的設計。
2016-10-28 熊軍
Oracle數據庫在安裝了2012年1月發佈的CPU或PSU補丁以後,常常出現下面一些現象:
一、應用出現ORA-19706: invalid SCN錯誤。
二、在alert日誌中出現相似以下警告:
請點擊此處輸入圖片描述
三、在alert日誌中出現相似以下錯誤:
請點擊此處輸入圖片描述
四、在alert日誌中出現相似以下信息:
請點擊此處輸入圖片描述
五、在MOS文檔《ORA-19706 and Related Alert Log Messages [ID 1393360.1]》中還提到其餘會出如今alert中的一些警告信息:
請點擊此處輸入圖片描述
若是說以上的現象只是警告或應用級報錯,影響範圍有限,那麼不幸的是若是遇到RECO進程在恢復分佈式事務時遇到SCN問題,則可能使數據庫宕掉,例如:
請點擊此處輸入圖片描述
那麼2012年1月發佈的CPU或PSU補丁到底使數據庫在SCN處理方面產生了什麼樣的變化?這種變化對數據庫有什麼危害嗎?甚至於說,以上提示的信息是因爲這個補丁的BUG引發的嗎?
要回答這些問題,得先從SCN講起。SCN能夠說是Oracle中的很基礎,但同時也是很重要的東西,它是一個單向增加的「時鐘」,普遍應用於數據庫的恢復、事務ACID、一致性讀還有分佈式事務中。那麼除了這些,SCN還有如下一些知識點:
SCN的內部存儲方式:在Oracle內部,SCN分爲兩部分存儲,分別稱之爲scn wrap和scn base。實際上SCN長度爲48位,即它其實就是一個48位的整數。只不過多是因爲在早些年一般只能處理32位甚至是16位的數據,因此人爲地分紅了低32位(scn base)和高16位(scn wrap)。爲何不設計成64位,這個或許是以爲48位已經足夠長了而且爲了節省兩個字節的空間:)。那麼SCN這個48位長的整數,最大就是2^48(2的48次方, 281萬億,281474976710656),很大的一個數字了。
Maximum Reasonable SCN:在當前時間點,SCN最大容許達到(或者說最大可能)的SCN值。也稱爲Reasonable SCN Limit,簡稱RSL。這個值是一個限制,避免數據庫的SCN無限制地增大,甚至達到了SCN的最大值。這個值大約是這樣一個公式計算出來的:(當前時間-1988年1月1日)*24*3600*SCN每秒最大可能增加速率。當前時間減1988年1月1日的結果是天數,24表示1天24小時,3600表示1小時3600秒。不過這個公式裏面「當前時間-1988年1月」部分並非兩個時間直接相減,而是按每個月31天進行計算的(或許是爲了計算簡單,所以在Oracle內部可能要頻繁地計算,這個計算方法能夠在安裝了13498243這個補丁後獲得的scnhealthcheck.sql文件中看到,《Installing, Executing and Interpreting output from the "scnhealthcheck.sql" script [ID 1393363.1]》這篇MOS文檔解釋了這個腳本的使用及對結果的解釋,實際上直接看腳本代碼更爲清楚)。那麼SCN最秒最大可能增加速率是多少呢,這個跟Oracle版本有必定的關係,在11.2.0.2以前是16384(即16K),在11.2.0.2及以後版本是32768(即32K)。在11.2.0.2的版本中有一個隱含參數,_max_reasonable_scn_rate,其默認值就是32768(不建議調整這個值)。若是按16K的最大值,SCN要增加到最大,要超過500年。
SCN Headroom:這個是指Maximum Reasonable SCN與當前數據庫SCN的差值。在alert中一般是以「天」爲單位,這個只是爲了容易讓人讀而已。天數=(Maximum Reasonable SCN-Current SCN)/16384/3600/24。這個值就的意思就是,若是按SCN的每大增加速率,多少天會到達Maximum Reasonable SCN。但實際上即便如此,也不會到達Maximum Reasonable SCN,由於到那時Maximum Reasonable SCN也增大了(越時間增大),要到達Maximum Reasonable SCN,得必須以SCN最大可能速率的2倍才行。
SCN的異常增加:一般來講,每秒最大容許的16K/32K增加速率已經足夠了,可是不排除因爲BUG,或者人爲調整致使SCN異常增加過大。特別是後者,好比數據庫經過特殊手段強制打開,手工把SCN遞增得很大。同時Oracle的SCN會經過db link進行傳播。若是A庫經過db link鏈接到B庫,若是A庫的SCN高於B庫的SCN,那麼B庫就會遞增SCN到跟A庫同樣,反之若是A庫的SCN低於B庫的SCN,那麼A庫的SCN會遞增到跟B庫的SCN同樣。也就是說,涉及到db link進行操做的多個庫,它們會將SCN同步到這些庫中的最大的SCN。
那麼,若是是數據庫自己操做而不是經過db link同步使得SCN的增加,其增加速率如何判斷呢,這個能夠經過系統的統計量「calls to kcmgas」和"DEBUG calls to kcmgas"來獲得。kcmgas的意思是get and advance SCN,即獲取並遞增SCN。
在兩個庫經過dblink進行分佈式事務時,假設B庫的SCN值要高於A庫的SCN,所以要將B庫的SCN增同步到A庫,可是若是B庫的SCN太高,這樣同步到A庫以後,使得A庫面臨Headroom太小的風險,那麼A庫會拒絕同步SCN,這個時候就會報ORA-19706: Invalid SCN錯誤。分佈式事務,或者說是經過db link的操做就會失敗,即便是經過db link的查詢操做。這裏顯然有一個閾值,若是遞增SCN使得Headroom太小到什麼值時,就會拒絕遞增(同步)SCN?目前來看是這樣:若是打了2012年1月CPU或PSU補丁,11.2.0.2及之後的版本,是1天即24小時,其餘版本是31天即744小時,打了補丁以後能夠由隱含參數_external_scn_rejection_threshold_hours來調整。而沒有打補丁的狀況下,視同此參數設爲0,實際最小爲1小時。因爲Oracle 9.2.0.8沒有了最新的補丁集,顯示也不會有這個參數,保持默認爲1小時。注意這是一個靜態參數。因此打了2012年1月CPU或PSU補丁的一個重要變化是增長了_external_scn_rejection_threshold_hours參數,同時使11.2.0.2如下版本的數據庫其Headroom的閾值增得較大。這帶來的影響就是ORA-19706的錯誤出現的機率更高。解決的辦法將_external_scn_rejection_threshold_hours這個隱含參數設置爲較小的值,推薦的值是24,即1天。從_external_scn_rejection_threshold_hours這個參數名的字面意思結合它的做用,能夠說這個參數就是」拒絕外部SCN「的閾值。對於數據庫自身產生的SCN遞增是沒有影響的。
雖然11.2.0.2及以後的版本,其默認的每秒最大可能SCN增加速率爲32K,這使得Maximum Reasonable SCN更大,也就是說其SCN能夠增加到更大的值。那也就是可能會使11.2.0.2的庫與低版本的數據庫之間不能進行dblink鏈接。或者是11.2.0.2的庫不能與16K速率的(好比調整了_max_reasonable_scn_rate參數值)的11.2.0.2的庫進行dblink鏈接。
如今是時候來回答如下幾個問題了:
2012年1月後發佈的CPU或PSU補丁到底使數據庫在SCN處理方面產生了什麼樣的變化?
增長了_external_scn_rejection_threshold_hours參數,11.2.0.2及以上版本的這個參數默認值是24,其餘版本默認值是744。這樣使11.2.0.2如下版本的數據庫其Headroom的閾值增得較大。
這種變化對數據庫有什麼危害嗎?
在一個具備不少系統的大型企業環境裏面,db link使用不少,甚至有一些不容易管控到的數據庫也在跟關鍵系統經過 db link進行鏈接,在這樣的環境中,太高的SCN擴散到關鍵系統,而系統若是打了這個補丁,其Headroom閾值變大,那麼就更容易出現ORA-19706錯誤,對db link依賴很嚴重的系統可能會致使業務系統問題,嚴重狀況下甚至會宕庫。不過經過設置隱含參數_external_scn_rejection_threshold_hours可解決這樣的問題。因此,若是你安裝了2012年1月的CPU或PSU補丁,請儘快設置此參數爲建議的值24,極端狀況下你能夠設置爲1。。
alert中的那些提示或警告信息是BUG引發的嗎?
這些提示或警告不是BUG引發的。它只是提醒你注意SCN太高增加,或者是你的Headroom較小(在Headroom小於62天時可能會提醒),引發你的重視。實際上根據MOS文檔《System Change Number (SCN), Headroom, Security and Patch Information[ID 1376995.1]》的說法,這個補丁修復了SCN相關的一些BUG。若是非要說BUG,能夠勉強認爲補丁安裝後新增的參數_external_scn_rejection_threshold_hours其默認值過大。Bug13554409 - Fix for bug 13554409 [ID 13554409.8]就是說的這個問題。不過這個問題已經在2012年4月的CPU或PSU補丁中獲得修復。
在最後咱們來解讀一下alert日誌中的一些信息:
信息
請點擊此處輸入圖片描述
這裏是說,SCN向前(跳躍)遞增了68098分鐘,其遞增後的SCN是0x0ba9.4111a520。注意這裏的分鐘的計算就是根據SCN每秒最大可能增加速率爲16K來的。咱們計算一下:
0x0ba94111a520轉換成10進制12821569053984。
在alert日誌中,這個信息是剛打開數據庫的時候,因此 crash recovery完成時的scn能夠作爲近似的當前SCN,其值爲12754630269552:
(12821569053984-12754630269552)/16384/60=68093.65278320313
這裏16384值的是SCN每秒最大可能增加速率,能夠看到計算結果極爲接近。
咱們再來計算一下這個SCN的headroom是多少:
請點擊此處輸入圖片描述
能夠看到結果爲24天,因爲這個時候_external_scn_rejection_threshold_hours參數值爲24,即1天,因此雖然有這麼大的跳躍,但SCN仍然增加成功。
信息
請點擊此處輸入圖片描述
在這個信息中,拒絕了db link引發的SCN增長。計算一下這個SCN的headroom:
0x0ba93caec689轉換成10進制是12821495465609
當前時間是2012-05-30 12:02:00,
請點擊此處輸入圖片描述
因爲這個時候_external_scn_rejection_threshold_hours參數值爲744,即31天,計算出的headroom在這個閾值以內,所以拒絕增長SCN。
(31-24.0710752)*24=166.2941952,正好是166小時。
-update on 2012/6/2--
實際上2012年1月的CPU或PSU補丁以後還會有下面的變化:
一、_minimum_giga_scn這個隱含沒有了,惋惜了這個手工增長SCN的利器。
二、11.2.0.2及以後的版本,從原來的32K SCN最大速率調整回了16K速率。能夠用下面的SQL來獲得結果:
請點擊此處輸入圖片描述
上面的SQL的結果只有在11.2.0.2及以上版本纔有意義,結果爲Y,表示使用的是16K的速率,不然是使用32K速率。
本文涉及的一些參數,和SCN的一些算法,可能會隨着版本或補丁的變化而產生較大的變化。
important update: 實際上在Jan 2012的PSU/CPU補丁中存在較大的SCN BUG,目前已經不建議打這個補丁集,而是打到更高的PSU補丁集上。