Welcome 微信登录

首页 / 数据库 / MySQL / 使用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 ProductionPL/SQL Release 11.2.0.4.0 - ProductionCORE    11.2.0.4.0      ProductionTNS for Linux: Version 11.2.0.4.0 - ProductionNLSRTL 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   1754355SQL> 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 setmypidStatement 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 0x001B7740BEFORE: [06001AE70, 06001AE74) = 001AC66FAFTER:  [06001AE70, 06001AE74) = 001B7740SQL> oradebug DUMPvar SGA kcsgscn_kcslf kcsgscn_ [06001AE70, 06001AEA0) = 001B7745 00000000 00000000 00000000 00000164 00000000 00000000 00000000 00000000 00000000 6001AB50 00000000SQL>poke命令中,第一位参数是对应写入的内存位数,第二位参数是写入长度,第三位参数是写入取值。默认写入取值是10进制,我们在这里指定写入16进制。每一个取值段,用8个16进制对应,对应到数字位数是4位。此时查看Oracle情况。SQL> select CHECKPOINT_CHANGE#, current_scn from v$database;CHECKPOINT_CHANGE# CURRENT_SCN------------------ -----------         1753982   1800400SQL> select dbms_flashback.get_system_change_number from dual;GET_SYSTEM_CHANGE_NUMBER------------------------               1800402SQL> select file#, checkpoint_change# from v$datafile;   FILE# CHECKPOINT_CHANGE#---------- ------------------       1            1753982       2            1753982       3            1753982       4            1753982       5            1753982       6            1753982       7            17539827 rows selectedSQL> select file#, checkpoint_change# from v$datafile_header;   FILE# CHECKPOINT_CHANGE#---------- ------------------       1            1753982       2            1753982       3            1753982       4            1753982       5            1753982       6            1753982       7            17539827 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            18004227 rows selectedSQL> select file#, checkpoint_change# from v$datafile_header;   FILE# CHECKPOINT_CHANGE#---------- ------------------       1            1800422       2            1800422       3            1800422       4            1800422       5            1800422       6            1800422       7            18004227 rows selectedSQL> select CHECKPOINT_CHANGE#, current_scn from v$database;CHECKPOINT_CHANGE# CURRENT_SCN------------------ -----------         1800422   1800433此时,关闭重启系统也不会有问题。篇幅原因,不进行具体展示。那么,很多时候SCN错误是会影响到开启数据库的,我们可能都不能进入open状态。从mount状态下我们怎么修改SCN编号。3、Mount状态修改SCN编号我们测试进入mount状态。SQL> startup mountORACLE instance started.Total System Global Area 3540881408 bytesFixed Size                  2258320 bytesVariable Size           855640688 bytesDatabase Buffers       2667577344 bytesRedo Buffers             15405056 bytesDatabase mounted.此时,oradebug命令导出内存取值。SQL> oradebug setmypidStatement 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            18009207 rows selectedSQL> select file#, checkpoint_change# from v$datafile_header;   FILE# CHECKPOINT_CHANGE#---------- ------------------       1            1800920       2            1800920       3            1800920       4            1800920       5            1800920       6            1800920       7            18009207 rows selectedSQL> 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 00000000SQL> oradebug poke 0x06001AE70 4 0x001B7AD8BEFORE: [06001AE70, 06001AE74) = 00000000AFTER:  [06001AE70, 06001AE74) = 001B7AD8SQL> oradebug poke 0x06001AE74 4 0x00000001BEFORE: [06001AE74, 06001AE78) = 00000000AFTER:  [06001AE74, 06001AE78) = 00000001SQL> 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  4296768485SQL> select file#, checkpoint_change# from v$datafile_header;   FILE# CHECKPOINT_CHANGE#---------- ------------------       1       4296768217       2       4296768217       3       4296768217       4       4296768217       5       4296768217       6       4296768217       7       42967682177 rows selectedSQL> select file#, checkpoint_change# from v$datafile;   FILE# CHECKPOINT_CHANGE#---------- ------------------       1       4296768217       2       4296768217       3       4296768217       4       4296768217       5       4296768217       6       4296768217       7       42967682177 rows selected显然在open的时候,写入的checkpoint在所有文件中。写入的wrap头也比较清晰。SQL> select 4296768217/(4*1024*1024*1024) from dual;4296768217/(4*1024*1024*1024)-----------------------------              1.0004193095956SQL> oradebug DUMPvar SGA kcsgscn_kcslf kcsgscn_ [06001AE70, 06001AEA0) = 001B7C1D 00000001 00000000 00000000 00000047 00000000 00000000 00000000 00000000 00000000 6001AB50 000000004、结论使用oradebug直接修改内存SCN,是我们在故障修复时候非常快捷的方法。不过,快捷建立在对内部机制清晰理解的前提之下。所以,无论何种场景进行修复,有备份、可恢复是我们工作的基本前提。更多Oracle相关信息见Oracle 专题页面 http://www.linuxidc.com/topicnews.aspx?tid=12本文永久更新链接地址