【体系结构】有关Oracle SCN知识点的整理
1 BLOG文档结构图
BLOG_Oracle_lhr_Oracle SCN的一点研究.pdf
2 前言部分
2.1 导读和注意事项
各位技术爱好者,看完本文后,你可以掌握如下的技能,也可以学到一些其它你所不知道的知识,~O(∩_∩)O~:
① Oracle中的SCN是什么?(重点)
② 如何查询SCN?(重点)
③ SCN有哪些分类?(重点)
④ SCN和系统恢复的关系?(重点)
④ 实例恢复和介质恢复的区别是什么?RAC中的实例恢复是什么样的?(重点)
⑥ SCN和时间的转换
⑦ SMON_SCN_TIME系统表的认识
⑧ 不完全恢复的一些分类及其写法
Tips:
① 本文在itpub(http://blog.itpub.net/26736162)、博客园(http://www.cnblogs.com/lhrbest)和微信公众号(xiaomaimiaolhr)上有同步更新。
② 文章中用到的所有代码、相关软件、相关资料及本文的pdf版本都请前往小麦苗的360云盘下载,我的360云盘地址见:http://blog.itpub.net/26736162/viewspace-1624453/。
③ 若网页文章代码格式有错乱,请尝试以下办法:①使用360浏览器,②去博客园地址阅读③下载pdf格式的文档来阅读。
④ 在本篇BLOG中,代码输出部分一般放在一行一列的表格中。其中,需要特别关注的地方我都用灰色背景和粉红色字体来表示,比如在下边的例子中,thread 1的最大归档日志号为33,thread 2的最大归档日志号为43是需要特别关注的地方;而命令一般使用黄色背景和红色字体标注;对代码或代码输出部分的注释一般采用蓝色字体表示。
List of Archived Logs in backup set 11 Thrd Seq Low SCN Low Time Next SCN Next Time ---- ------- ---------- ------------------- ---------- --------- 1 32 1621589 2015-05-29 11:09:52 1625242 2015-05-29 11:15:48 1 33 1625242 2015-05-29 11:15:48 1625293 2015-05-29 11:15:58 2 42 1613951 2015-05-29 10:41:18 1625245 2015-05-29 11:15:49 2 43 1625245 2015-05-29 11:15:49 1625253 2015-05-29 11:15:53 [ZHLHRDB1:root]:/>lsvg -o T_XLHRD_APP1_vg rootvg [ZHLHRDB1:root]:/> 00:27:22 SQL> alter tablespace idxtbs read write; ====》2097152*512/1024/1024/1024=1G |
本文如有错误或不完善的地方请大家多多指正,ITPUB留言或QQ皆可,您的批评指正是我写作的最大动力。
2.2 本文简介
由于写书遇到了SCN的概念,所以就找了点资料,整理了一下有关SCN的一些知识。顺便复习了一下SCN和数据库恢复的关系。
3 Oracle SCN
3.1 简介
SCN(System Change Number,系统改变号)是一个由系统内部维护的序列号。当系统需要更新的时候自动增加,它是系统中维持数据的一致性和顺序恢复的重要标志,是数据库非常重要的一种数据结构。SCN的最大值是0xffff.ffffffff。在数据库中SCN作为一种时钟机制来标记数据库动作,比如当事务的发生,数据库会用一个SCN来标记它。同时这个SCN在数据库全局也是唯一的,它随时间的增长而增长除非重建数据库。
在数据库中,SCN可以说是无处不在,数据文件头,控制文件,数据块头,日志文件等等都标记着SCN。也正是这样,数据库的一致性维护和SCN密切相关。不管是数据的备份,恢复都是离不开SCN的。
3.2 官方文档
A system change number (SCN) is a logical, internal time stamp used by Oracle Database. SCNs order events that occur within the database, which is necessary to satisfy the ACID properties of a transaction. Oracle Database uses SCNs to mark the SCN before which all changes are known to be on disk so that recovery avoids applying unnecessary redo. The database also uses SCNs to mark the point at which no redo exists for a set of data so that recovery can stop.
SCNs occur in a monotonically increasing sequence. Oracle Database can use an SCN like a clock because an observed SCN indicates a logical point in time and repeated observations return equal or greater values. If one event has a lower SCN than another event, then it occurred at an earlier time with respect to the database. Several events may share the same SCN, which means that they occurred at the same time with respect to the database.
Every transaction has an SCN. For example, if a transaction updates a row, then the database records the SCN at which this update occurred. Other modifications in this transaction have the same SCN. When a transaction commits, the database records an SCN for this commit.
Oracle Database increments SCNs in the system global area (SGA). When a transaction modifies data, the database writes a new SCN to the undo data segment assigned to the transaction. The log writer process then writes the commit record of the transaction immediately to the online redo log. The commit record has the unique SCN of the transaction. Oracle Database also uses SCNs as part of its instance recovery and media recovery mechanisms.
怎么理解这个“SCN(系统变更号)是供Oracle数据库使用的一个逻辑的、内部的时间戳”呢?要理解这个先需要理解Oracle中的事务(Transaction)和数据一致性(Data Consistency)的概念。
先说说数据一致性的概念。数据一致性指的是数据的可用性。比如说管理一个财务的系统,需要从A账户将100元转入到B账户,正常的操作是从A账户减去100元,然后给B账户加上100元,如果这两步操作都正常完成了,那我们可以说完成转账操作之后的数据是一致可用的;但是如果在操作的过程中出了问题,A账户的100元给减掉了,但是B账户却没有加上100元,这样的情况下产生的结果数据就有问题了,因为部分操作的失败导致了数据的不一致而不可用,在实际中肯定是要避免这种让数据不一致的情况发生的。在Oracle数据库中,保证数据一致性的方法就是事务。
事务是一个逻辑的、原子性的作业单元,通常由一个或者是多个SQL组成,一个事务里面的所有SQL操作要么全部失败回滚(Rollback),要么就是全部成功提交(Commit)。就像上面转账的例子,为保证数据的一致性,就需要将转账的两步操作放在一个事务里面,这样不管哪个操作失败了,都需要将所有已进行的操作回滚,以保证数据的可用性。进行事务管理是数据库区别于别的文件系统的一个最主要的特征,在数据库中事务最主要的作用就是保证了数据的一致性,每次事务的提交都是将数据库从一种一致性的状态带入到另外一种一致性的状态中,SCN就是用来对数据库的每个一致状态进行标记的,每当数据库进入到一个新的一致的状态,SCN就会加1,也就是每个提交操作之后,SCN都会增加。也许你会想为什么不直接记录事务提交时候的时间戳呢?这里面主要是涉及了两个问题,一个是时间戳记录的精度有限,再一个就是在分布式系统中记录时间戳会存在系统时钟同步的问题,详细的讨论可以查看Ordering Events in Oracle。
SCN在数据库中是一个单一的不断的随着数据库一致性状态的改变而自增的序列。正如一个时间戳代表着时间里面的某一个固定的时刻点一样,每一个SCN值也代表着数据库在运行当中的一个一致性的点,大的SCN值所对应的事务总是比小SCN值的事务发生的更晚。因此把SCN说成是Oracle数据库的逻辑时间戳是很恰当的。
3.3 SCN的分类
严格来说SCN是没有分类的,之所以会有不同类型的SCN并不是说这些SCN的概念不一样,而是说不同分类的SCN代表的意义不一样,不管什么时候SCN所指代的都是数据库的某个一致性的状态。就像我们给一天中的某个时间点定义上班时间、另外的某个时间点定义成下班时间一样,数据库Checkpoint发生点的SCN被称为Checkpoint SCN,仅此而已。
SCN可以分为4类,系统检查点SCN(System Checkpoint SCN)、文件检查点SCN(Datafile Checkpoint SCN)、开始SCN(Start SCN)和结束SCN(Stop SCN),参考如下表格:
3.4 查询4种SCN常用的SQL语句
col status for a10 select GROUP# ,SEQUENCE#,STATUS,FIRST_CHANGE#,FIRST_TIME from v$log; SELECT A.FILE#, A.NAME, (SELECT CHECKPOINT_CHANGE# FROM V$DATABASE) SYSTEM_CKPT_SCN, A.CHECKPOINT_CHANGE# DF_CKPT_SCN, A.LAST_CHANGE# END_SCN, B.CHECKPOINT_CHANGE# START_SCN, B.RECOVER, A.STATUS FROM VDATAFILEA,VDATAFILEA,VDATAFILE_HEADER B WHERE A.FILE# = B.FILE#; SELECT FILE#,ONLINE_STATUS,CHANGE#,ERROR FROM V$RECOVER_FILE; |
3.4.1 文件检查点SCN (Datafile Checkpoint SCN)
SYS@lhrdb> select file#,checkpoint_change# from v$datafile; FILE# CHECKPOINT_CHANGE# ---------- ------------------ 1 9026292 2 9026292 3 9026292 4 9026292 5 9026292 6 9026292 7 9026292 7 rows selected. SYS@lhrdb> alter tablespace users read only; Tablespace altered. SYS@lhrdb> select file#,checkpoint_change# from v$datafile; FILE# CHECKPOINT_CHANGE# ---------- ------------------ 1 9026292 2 9026292 3 9026292 4 9028165 5 9026292 6 9026292 7 9026292 7 rows selected. SYS@lhrdb> select checkpoint_change# from v$database; CHECKPOINT_CHANGE# ------------------ 9026292 |
可以看到4号文件也就是users表空间所属的文件scn值和其他文件不一致,且比系统检查点的scn要大。
3.4.2 Stop SCN
每个数据文件的终止scn都存储在控制文件中,在数据库正常运行的情况下,对可读写的,online的数据文件,该SCN号为NULL。
SQL:SELECT NAME,status,enabled,Checkpoint_change# ,checkpoint_time,last_change# FROM v$datafile;
在数据库打开过程中,Oracle会比较各文件的stop scn和checkpoint scn,如果值不一致,表明数据库先前没有正常关闭,需要做恢复。
SYS@lhrdb> SELECT TABLESPACE_NAME,STATUS FROM DBA_TABLESPACES; TABLESPACE_NAME STATUS ------------------------------ --------- SYSTEM ONLINE SYSAUX ONLINE UNDOTBS1 ONLINE TEMP ONLINE USERS READ ONLY EXAMPLE ONLINE TS_MIG_CHAIN_LHR ONLINE TS_TESTBLOCKLHR ONLINE 8 rows selected. SYS@lhrdb> SELECT FILE#,LAST_CHANGE# FROM V$DATAFILE; FILE# LAST_CHANGE# ---------- ------------ 1 2 3 4 9028165 5 6 7 7 rows selected. |
可以看到除了USERS表空间的结束SCN不为空,其他数据文件的结束SCN为空。
将数据库至于MOUNT状态,由于该状态下所有的数据文件都不可写,故MOUNT状态下所有的数据文件都具有结束SCN。
SYS@lhrdb> startup mount ORACLE instance started. Total System Global Area 1720328192 bytes Fixed Size 2247072 bytes Variable Size 452986464 bytes Database Buffers 1258291200 bytes Redo Buffers 6803456 bytes Database mounted. SYS@lhrdb> SELECT FILE#,LAST_CHANGE# FROM V$DATAFILE; FILE# LAST_CHANGE# ---------- ------------ 1 9048847 2 9048847 3 9048847 4 9028165 5 9048847 6 9048847 7 9048847 7 rows selected. SYS@lhrdb> alter tablespace users read write; Tablespace altered. SYS@lhrdb> SELECT FILE#,LAST_CHANGE# FROM V$DATAFILE; FILE# LAST_CHANGE# ---------- ------------ 1 2 3 4 5 6 7 7 rows selected. SYS@lhrdb> startup force mount ORACLE instance started. Total System Global Area 1720328192 bytes Fixed Size 2247072 bytes Variable Size 452986464 bytes Database Buffers 1258291200 bytes Redo Buffers 6803456 bytes Database mounted. SYS@lhrdb> SELECT FILE#,LAST_CHANGE# FROM V$DATAFILE; FILE# LAST_CHANGE# ---------- ------------ 1 2 3 4 5 6 7 7 rows selected. |
3.4.3 HIGH AND LOW SCN
ORACLE的REDO LOG会顺序纪录数据库的各个变化。一组REDO LOG文件写满后,会自动切换到下一组REDO LOG文件。则上一组REDO LOG的HIGH SCN就是下一组REDO LOG的LOW SCN。在CURRENT LOG中HIGH SCN为无穷大。
在视图V$LOG_HISTORY中,SEQUENCE#代表REDO LOG的序列号,FIRST_CHANGE#表示当前REDO LOG的LOW SCN,列NEXT_CHANGE#表示当前REDO LOG的HIGH SCN。
可通过查询V$LOG_HISTORY查看 LOW SCN和 HIGH SCN。
SYS@lhrdb> set pagesize 9999 SYS@lhrdb> SELECT RECID,SEQUENCE#,FIRST_CHANGE#,NEXT_CHANGE# FROM V$LOG_HISTORY WHERE ROWNUM<=6; RECID SEQUENCE# FIRST_CHANGE# NEXT_CHANGE# ---------- ---------- ------------- ------------ 272 272 7486197 7510243 273 273 7510243 7527538 274 274 7527538 7539409 275 275 7539409 7556740 276 276 7556740 7572195 277 277 7572195 7581847 6 rows selected. |
查看CURRNET REDO LOG中的HIGH SCN
SYS@lhrdb> COL MEMBER FORMAT A50 SYS@lhrdb> SELECT VF.MEMBER,V.STATUS,V.FIRST_CHANGE# FROM VLOGFILEVF,VLOGFILEVF,VLOG V 2 WHERE VF.GROUP#=V.GROUP# 3 AND V.STATUS='CURRENT'; MEMBER STATUS FIRST_CHANGE# -------------------------------------------------- ---------------- ------------- +DATA/lhrdb/onlinelog/group_4.798.923841413 CURRENT 9069089 +DATA/lhrdb/onlinelog/group_4.797.923841415 CURRENT 9069089 SYS@lhrdb> ALTER SYSTEM DUMP LOGFILE '+DATA/lhrdb/onlinelog/group_4.797.923841415'; System altered. SYS@lhrdb> oradebug setmypid Statement processed. SYS@lhrdb> oradebug tracefile_name /oracle/app/oracle/diag/rdbms/lhrdb/lhrdb/trace/lhrdb_ora_8388948.trc |
查看转储文件的内容:
DUMP OF REDO FROM FILE '+DATA/lhrdb/onlinelog/group_4.797.923841415' 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 = 186647552=0xb200400 Db ID=959319562=0x392e0e0a, Db Name='LHRDB' Activation ID=959339270=0x392e5b06 Control Seq=96545=0x17921, File size=204800=0x32000 File Number=4, Blksiz=512, File Type=2 LOG descrip:"Thread 0001, Seq# 0000001090, SCN 0x0000008a6221-0xffffffffffff" thread: 1 nab: 0xffffffff seq: 0x00000442 hws: 0x2 eot: 1 dis: 0 resetlogs count: 0x36a23c8c scn: 0x0000.000e20dc (925916) prev resetlogs count: 0x3155bebd scn: 0x0000.00000001 (1) Low scn: 0x0000.008a6221 (9069089) 10/11/2016 16:46:41 Next scn: 0xffff.ffffffff 01/01/1988 00:00:00 Enabled scn: 0x0000.000e20dc (925916) 07/07/2016 19:39:56 Thread closed scn: 0x0000.008a6221 (9069089) 10/11/2016 16:46:41 Disk cksum: 0xc14c Calc cksum: 0xc14c 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: 0x800000 Thread internal enable indicator: thr: 0, seq: 0 scn: 0x0000.00000000 Zero blocks: 0 Format ID is 1 redo log key is 47e6cd1abd3a43fd864d2b94ae9a8128 redo log key flag is 5 Enabled redo threads: 1 |
当前最新的数据库scn值可通过如下命令查看:
SYS@lhrdb> select dbms_flashback.get_system_change_number from dual; GET_SYSTEM_CHANGE_NUMBER ------------------------ 9069555 |
如果需要进行实例恢复,则需要恢复的记录为9069089至9069555中redo log中的记录。
3.5 SCN号于数据库的启动、关闭
Scn号与Oracle数据库恢复过程有着密切的关系,只有很好地理解了这层关系,才能深刻地理解恢复的原理。CKPT进程在checkpoint发生时,将当时的SCN号写入数据文件头和控制文件,同时通知DBWR进程将数据块写到数据文件。
CKPT进程也会在控制文件中记录RBA(redo block address),以标志Recovery需要从日志中哪个地方开始。
1.在数据库的启动过程中,当System Checkpoint SCN=Datafile Checkpoint SCN=Start SCN的时候,Oracle数据库是可以正常启动的,而不需要做任何的MEDIA RECOVERY。而如果三者当中有一个不同的话,则需要做MEDIA RECOVERY。Oracle在启动过程中首先检查是否需要MEDIA RECOVERY,然后再检查是否需要INSTANCE RECOVERY。
2.那什么时候需要做INSTANCE RECOVERY呢?其实在正常OPEN数据库的时候,Oracle会将记录在控制文件中的每一个数据文件头的End SCN都设置为#FFFFFF(NULL),那么如果数据库进行了正常关闭比如(shutdown or shutdown immediate)这个时候,系统会执行一个检查点,这个检查点会将控制文件中记录的各个数据文件头的End SCN更新为当前online数据文件的各个数据文件头的Start SCN,也就是End SCN=Start SCN,如果再次启动数据库的时候发现二者相等,则直接打开数据库,并再次将End SCN设置为#FFFFFF(NULL),那么如果数据库是异常关闭,那么CHECKPOINT就不会执行,因此再次打开数据库的时候End SCN<>Start SCN这个时候就需要做实例恢复。如果数据库异常关闭的话,则END SCN号将为NULL.则需要做instance recovery。
3.5.1 为什么需要System checkpoint SCN号与Datafile Checkpoint SCN号
为什么ORACLE会在控制文件中记录System checkpoint SCN号的同时,还需要为每个数据文件记录Datafile Checkpoint SCN号?
原因有二:
1.对只读表空间,其数据文件的Datafile Checkpoint SCN、Start SCN和END SCN号均相同。这三个SCN在表空间处于只读期间都将被冻结。
2.如果控制文件不是当前的控制文件,则System checkpoint会小于Start SCN或END SCN号。记录这些SCN号,可以区分控制文件是否是当前的控制文件。
SYS@lhrdb> alter tablespace users read only; Tablespace altered. SYS@lhrdb> SELECT A.FILE#, 2 A.NAME, 3 (SELECT CHECKPOINT_CHANGE# FROM V$DATABASE) SYSTEM_CKPT_SCN, 4 A.CHECKPOINT_CHANGE# DF_CKPT_SCN, 5 A.LAST_CHANGE# END_SCN, 6 B.CHECKPOINT_CHANGE# START_SCN, 7 B.RECOVER, 8 A.STATUS 9 FROM V$DATAFILEA A,V$DATAFILE_HEADER B 10 WHERE A.FILE# = B.FILE#; FILE# NAME SYSTEM_CKPT_SCN DF_CKPT_SCN END_SCN START_SCN REC STATUS ---------- ------------------------------------------------------------ --------------- ----------- ---------- ---------- --- ---------- 1 +DATA/lhrdb/datafile/system.347.916601927 9225394 9225394 9225394 NO SYSTEM 2 +DATA/lhrdb/datafile/sysaux.340.916601927 9225394 9225394 9225394 NO ONLINE 3 +DATA/lhrdb/datafile/undotbs1.353.916601927 9225394 9225394 9225394 NO ONLINE 4 +DATA/lhrdb/datafile/users.445.916601927 9225394 9229175 9229175 9229175 NO ONLINE 5 +DATA/lhrdb/datafile/example.416.916602001 9225394 9225394 9225394 NO ONLINE 6 +DATA/lhrdb/datafile/ts_mig_chain_lhr.471.919677645 9225394 9225394 9225394 NO ONLINE 7 /oracle/app/oracle/oradata/lhrdb/testblocklhr01.dbf 9225394 9225394 9225394 NO ONLINE 7 rows selected. |
3.5.2 recover database using backup controlfile
当有一个Start SCN号超过了System Checkpoint SCN号时,则说明控制文件不是当前的控制文件,因此在做recover时需要采用using backup controlfile。这是为什么需要记录SystemCheckpoint SCN的原因之一。
这里需要一提的是,当重建控制文件的时候,System Checkpoint SCN为0,Datafile Checkpoint SCN的数据来自于Start SCN。根据上述的描述,此时需要采用using backup controlfile做recovery.
3.6 查看系统当前SCN
Oracle数据库提供了两种直接查看系统当前SCN的方法,一个是V$DATABASE中的CURRENT_SCN列,另外一个就是通过DBMS_FLASHBACK.GET_SYSTEM_CHANGE_NUMBER得到。
SYS@ORACNSL1> COL SCN1 FOR 9999999999999 SYS@ORACNSL1> COL SCN2 FOR 9999999999999 SYS@ORACNSL1> COL SCN3 FOR 9999999999999 SYS@ORACNSL1> SELECT CURRENT_SCN SCN1,DBMS_FLASHBACK.GET_SYSTEM_CHANGE_NUMBER SCN2,TIMESTAMP_TO_SCN(SYSDATE) SCN3 FROM V$DATABASE; SCN1 SCN2 SCN3 -------------- -------------- ---------- 1495460388 1495460388 1495460387 |
一般情况下,SCN1和SCN2的结果一致,但在系统比较繁忙的时候可能SCN2比SCN1稍微大一点,比如大1。
在oracle 9i中要麻烦些,V$DATABASE视图中没有CURRENT_SCN这列,只有通过查询X$KTUXE视图来得到。
SYS@lhrdb> SELECT MAX(KTUXESCNW*POWER(2,32)+KTUXESCNB) SCN FROM X$KTUXE; SCN ---------- 8764198 |
3.7 SCN与时间的相互转换(SCN_TO_TIMESTAMP与TIMESTAMP_TO_SCN)
Oracle 10g提供了两个新函数对于SCN和时间戳进行相互转换,这两个函数是SCN_TO_TIMESTAMP、TIMESTAMP_TO_SCN,通过对SCN和时间戳进行转换,Oracle极大地方便了很多备份和恢复过程。
一个SCN值总是发生在某一个特定的时刻的,只不过由于粒度的不一样,通常会存在多个SCN对应同一个时间戳。Oracle中提供了两个函数以供我们进行SCN和时间的互换:
l SCN_TO_TIMESTAMP(scn_number) 将SCN转换成时间戳。
l TIMESTAMP_TO_SCN(timestamp) 将时间戳转换成SCN。
通过这两个函数,最终Oracle将SCN和时间的关系建立起来,在Oracle 10g之前,是没有办法通过函数转换得到SCN和时间的对应关系的,一般可以通过logmnr分析日志获得。但是这种转换要依赖于数据库内部的数据记录(SMON_SCN_TIME),对于久远的SCN则不能转换,请看以下举例:
SYS@lhrdb> SELECT MIN(FIRST_CHANGE#) SCN,DBMS_FLASHBACK.GET_SYSTEM_CHANGE_NUMBER FROM V$ARCHIVED_LOG; SCN GET_SYSTEM_CHANGE_NUMBER ---------- ------------------------ 7527538 8763206 SYS@lhrdb> SELECT SCN_TO_TIMESTAMP(7527538) SCN FROM DUAL; select scn_to_timestamp(7527538) scn from dual * ERROR at line 1: ORA-08181: specified number is not a valid system change number ORA-06512: at "SYS.SCN_TO_TIMESTAMP", line 1 SYS@lhrdb> select min(scn) from smon_scn_time; MIN(SCN) ---------- 8622517 SYS@lhrdb> select scn_to_timestamp(8622517) timestamp from dual; TIMESTAMP --------------------------------------------------------------------------- 08-OCT-16 04.30.26.000000000 AM SYS@lhrdb> select scn_to_timestamp(8622516) timestamp from dual; select scn_to_timestamp(8622516) timestamp from dual * ERROR at line 1: ORA-08181: specified number is not a valid system change number ORA-06512: at "SYS.SCN_TO_TIMESTAMP", line 1 |
从上面的例子可以看出Oracle能够转换的最小SCN也就是SMON_SCN_TIME.scn的最小值。
SYS@lhrdb> SELECT SCN_TO_TIMESTAMP(8763206) SCN FROM DUAL; SCN --------------------------------------------------------------------------- 10-OCT-16 05.22.40.000000000 PM SYS@lhrdb> SELECT TIMESTAMP_TO_SCN(TO_TIMESTAMP('10-OCT-16 05.22.40.000000000 PM','DD-Mon-RR HH:MI:SS.FF AM')) SCN FROM DUAL; SCN ---------- 8763206 SYS@lhrdb> SELECT TIMESTAMP_TO_SCN(TO_TIMESTAMP('2016-10-10 17:22:40','YYYY-MM-DD HH24:MI:SS')) SCN FROM DUAL; SCN ---------- 8763206 SYS@lhrdb> SELECT TO_CHAR(SCN_TO_TIMESTAMP(8763206), 'YYYY-MM-DD HH24:MI:SS') CHR_DATE,TIMESTAMP_TO_SCN(SCN_TO_TIMESTAMP(8763206)) DT FROM DUAL; CHR_DATE DT ------------------- ---------- 2016-10-10 17:22:40 8763206 |
对于时间到SCN的转换,Oracle只能定位到3秒以内,3秒内的时间都被转换成同一个SCN:
SYS@lhrdb> SELECT TIMESTAMP_TO_SCN(TO_TIMESTAMP('2016-10-10 17:22:40','YYYY-MM-DD HH24:MI:SS')) SCN FROM DUAL; SCN ---------- 8763206 SYS@lhrdb> SELECT TIMESTAMP_TO_SCN(TO_TIMESTAMP('2016-10-10 17:22:41','YYYY-MM-DD HH24:MI:SS')) SCN FROM DUAL; SCN ---------- 8763206 SYS@lhrdb> SELECT TIMESTAMP_TO_SCN(TO_TIMESTAMP('2016-10-10 17:22:42','YYYY-MM-DD HH24:MI:SS')) SCN FROM DUAL; SCN ---------- 8763206 SYS@lhrdb> SELECT TIMESTAMP_TO_SCN(TO_TIMESTAMP('2016-10-10 17:22:43','YYYY-MM-DD HH24:MI:SS')) SCN FROM DUAL; SCN ---------- 8763213 SYS@lhrdb> SELECT TIMESTAMP_TO_SCN(TO_TIMESTAMP('2016-10-10 17:22:39','YYYY-MM-DD HH24:MI:SS')) SCN FROM DUAL; SCN ---------- 8763205 |
3.7.1 SMON_SCN_TIME
SELECT * FROM DBA_TABLES D WHERE D.TABLE_NAME = 'SMON_SCN_TIME';
Oracle 在内部都是使用scn,即使你指定的是as of timestamp,oracle 也会将其转换成scn,系统时间标记与scn 之间存在一张表,即SYS下的SMON_SCN_TIME。
SYS@lhrdb> set linesize 80 SYS@lhrdb> desc sys.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 |
每隔5分钟,系统产生一次系统时间标记与scn的匹配并存入sys.smon_scn_time 表,该表中记录了最近1440个系统时间标记与scn的匹配记录,由于该表只维护了最近的1440条记录,因此如果使用as of timestamp的方式则只能flashback最近5天内的数据(假设系统是在持续不断运行并无中断或关机重启之类操作的话)。
查看SCN 和 timestamp 之间的对应关系:
SELECT SCN, TO_CHAR(TIME_DP, 'YYYY-MM-DD HH24:MI:SS') TIME_DP
FROM SYS.SMON_SCN_TIME T
ORDER BY T.SCN DESC;
有关表SMON_SCN_TIME的更多内容可以参考我的BLOG:http://blog.itpub.net/26736162/viewspace-2126291/,David大神写的,非常全面,我就不画蛇添足了。
3.8 实例恢复(INSTANCE RECOVERY)和介质恢复(MEDIA RECOVERY)
REDO LOG是Oracle为确保已经提交的事务不会丢失而建立的一个机制。实际上REDO LOG的存在是为两种场景准备的,一种我们称之为实例恢复(INSTANCE RECOVERY),一种我们称之为介质恢复(MEDIA RECOVERY)。
REDO LOG的数据是按照THREAD来组织的,对于单实例系统来说,只有一个THREAD,对于RAC系统来说,可能存在多个THREAD,每个数据库实例拥有一组独立的REDO LOG文件,拥有独立的LOG BUFFER,某个实例的变化会被独立的记录到一个THREAD的REDO LOG文件中。
3.8.1 实例恢复
对于单实例的系统,实例恢复一般是在数据库实例异常故障后数据库重启时进行,当数据库执行了SHUTDOWN ABORT或者由于操作系统、主机等原因宕机重启后,在执行ALTER DATABASE OPEN的时候,就会自动做实例恢复。而在RAC环境中,如果某个实例宕机了,那么剩下的实例将会代替宕掉的实例做实例恢复。除非是所有的实例都宕机了,这样的话,第一个执行ALTER DATABASE OPEN的实例将会做实例恢复。这也是在RAC环境中,REDO LOG是实例私有的组件,但是REDO LOG的文件必须存放在共享存储上的原因。
一、 RAC中的实例恢复
一个单实例数据库或者RAC数据库所有实例失败之后,第一个打开数据库的实例会自动执行实例恢复。这种形式的实例恢复称为Crash恢复。一个RAC数据库的一部分但不是所有实例失败后,在RAC中幸存的实例自动执行失败实例的恢复称为实例恢复。一般而言,在崩溃或关机退出之后第一个打开数据库的实例将自动执行崩溃恢复。
根据Crash恢复和实例恢复的不同,由幸存实例或者第一个重启的实例读取失败实例生成的联机Redo日志和UNDO表空间数据,使用这些信息确保只有已提交的事务被写到数据库中,回滚在失败时候活动的事务,并释放事务使用的资源。
[ZFZHLHRDB1:oracle]:/oracle>crsctl stat res -t -------------------------------------------------------------------------------- NAME TARGET STATE SERVER STATE_DETAILS -------------------------------------------------------------------------------- Local Resources -------------------------------------------------------------------------------- ora.DATA.dg ONLINE ONLINE zfzhlhrdb1 ONLINE ONLINE zfzhlhrdb2 ora.LISTENER.lsnr ONLINE ONLINE zfzhlhrdb1 ONLINE ONLINE zfzhlhrdb2 ora.LISTENER_LHRDG.lsnr ONLINE ONLINE zfzhlhrdb1 ONLINE ONLINE zfzhlhrdb2 ora.asm ONLINE ONLINE zfzhlhrdb1 Started ONLINE ONLINE zfzhlhrdb2 Started ora.gsd OFFLINE OFFLINE zfzhlhrdb1 OFFLINE OFFLINE zfzhlhrdb2 ora.net1.network ONLINE ONLINE zfzhlhrdb1 ONLINE ONLINE zfzhlhrdb2 ora.ons ONLINE ONLINE zfzhlhrdb1 ONLINE ONLINE zfzhlhrdb2 ora.registry.acfs ONLINE ONLINE zfzhlhrdb1 ONLINE ONLINE zfzhlhrdb2 -------------------------------------------------------------------------------- Cluster Resources -------------------------------------------------------------------------------- ora.LISTENER_SCAN1.lsnr 1 ONLINE ONLINE zfzhlhrdb1 ora.cvu 1 ONLINE ONLINE zfzhlhrdb1 ora.lhrdb.db 1 ONLINE ONLINE zfzhlhrdb1 Open ora.oc4j 1 ONLINE ONLINE zfzhlhrdb1 ora.raclhr.db 1 ONLINE ONLINE zfzhlhrdb2 Open 2 ONLINE ONLINE zfzhlhrdb1 Open ora.scan1.vip 1 ONLINE ONLINE zfzhlhrdb1 ora.zfzhlhrdb1.vip 1 ONLINE ONLINE zfzhlhrdb1 ora.zfzhlhrdb2.vip 1 ONLINE ONLINE zfzhlhrdb2 [ZFZHLHRDB1:oracle]:/oracle>srvctl stop instance -d raclhr -i raclhr1 -o abort [ZFZHLHRDB1:oracle]:/oracle>srvctl status db -d raclhr Instance raclhr1 is not running on node zfzhlhrdb1 Instance raclhr2 is running on node zfzhlhrdb2 |
abort掉实例1后:
实例一的告警日志:
Thu Oct 13 15:51:30 2016 Shutting down instance (abort) License high water mark = 60 USER (ospid: 4194780): terminating the instance Instance terminated by USER, pid = 4194780 Thu Oct 13 15:51:32 2016 Instance shutdown complete |
实例二的告警日志:
Thu Oct 13 15:51:31 2016 Reconfiguration started (old inc 4, new inc 6) List of instances: 2 (myinst: 2) Global Resource Directory frozen * dead instance detected - domain 0 invalid = TRUE Communication channels reestablished Master broadcasted resource hash value bitmaps Non-local Process blocks cleaned out Thu Oct 13 15:51:31 2016 LMS 0: 0 GCS shadows cancelled, 0 closed, 0 Xw survived Thu Oct 13 15:51:31 2016 LMS 1: 0 GCS shadows cancelled, 0 closed, 0 Xw survived Set master node info Submitted all remote-enqueue requests Dwn-cvts replayed, VALBLKs dubious All grantable enqueues granted Post SMON to start 1st pass IR Thu Oct 13 15:51:31 2016 Instance recovery: looking for dead threads Submitted all GCS remote-cache requests Post SMON to start 1st pass IR Fix write in gcs resources Reconfiguration complete Beginning instance recovery of 1 threads parallel recovery started with 7 processes Started redo scan Completed redo scan read 18 KB redo, 14 data blocks need recovery Started redo application at Thread 1: logseq 235, block 68352 Recovery of Online Redo Log: Thread 1 Group 1 Seq 235 Reading mem 0 Mem# 0: +DATA/raclhr/onlinelog/group_1.362.916601361 Mem# 1: +DATA/raclhr/onlinelog/group_1.361.916601361 Completed redo application of 0.01MB Completed instance recovery at Thread 1: logseq 235, block 68389, scn 9725527 14 data blocks read, 14 data blocks written, 18 redo k-bytes read Thu Oct 13 15:51:33 2016 minact-scn: Inst 2 is now the master inc#:6 mmon proc-id:25100420 status:0x7 minact-scn status: grec-scn:0x0000.00000000 gmin-scn:0x0000.009417d9 gcalc-scn:0x0000.009417e3 minact-scn: master found reconf/inst-rec before recscn scan old-inc#:6 new-inc#:6 Thread 1 advanced to log sequence 236 (thread recovery) Redo thread 1 internally disabled at seq 236 (SMON) Thu Oct 13 15:51:34 2016 Thread 2 advanced to log sequence 265 (LGWR switch) Current log# 4 seq# 265 mem# 0: +DATA/raclhr/onlinelog/group_4.349.916601715 Current log# 4 seq# 265 mem# 1: +DATA/raclhr/onlinelog/group_4.348.916601715 Thu Oct 13 15:51:35 2016 Archived Log entry 493 added for thread 1 sequence 235 ID 0x441b1480 dest 1: Thu Oct 13 15:51:35 2016 ARC0: Archiving disabled thread 1 sequence 236 Archived Log entry 494 added for thread 1 sequence 236 ID 0x441b1480 dest 1: Thu Oct 13 15:51:35 2016 Archived Log entry 495 added for thread 2 sequence 264 ID 0x441b1480 dest 1: minact-scn: master continuing after IR |
3.8.2 介质恢复
介质恢复是基于物理备份恢复数据,它是Oracle数据库出现介质故障时恢复的重要保障。介质恢复包括块恢复、数据文件恢复、表空间恢复和整个数据库的恢复。介质恢复主要是针对错误类型中的介质失败,如果是少量的块失败,那么可以使用介质恢复中的块恢复来快速修复;但如果是其它情况的丢失,那么需要根据具体情况,可使用数据文件恢复、表空间恢复甚至全库恢复,可以参考如下的表格:
错误分类 |
恢复解决方案 |
介质失败 |
如果是少量的块损坏,使用块介质恢复;如果是大量的块、数据文件、表空间的损坏,可能需要对损坏的数据文件或者表空间执行完全恢复;如果是归档REDO日志文件或者联机REDO日志文件的丢失,那么只需要不完全恢复方式。 |
逻辑损坏 |
如果是程序员错误导致出现的问题,可通过补丁应用修复问题。对于无法修复的问题,也可采用介质恢复手段来恢复数据。 |
用户错误 |
根据不同用户错误,选择不同的FLASHBACK技术恢复,使用FLASHBACK技术恢复用户错误是首选方案。如果FLASHBACK不能很好的恢复数据再考虑使用介质恢复或者表空间时间点恢复。 |
Oracle数据库的介质恢复实际上包含了两个过程:数据库还原(RESTORE)与数据库恢复(RECOVER)。
数据库还原(RESTORE)是指利用备份的数据库文件来替换已经损坏的数据库文件或者将其恢复到一个新的位置。RMAN在进行还原操作时,会利用恢复目录(有建立恢复目录的话就使用目标数据库的控制文件)来获取备份信息,并从中选择最合适的备份进行修复操作。选择备份时有两个原则:1、选择距离恢复目录时刻最近;2、优先选择镜像复制,其次才是备份集。
数据库恢复(RECOVER)是指数据文件的介质恢复,即为修复后的数据文件应用联机或归档日志,从而将修复的数据库文件更新到当前时刻或指定时刻下的状态。在执行恢复数据库时,需要使用RECOVER命令。
还原是将某个时间点数据文件的拷贝再拷贝回去,还原后的数据库处于不一致性的状态,或不是最新的状态,还需要执行恢复操作。恢复就是使用归档REDO日志文件和联机REDO日志文件将不一致的数据库应用到一致性状态。
需要注意的是,还原只是建立在数据库备份的基础版本上,例如,如果数据库备份包括0级备份和很多1级备份,还原只是应用0级备份,恢复过程会根据情况自动应用1级备份或REDO日志将数据库恢复到一致性的状态。
数据库的恢复过程根据恢复数据的程度又分为完全恢复(Complete Recovery)和不完全恢复(Incomplete Recovery)。
完全恢复是一种没有数据丢失的恢复方式,能够恢复到最新的联机REDO日志中已提交的数据。在传统恢复方式中,因介质失败破坏了数据文件之后,可以在数据库、表空间和数据文件上执行完全介质恢复。
不完全恢复是一种与完全恢复相反的恢复方式,是一种丢失数据的恢复方式,也称为数据库基于时间点恢复(Point-in-Time Recovery),是将整个数据库恢复到之前的某个时间点、日志序列号或者SCN号。通常情况下,若FLASHBACK DATABASE没有启用或者变得无效,可以执行不完全恢复撤销一个用户错误。不完全恢复不一定在原有的数据库环境执行,可以在测试环境下执行不完全恢复,将找回的数据再重新导入生产库中。不完全恢复根据备份情况恢复到与指定时间、日志序列号和SCN具有一致性的数据,之后的数据都将丢失。执行不完全恢复一方面是因为归档REDO日志、联机REDO日志的丢失不得不执行不完全恢复,另一方面可能是因为在某个时刻错误地操作了数据,过了一段时间之后才发现问题,而其它的恢复手段都无法恢复数据,这时也不得不使用不完全恢复来找回数据。执行不完全恢复必须从备份中还原所有的数据文件,备份文件必须是要恢复的时间点之前创建的。当恢复完成,使用RESTLOGS选项打开数据库,将重新初始化联机Redo日志,创建一个新的日志序列号流,日志序列号从1开始,RESETLOGS之后的SCN还是在递增。
如果是完全恢复,那么数据库就是最新的一致性状态;如果是不完全恢复,那么数据库是非最新的一致性状态。对于非归档模式的数据库来说,不能执行不完全恢复。
不完全恢复的选项如下表所示:
不完全恢复方式 |
RMAN选项 |
用户管理备份选项 |
恢复到某个时间点 |
UNTIL TIME |
UNTIL TIME |
恢复到某个日志序列号 |
UNTIL SUQUENCE |
UNTIL CANCEL |
恢复到某个SCN号 |
UNTIL SCN |
UNTIL CHANGE |
不完全恢复的几种类型如下表所示(注意:下图是小麦苗即将出版的书上的一个表格,现在提前分享给大家):
综上所述,恢复的分类大致可以如下图所示的分类(注意:下图也是小麦苗即将出版的书上的一个表格,现在提前分享给大家):
3.8.3 实例恢复和介质恢复的区别(注意:下图也是小麦苗即将出版的书上的一个表格,现在提前分享给大家)
DBA入门之认识Oracle SCN(System Change Number)
1. SCN的定义
SCN(System Change Number),也就是通常所说的系统改变号,是数据库中非常重要的一个数据结构。
SCN用以标识数据库在某个确切时刻提交的版本。在事务提交时,它被赋予一个唯一的标识事务的SCN。SCN同时被作为Oracle数据库的内部时钟机制,可被看做逻辑时钟,每个数据库都有一个全局的SCN生成器。
作为数据库内部的逻辑时钟,数据库事务依SCN而排序,Oracle也依据SCN来实现一致性读(Read Consistency)等重要数据库功能。另外对于分布式事务(Distributed Transactions),SCN也极为重要,这里不做更多介绍。
SCN在数据库中是唯一的,并随时间而增加,但是可能并不连贯。除非重建数据库,SCN的值永远不会被重置为0.
一直以来,对于SCN有很多争议,很多人认为SCN是指System Commit Number,而通常SCN在提交时才变化,所以很多时候,这两个名词经常在文档中反复出现。即使在Oracle的官方文档中,SCN也常以System Change/Commit Number两种形式出现。
到底是哪个词其实不是很重要,重要的是需要知道SCN是Oracle内部的时钟机制,Oracle通过SCN来维护数据库的一致性,并通过SCN实施Oracle至关重要的恢复机制。
SCN在数据库中是无处不在,常见的事务表、控制文件、数据文件头、日志文件、数据块头等都记录有SCN值。
冠以不同前缀,SCN也有了不同的名称,如检查点SCN(Checkpint SCN)、Resetlogs SCN等。
2.SCN的获取方式
可以通过如下几种方式获得数据库的当前或近似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进行修改。
注意:这种方法比较危险,请不要在投产环境下进行测试。
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
我们先聊聊Oracle的SCN。在数据库内部,SCN是一个单向递增的数字编号,控制文件、数据文件、在线Redo日志、归档日志和备份集合中,都包括这个数字编号。在内部文件中,SCN是通过Base和Wrap两个部分进行保存。Base是SCN编号的基础位,是通过32位二进制位进行保存。一旦超过这32位长度,系统会自动在Wrap进位。也就是说,Wrap表示的超过4G个数的进位次数。
使用Oracle oradebug修改SCN,可以在两个场景下进行,就是Oracle启动Open状态和Mount状态。下面分别进行说明。
2、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编号。
3、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
4、结论
使用oradebug直接修改内存SCN,是我们在故障修复时候非常快捷的方法。不过,快捷建立在对内部机制清晰理解的前提之下。所以,无论何种场景进行修复,有备份、可恢复是我们工作的基本前提。
一.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
二.SMON_SCN_TIME表记录保存策略说明
2.1 Oracle 9i
根据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条的记录在下次循环中会被删除。
2.2 Oracle 10g以后的版本
在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操作。
三.禁用SMON 进程对SMON_SCN_TIME 表的更新
可以设置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
四.SMON_SCN_TIME 表相关的2个案例
4.1 Oracle 9i SMON_SCN_TIME 表被锁
LOCK ON SYS.SMON_SCN_TIME [ID 747745.1]
4.1.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
4.1.2 处理方法
设置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.
4.2 Oracle 10g SMON_SCN_TIME 表频繁的被delete
High Executions Of Statement "deletefrom smon_scn_time..." [ID 375401.1]
4.2.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
4.2.2 处理方法
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系列一
背景
在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最大值是什么,哈哈
About Me
...............................................................................................................................
● 本文作者:小麦苗,只专注于数据库的技术,更注重技术的运用
● 本文在itpub(http://blog.itpub.net/26736162)、博客园(http://www.cnblogs.com/lhrbest)和个人微信公众号(xiaomaimiaolhr)上有同步更新
● 本文itpub地址:http://blog.itpub.net/26736162/viewspace-2126407/
● 本文博客园地址:http://www.cnblogs.com/lhrbest/p/5961987.html
● 本文pdf版及小麦苗云盘地址:http://blog.itpub.net/26736162/viewspace-1624453/
● 数据库笔试面试题库及解答:http://blog.itpub.net/26736162/viewspace-2134706/
● QQ群:230161599 微信群:私聊
● 联系我请加QQ好友(646634621),注明添加缘由
● 于 2017-07-01 09:00 ~ 2017-07-31 22:00 在魔都完成
● 文章内容来源于小麦苗的学习笔记,部分整理自网络,若有侵权或不当之处还请谅解
● 版权所有,欢迎分享本文,转载请保留出处
...............................................................................................................................
拿起手机使用微信客户端扫描下边的左边图片来关注小麦苗的微信公众号:xiaomaimiaolhr,扫描右边的二维码加入小麦苗的QQ群,学习最实用的数据库技术。