浅析Oracle数据恢复操作

时间:2023-01-12 03:39:07

以下是我看见的两篇文章,我觉的不错在此装载下,希望对你有用哈!!

1. 恢复delete掉的表中数据

select * from sys.smon_scn_time t order by t.time_dpdesc; 
--scn与时间的对应关系 
每隔5分钟,系统产生一次系统时间标记与scn的匹配并存入sys.smon_scn_time表。 
select * from ow_admin_organizationsas of scn 18867092846 
就可以看到在这个检查点的表的历史情况。 
然后我们恢复到这个检查点 
insert intoow_admin_organizations
    select * fromow_admin_organizations as of scn 18867092846
    where id not in (select org_key from ow_admin_organizations)
---------------------------------------------------------------------------------------
第一步,先应记住被删除的表中有多少记录
select count(*) from t1;
第二步,delete该表的数据
delete from t1;
commnit;
第三步,获得当前scn
selectdbms_flashback.get_system_change_number from dual;
第四步,根据第三步返回的scn不停地尝试查询直到所有记录都存在为止。
select count(*) from t1 as of scn10670000;--10670000为返回的scn
第五步,当第四步返回的值为所删除的记录数时执行
insert into t1 select * from t1 asof scn 10670000;
commite;
到此有的网友对我之前写的一篇技术博文中的描述提出了疑问,http://blog.itpub.net/23718752/viewspace-1436965/
其中的主要意思是:oracle中采用了undo+redo机制来作为数据恢复的基石,数据的恢复是通过前后台结合来实现的,在缓存级别,通过dbwr,能够把修改后的数据块刷入数据文件,这是一个异步的过程,不会因为发生数据变更就马上写入数据文件,同时存在log buffer,能够通过log buffer生成redo日志,最后通过lgwr把这部分变更刷到redo 日志,在这个过程中lgwr负责了保持数据完整性的任务,保证了数据不会丢失。
这句话再浓缩一下就是Oracle能够保证对于commit操作的数据都能够成功恢复。
今天可以通过两个特殊的场景来解释一下。
场景1:模拟Oracle ACID的异常情况,事务已经提交,但是redo log buffer还没有写到磁盘
第一个场景就是把lgwr写入redo的操作影响放大,操作时间延长。这个可以参考Jonathan Lewis的博客。https://jonathanlewis.wordpress.com/2011/08/19/redo-2/
这个场景被称为模拟Oracle ACID的异常情况,事务已经提交,但是redo log buffer还没有写到磁盘.我们来看看再下结论。
window #1: --打开一个窗口1,然后创建一个临时表t1
create table t1(n1 number);
insert into t1 values(1);
commit;

然后通过v$process查到对应的LGWR pid
n1@TEST11G>  select v$process.pid  from v$process  where pname='LGWR';
       PID
----------
        11

window #2 --打开窗口2,开启oradebug,绑定到lgwr上
sys@TEST11G> oradebug setorapid 11
Oracle pid: 11, Unix process pid: 11767, image: oracle@oel1 (LGWR)
sys@TEST11G>oradebug suspend 
Statement processed.

window #1--然后回到窗口1,做一个dml操作,commit
n1@TEST11G> update t1 set n1 = 2;
1 row updated.
n1@TEST11G> commit;

这个时候commit操作会一直hang在那儿


window #3  --开启第3个窗口,然后查看是否更新后的值已经可以成功查看。
sys@TEST11G> select count(*)from n1.t1;
  COUNT(*)
----------
         2
1 row selected. 

这个时候我们马上做类似断电的场景,shutdown abort
sys@TEST11G> shutdown abort
ORACLE instance shut down.

这个时候如果观察第一个窗口,会发现下面的错误,可以得知对应的session已经被强制释放了。
n1@TEST11G> commit;
ERROR:
ORA-03114: not connected to ORACLE
commit
*
ERROR at line 1:
ORA-03113: end-of-file on communication channel
Process ID: 15180
Session ID: 125 Serial number: 84

然后我们重启数据库
idle> startup
ORACLE instance started.
Total System Global Area  435224576 bytes
Fixed Size                  1337044 bytes
Variable Size             272632108 bytes
Database Buffers          155189248 bytes
Redo Buffers                6066176 bytes
Database mounted.
Database opened.

这个时候再查看数据,就会发现更新后的值已经丢失了。
idle> select *from n1.t1;
        N1
----------
         1
1 row selected.
对于这个问题,网上大家也是各有所见,有的说commit没有成功返回,就不算是一个完整的事务,没有恢复是可以理解的。有的说,这个是Oracle对于数据恢复的一个灰色地带。
我的意见是首先这是一个测试,把整个过程放慢,影响放大了,整个过程处于一个快要提交但是还没有提交的边界。这部分内容还是没有写入redo中的。只是从缓存中完成了整个数据变更的过程。
commit在这个放慢的临界点没有完成,严格意义上应该不属于一个完整的事务。

上面这个案例是通过debug的方式来做的,我们来用另外一个场景来模拟一下,看看实际中可能碰到的场景如果出现类似问题,redo是否依旧可靠。

场景2:模拟Oracle 归档满的临界点,事务是否依然能够成功提交,成功恢复
我们来模拟在归档日志满的时候,无法再写入redo,依旧可以成功commit,但是数据是否能够成功恢复的案例。
我们在测试环境简单模拟一下归档满的临界点,查看磁盘空间,归档所在的挂载点还有6G的可用空间。
[ora11g@oel1 archivelog]$ df -h
Filesystem            Size  Used Avail Use% Mounted on
/dev/sda3              30G   23G  6.0G  79% /u02
none                  690M  104K  690M   1% /var/lib/xenstored

我们来使用dd来创建一些dummy文件。
[ora11g@oel1 archivelog]$ time dd if=/dev/zero bs=1M count=5000 of=direct_5000M
5000+0 records in
5000+0 records out
5242880000 bytes (5.2 GB) copied, 224.21 seconds, 23.4 MB/s
real    3m44.222s
user    0m0.024s
sys     0m20.317s
创建后再逐步缩小范围。
[ora11g@oel1 archivelog]$ time dd if=/dev/zero bs=1M count=1000 of=direct_1000M
[ora11g@oel1 archivelog]$ time dd if=/dev/zero bs=1M count=100 of=direct_100M
最后发现空间都被占用完了。
[ora11g@oel1 archivelog]$ df -h
Filesystem            Size  Used Avail Use% Mounted on
/dev/sda3              30G   29G     0 100% /u02
直到没有空间可用我们才收手。
[ora11g@oel1 archivelog]$ time dd if=/dev/zero bs=1M count=10 of=direct_10M
dd: writing `direct_10M': No space left on device
1+0 records in
0+0 records out
0 bytes (0 B) copied, 0.000909 seconds, 0.0 kB/s
最后生成的dd文件如下:
-rw-r----- 1 ora11g dba   33485824 May 20 15:30 1_4_879784710.dbf
-rw-r--r-- 1 ora11g dba 5242880000 May 20 15:36 direct_5000M
-rw-r--r-- 1 ora11g dba 1048576000 May 20 15:37 direct_1000M
-rw-r--r-- 1 ora11g dba  104603648 May 20 15:38 direct_100M
-rw-r--r-- 1 ora11g dba           0 May 20 15:39 direct_10M

使用sqlplus报出下面的错误,这样我们就可以开始这个临界点的测试了。
sys@TEST11G> conn n1/n1
ERROR:
ORA-00257: archiver error. Connect internal only, until freed.
sys@TEST11G> create table aa as select *from cat;
Table created.
sys@TEST11G> insert into aa select *from aa;
4856 rows created.
sys@TEST11G> commit;
Commit complete.
sys@TEST11G> insert into aa select *from aa;
9712 rows created.
sys@TEST11G> commit;
Commit complete.
sys@TEST11G> select count(*)from aa;
  COUNT(*)
----------
     19424

可以看到这个过程中还是能够成功commit数据的。查取更新都可以使用顺利完成。
可以再开一个窗口运行alter system switch logfile做几个日志刷新。发现这个时候日志刷新也hang住了。

看看alert日志,发现已经提示空间不够,无法生成归档日志了。
Wed May 20 15:43:59 2015
Errors in file /u02/ora11g/diag/rdbms/test11g/TEST11G/trace/TEST11G_arc1_13247.trc:
ORA-19504: failed to create file "/u02/ora11g/flash_recovery_area/TEST11G/archivelog/1_5_879784710.dbf"
ORA-27044: unable to write the header block of file
Linux Error: 28: No space left on device
Additional information: 3
ARC1: Error 19504 Creating archive log file to '/u02/ora11g/flash_recovery_area/TEST11G/archivelog/1_5_879784710.dbf'
ARCH: Archival stopped, error occurred. Will continue retrying
Non critical error ORA-00001 caught while writing to trace file "/u02/ora11g/diag/rdbms/test11g/TEST11G/trace/TEST11G_arc1_13247.trc"
Error message: 
Writing to the above trace file is disabled for now on...
ORACLE Instance TEST11G - 

这个时候我们继续模拟一个断电场景shutdown abort.
原有的日志刷新也会自动终止。
ERROR:
ORA-03114: not connected to ORACLE
alter system switch logfile
*
ERROR at line 1:
ORA-03113: end-of-file on communication channel
Process ID: 9686
Session ID: 125 Serial number: 480

如果这个时候启动到open阶段就会自动停止,原因就是归档空间的问题。
我们做一个小改动。腾出一小部分空间来。
[ora11g@oel1 archivelog]$ rm direct_100M
然后再次尝试启动数据库就没有问题了
idle> alter database open;
Database altered.
这个时候查看归档路径下,会发现已经生成了3个归档文档
-rw-r--r-- 1 ora11g dba 5242880000 May 20 15:36 direct_5000M
-rw-r--r-- 1 ora11g dba 1048576000 May 20 15:37 direct_1000M
-rw-r--r-- 1 ora11g dba          0 May 20 15:39 direct_10M
-rw-r----- 1 ora11g dba       2048 May 20 15:55 1_6_879784710.dbf
-rw-r----- 1 ora11g dba     204800 May 20 15:55 1_5_879784710.dbf
-rw-r----- 1 ora11g dba    1808384 May 20 15:55 1_7_879784710.dbf
这个时候发现对于这些信息变更已经成功刷新到了归档中。这样就为数据恢复提供了强有力的基石,保证了数据在commit成功的情况下能够成功恢复。
网站建设数据恢复完毕!

2. 恢复drop掉的表
 
Oracle闪回特性 收藏 
Oracle闪回特性
在利用闪回功能前需要确认:
1、用户有对dbms_flashback包有执行权限!
2、进行闪回网站建设查询必须设置自动回滚段管理,在init.ora设置参数UNDO_MANAGEMENT=AUTO,参数UNDO_RETENTION=n,决定了能往前闪回的最大时间,值越大就需要越多Undo空间。
 
Oracle 9i中闪回查询操作实例
 
查看Oracle中Delete和Commit操作的流程分析
  
例:Oracle 9i的Flashback Query操作。
(1)创建闪回查询用户
SQL> create user test identified by test;
SQL> grant connect, resource to test;
SQL> grant execute on dbms_flashback to test;
SQL> connect test/test;
 
(2)创建测试表,插入测试记录
SQL> create table test(id number(3));
SQL> insert into test values(1);
SQL> insert into test values(2);
SQL> commit;   
 
注意:在执行步骤3或者步骤4之前,等待5分钟。
 
(3)删除记录
SQL> delete from test where id=1;
SQL> commit;
 
   通过以上的操作,我们插入了两条记录,并删除了其中一条记录。在以下APP开发的操作中,我们将通过flashbackquery找到删除的网页设计记录
 
(4)闪回查询(分别通过timestamp和scn查询)
SQL> select * from test as of timestamp sysdate - 5/1440;
ID
----
1
2

SQL> select * from test as of scn 8173800;
ID
----
1
     可以看出,虽然删除记录并提交,但是通过闪回网页制作操作,仍能查询到删除前网站制作的两条记录。需要注意Oracle每5分钟记录一次SCN到SMON_SCN_TIME,并将SCN和对应时间的映射进行纪录。如果原来插入的网站制作公司记录到做闪回操作的时间在5分钟之内,用基于时间的闪回查询可能得不到记录,因为基于时间点的查询实际上是转化为最近的一次SCN,然后从这个SCN开始进行恢复。因此,如果需要精确的查询可以采用基于SCN的闪回查询,可精确闪回到需要恢复的时间。可以通过DBMS_FLASHBACK.GET_SYSTEM_CHANGE_NUMBER语句获取SCN。
 
5、恢复被删除的数据实例
SQL>insert into test select * from test as of scn 8173800 whereid=1;
 
Oracle 10g中闪回查询企业网站建设操作实例
 
        与Oracle 9i相比Oracle 10g的Flashback有了非常大的改进,在Orcle10g之前,SMON_SCN_TIME由SMON来获取和记录信息的,每5分钟记录一次,从Oracle10g开始,LGWR首先会在SGA中记录SCN与时间的映射关系(由于LGWR至少每3秒就会被激活一次,所以现在SMON_SCN_TIME能够支持大于3秒的闪回),SMON则定期检查SGA是否内存中的映射大于磁盘上的,如果有就刷新纪录到磁盘,而且从普通的Flashback Query发展到了网站建设公司多种形式,主要表现在如下几方面新特性:
 
1、Flashback Database
  Oracle Flashback Database特性允许通过SQL语句FlashbackDatabase语句,让数据库前滚到当前的前一个时间点或者SCN,而不需要做时间点的恢复。闪回数据库可以迅速将数据库回到误操作或人为错误的前一个时间点,如Word中的"撤消"操作,可以不利用备份就快速的实现基于时间点的恢复。Oracle通过创建新的FlashbackLogs(闪回日志),记录数据库的做网站闪回操作。
如果希望能闪回数据库,需要设置如下参数:
DB_RECOVER_FILE_DEST 
        --日志的存放位置,
DB_RECOVER_FILE_DEST_SIZ 
--E恢复区的大小
在创建数据库的时候,Oracle将自动创建
建网站 恢复区,但默认是关闭的,需要执行alter database flashbackon命令。
 
   
执行Flashback Database命令格式:
SQL>flashback database to time to_timestamp(xxx);
SQL>flashback database to scn xxx
 
数据库的闪回状态可以从V$database视图中查询得到:
SQL> select dbid,name,flashback_on,current_scn fromv$database;
DBID                        NAME            FLASHBACK_ON CURRENT_SCN
----------              ---------          ------------------            -----------
1692001961  ACF                  NO                                                8175168
 
一个数据库级闪回的例子:     
SQL> shutdown immediate;
数据库已经关闭。
已经卸载数据库。
ORACLE 例程已经关闭。
SQL> startup mount
ORACLE 例程已经启动。
Total System Global Area 1719664640 bytes
Fixed Size 1251896 bytes
Variable Size 293602760 bytes
Database Buffers 1417674752 bytes
Redo Buffers 7135232 bytes
数据库装载完毕。
SQL> alter database flashback on;
数据库已更改。网站设计
SQL> alter database open;
数据库已更改。
SQL> select dbid,name,flashback_on,current_scn fromv$database;
DBID NAME FLASHBACK_ON CURRENT_SCN
---------- --------- ------------------ -----------
1692001961 ACF YES 8175890
SQL> select dbms_flashback.get_system_change_number fromdual;
GET_SYSTEM_CHANGE_NUMBER
------------------------
8175973
SQL> delete from test where id=1;
1 row deleted
SQL> select * from test;
ID
----
2
SQL> shutdown immediate
数据库已经关闭。
已经卸载数据库。
ORACLE 建设网站例程已经关闭。
SQL> startup mount ORACLE 例程已经启动。
Total System Global Area 1719664640 bytes
Fixed Size 1251896 bytes
Variable Size 301991368 bytes
Database Buffers 1409286144 bytes
Redo Buffers 7135232 bytes
数据库装载完毕。
SQL> flashback database to scn 8175973; 闪回完成。
SQL> alter database open resetlogs; 数据库已更改。
SQL> select * from test;
ID
----
2
1 --可以看到,数据已经恢复成功
 
 
2、Flashback Table
  Oracle Flashback Table特性允许利用FlashbackTable语句,确保闪回到表的网站设计公司前一个时间点。与Oracle 9i中的FlashbackQuery相似,利用回滚段信息来恢复一个或一些表到以前的一个时间点(一个快照)。要注意的是,FlashbackTable不等于Flashback Query,FlashbackQuery仅仅是查询以前的一个快照点而已,并不改变当前表的状态,而FlashbackTable将改变当前表及附属对象一起回到以前的设计公司时间点。
 
语法:
alter table table_name enable row movement;
flashback table tablename to timestamp xxx 或
flashback table tablename to scn xxx
 
注意:如果需要闪回一个表,需要以下条件:
·需要有flashback any table的系统权限或者是该表的flashback对象权限;
·需要有该表的select,insert,delete,alter权限;
·必须保证该表row movement。
例:执行将test表闪回到2005年5月7日下午3点。
SQL>flashback table test to timestamp to_timestamp(’2005-05-0715:00:00’,’yyyy-mm-dd hh24:mi:ss’);
 
一个完整的Flashback Table例子
SQL> select * from test;
  ID
----
    2
    1
SQL> select dbms_flashback.get_system_change_number fromdual;
GET_SYSTEM_CHANGE_NUMBER
------------------------
                                8178419
SQL> delete from test where id=1;
1 row deleted
SQL> select * from test;
  ID
----
    2
SQL> alter table test enable row movement;
Table altered
SQL> flashback table test to scn 8178419;
Done
SQL> select * from test;
  ID
----
    2
    1
 
3、Flashback Drop
  Oracle Flashback Drop特性提供一个类似回收站的功能,用来恢复不小心被删除网络营销的表。当删除表时,Oracle10g并不立刻释放被删除的表所占用的空间,而是将这个被删除的表进行自动重命名(为了避免同类对象名称的重复)并放进回收站中。所谓的回收站类似于Windows系统中的回收站,是一个虚拟的容器,用于存放所有被删除的对象,在回收站中被删除网络推广的对象将占用创建时的同样的空间。如果这个被删除的表需要进行恢复,就可利用FlashbackDrop功能。
  例:进行一个删除表后恢复的简单测试。
 
(1)显示回收站信息(不要以Sysdba用户查询,否则会把错)
SQL>show recyclebin;
可以看到,回收站中是没有任何结果的,表示没有任何表在回收站中。
 
(2)创建一个表,并删除,再次显示回收站信息
SQL>create table test_drop(name varchar2(10));
SQL>drop table test_drop;
SQL>show recyclebin;
ORIGINAL NAME RECYCLEBIN NAME OBJECT TYPE DROP TIME
TEST_DROP BIN$b+XkkO1RS5K10uKo9BfmuA==$0 TABLE2005-05-07:14:30:47
 
 
(3)对被删除的表进行恢复
SQL>flashback table test_drop to before drop;或
SQL>flashback table "BIN$b+XkkO1RS5K10uKo9BfmuA==$0" to beforedrop;
 
 
(4)管理回收站
清除回收站中的单个表:purge table test_drop
清除整个回收站:purge recyclebin
清除不同的对象回收站:purge user_recyclebin或purge dba_recyclebin
注意:需要注意的是sysdba的drop操作不会被记录,Oracle也从不推荐用户使用sysdba身份创建用户对象
  
(5)确认删除一个表
SQL>drop table test_drop purge;
如果删除一个网络优化表且不放到回收站中不能进行恢复,在drop语句中可以利用purge选项。
 
(6)可以通过参数禁用或启用recyclebin这个特性
在Oracle 10gR1中,通过修改一个隐含_recyclebin为False可以禁用这个特性,在Oracle10gR2中,recyclebin变成了一个常规参数,可以在session/system级动态修改 :
SQL> show parameter recyclebin
NAME                                                                TYPE              VALUE
------------------------------------ ----------- ------
recyclebin 
                                                  string          on
SQL> alter session set recyclebin=off;
会话已更改。
SQL> alter session set recyclebin=on;
会话已更改。
SQL> alter system set recyclebin=off;
系统已更改。
SQL> alter system set recyclebin=on;
系统已更改。
 
4、Flash Version Query
          Oracle Flashback VersionQuery特性,利用保存的回滚信息,可以看到特定的表在时间段内的任何修改,如电影的回放一样,可以了解表在该期间的任何变化。Flashbackversionquery一样依赖于AUM,提供了一个查看行改变的功能,能找到所有已经提交了的行的记录,分析出过去时间都执行了什么操作。
 
Flashback version query采用VERSIONS BETWEEN语句来进行查询,常用的方法:
·VERSIONS_SCN - 系统改变号
·VERSIONS_TIMESTAMP - 时间
 
例如:在test表中,时间1插入一条记录,时间2删除了网站推广这条记录,对于时间3执行select * fromtest当然查询不到这条记录,只能看到该表最后的提交记录。这时如果利用Flash Table或者是FlashQuery,只能看到过去的某一时间点的一个快照,而利用Flashback VersionQuery,能够把时间1、时间2的操作给记录下来,并详细的查询出对表进行的任何操作。
 
SQL>select versions_starttime,versions_endtime,versions_xid,versions_operation,id 
from test versions 
between timestamp minvalue and maxvalue 
order by versions_starttime;
  
在上述查询中,列versions_starttime、versions_endtime、versions_xid、versions_operation是伪列,还有一些伪列,如
versions_startscn和versions_endscn显示了该时刻的系统更改号。列versions_xid显示了更改该行的网站推广事务标识符。
  当然,除了分析以上所有的变更之外,可以根据需要指定时间段,如显示在2005-05-07时间在15:30到16:30之间test表的所有变更。
 
SQL>select id from test 
versions between timestampto_date(’2005-05-07 15:30:00’,’yyyy-mm-dd hh24:mi:ss’) andto_date(’2005-05-07 16:30:00’,’
yyyy-mm-dd hh24:mi:ss’)
 
5、Flashback Transaction Query
  Oracle Flashback TransactionQuery特性确保检查数据库的任何改变在一个事务级别,可以利用此功能进行诊断问题、性能分析和审计
事务。它其实是Flashback Version Query查询的一个扩充,Flashback VersionQuery说明了可以审计一段时间内表的所有改变,但是也仅仅
是能发现问题,对于错误的事务,没有好的处理办法。而Flashback TransactionQuery提供了从FLASHBACK_TRANSACTION_QUERY视图中获得事
务的历史以及Undo_sql(回滚事务对应的sql语句),也就是说审计一个事务到底做了什么,网站运营甚至可以回滚一个已经提交的事务。
例:Flashback Transaction Query的操作实例。
(1)在test表中删除记录,获得事务的标识XID,然后提交。
SQL>delete from test where id=2;
SQL>select xid from v$transaction;
XID
----------------
04001200AE010000
SQL>commit;
  在测试中方便起见,在事务没有提交的时候,获得事务的XID为04001F0035000000。实际情况下,不可能去跟踪每个事务,想要获得已提交事务的XID,就必须通过上面的FlashbackVersion Query。
 
(2)进行Flashback Transaction Query
SQL>select * from FLASHBACK_TRANSACTION_QUERY
where xid=’04001F0035000000’;

UNDO_SQL
insert into "test"."TEST"("ID") values (’2’);
  注意:这个删除语句对应的是1个Insert语句,如果想回滚这个事务,执行这个Insert语句即可。
  可以看到,Flashback TransactionQuery主要用于审计一个事务,并可以回滚一个已经提交的事务。如果确定出错的事务是最后一个事务,我们利用FlashbackTable或者FlashbackQuery就可以解决问题。但是,如果执行了一个错误的事务之后,又执行了一系列正确的事务,那么上面的方法就无能为力,利用FlashbackTransaction Query可以查看或回滚这个错误的事务。
有的网友对我之前写的一篇技术博文中的描述提出了疑问,http://blog.itpub.net/23718752/viewspace-1436965/
其中的主要意思是:oracle中采用了undo+redo机制来作为数据恢复的基石,数据的恢复是通过前后台结合来实现的,在缓存级别,通过dbwr,能够把修改后的数据块刷入数据文件,这是一个异步的过程,不会因为发生数据变更就马上写入数据文件,同时存在log buffer,能够通过log buffer生成redo日志,最后通过lgwr把这部分变更刷到redo 日志,在这个过程中lgwr负责了保持数据完整性的任务,保证了数据不会丢失。
这句话再浓缩一下就是Oracle能够保证对于commit操作的数据都能够成功恢复。
今天可以通过两个特殊的场景来解释一下。
场景1:模拟Oracle ACID的异常情况,事务已经提交,但是redo log buffer还没有写到磁盘
第一个场景就是把lgwr写入redo的操作影响放大,操作时间延长。这个可以参考Jonathan Lewis的博客。https://jonathanlewis.wordpress.com/2011/08/19/redo-2/
这个场景被称为模拟Oracle ACID的异常情况,事务已经提交,但是redo log buffer还没有写到磁盘.我们来看看再下结论。
window #1: --打开一个窗口1,然后创建一个临时表t1
create table t1(n1 number);
insert into t1 values(1);
commit;

然后通过v$process查到对应的LGWR pid
n1@TEST11G>  select v$process.pid  from v$process  where pname='LGWR';
       PID
----------
        11

window #2 --打开窗口2,开启oradebug,绑定到lgwr上
sys@TEST11G> oradebug setorapid 11
Oracle pid: 11, Unix process pid: 11767, image: oracle@oel1 (LGWR)
sys@TEST11G>oradebug suspend 
Statement processed.

window #1--然后回到窗口1,做一个dml操作,commit
n1@TEST11G> update t1 set n1 = 2;
1 row updated.
n1@TEST11G> commit;

这个时候commit操作会一直hang在那儿


window #3  --开启第3个窗口,然后查看是否更新后的值已经可以成功查看。
sys@TEST11G> select count(*)from n1.t1;
  COUNT(*)
----------
         2
1 row selected. 

这个时候我们马上做类似断电的场景,shutdown abort
sys@TEST11G> shutdown abort
ORACLE instance shut down.

这个时候如果观察第一个窗口,会发现下面的错误,可以得知对应的session已经被强制释放了。
n1@TEST11G> commit;
ERROR:
ORA-03114: not connected to ORACLE
commit
*
ERROR at line 1:
ORA-03113: end-of-file on communication channel
Process ID: 15180
Session ID: 125 Serial number: 84

然后我们重启数据库
idle> startup
ORACLE instance started.
Total System Global Area  435224576 bytes
Fixed Size                  1337044 bytes
Variable Size             272632108 bytes
Database Buffers          155189248 bytes
Redo Buffers                6066176 bytes
Database mounted.
Database opened.

这个时候再查看数据,就会发现更新后的值已经丢失了。
idle> select *from n1.t1;
        N1
----------
         1
1 row selected.
对于这个问题,网上大家也是各有所见,有的说commit没有成功返回,就不算是一个完整的事务,没有恢复是可以理解的。有的说,这个是Oracle对于数据恢复的一个灰色地带。
我的意见是首先这是一个测试,把整个过程放慢,影响放大了,整个过程处于一个快要提交但是还没有提交的边界。这部分内容还是没有写入redo中的。只是从缓存中完成了整个数据变更的过程。
commit在这个放慢的临界点没有完成,严格意义上应该不属于一个完整的事务。

上面这个案例是通过debug的方式来做的,我们来用另外一个场景来模拟一下,看看实际中可能碰到的场景如果出现类似问题,redo是否依旧可靠。

场景2:模拟Oracle 归档满的临界点,事务是否依然能够成功提交,成功恢复
我们来模拟在归档日志满的时候,无法再写入redo,依旧可以成功commit,但是数据是否能够成功恢复的案例。
我们在测试环境简单模拟一下归档满的临界点,查看磁盘空间,归档所在的挂载点还有6G的可用空间。
[ora11g@oel1 archivelog]$ df -h
Filesystem            Size  Used Avail Use% Mounted on
/dev/sda3              30G   23G  6.0G  79% /u02
none                  690M  104K  690M   1% /var/lib/xenstored

我们来使用dd来创建一些dummy文件。
[ora11g@oel1 archivelog]$ time dd if=/dev/zero bs=1M count=5000 of=direct_5000M
5000+0 records in
5000+0 records out
5242880000 bytes (5.2 GB) copied, 224.21 seconds, 23.4 MB/s
real    3m44.222s
user    0m0.024s
sys     0m20.317s
创建后再逐步缩小范围。
[ora11g@oel1 archivelog]$ time dd if=/dev/zero bs=1M count=1000 of=direct_1000M
[ora11g@oel1 archivelog]$ time dd if=/dev/zero bs=1M count=100 of=direct_100M
最后发现空间都被占用完了。
[ora11g@oel1 archivelog]$ df -h
Filesystem            Size  Used Avail Use% Mounted on
/dev/sda3              30G   29G     0 100% /u02
直到没有空间可用我们才收手。
[ora11g@oel1 archivelog]$ time dd if=/dev/zero bs=1M count=10 of=direct_10M
dd: writing `direct_10M': No space left on device
1+0 records in
0+0 records out
0 bytes (0 B) copied, 0.000909 seconds, 0.0 kB/s
最后生成的dd文件如下:
-rw-r----- 1 ora11g dba   33485824 May 20 15:30 1_4_879784710.dbf
-rw-r--r-- 1 ora11g dba 5242880000 May 20 15:36 direct_5000M
-rw-r--r-- 1 ora11g dba 1048576000 May 20 15:37 direct_1000M
-rw-r--r-- 1 ora11g dba  104603648 May 20 15:38 direct_100M
-rw-r--r-- 1 ora11g dba          0 May 20 15:39 direct_10M

使用sqlplus报出下面的错误,这样我们就可以开始这个临界点的测试了。
sys@TEST11G> conn n1/n1
ERROR:
ORA-00257: archiver error. Connect internal only, until freed.
sys@TEST11G> create table aa as select *from cat;
Table created.
sys@TEST11G> insert into aa select *from aa;
4856 rows created.
sys@TEST11G> commit;
Commit complete.
sys@TEST11G> insert into aa select *from aa;
9712 rows created.
sys@TEST11G> commit;
Commit complete.
sys@TEST11G> select count(*)from aa;
  COUNT(*)
----------
     19424

可以看到这个过程中还是能够成功commit数据的。查取更新都可以使用顺利完成。
可以再开一个窗口运行alter system switch logfile做几个日志刷新。发现这个时候日志刷新也hang住了。

看看alert日志,发现已经提示空间不够,无法生成归档日志了。
Wed May 20 15:43:59 2015
Errors in file /u02/ora11g/diag/rdbms/test11g/TEST11G/trace/TEST11G_arc1_13247.trc:
ORA-19504: failed to create file "/u02/ora11g/flash_recovery_area/TEST11G/archivelog/1_5_879784710.dbf"
ORA-27044: unable to write the header block of file
Linux Error: 28: No space left on device
Additional information: 3
ARC1: Error 19504 Creating archive log file to '/u02/ora11g/flash_recovery_area/TEST11G/archivelog/1_5_879784710.dbf'
ARCH: Archival stopped, error occurred. Will continue retrying
Non critical error ORA-00001 caught while writing to trace file "/u02/ora11g/diag/rdbms/test11g/TEST11G/trace/TEST11G_arc1_13247.trc"
Error message: 
Writing to the above trace file is disabled for now on...
ORACLE Instance TEST11G - 

这个时候我们继续模拟一个断电场景shutdown abort.
原有的日志刷新也会自动终止。
ERROR:
ORA-03114: not connected to ORACLE
alter system switch logfile
*
ERROR at line 1:
ORA-03113: end-of-file on communication channel
Process ID: 9686
Session ID: 125 Serial number: 480

如果这个时候启动到open阶段就会自动停止,原因就是归档空间的问题。
我们做一个小改动。腾出一小部分空间来。
[ora11g@oel1 archivelog]$ rm direct_100M
然后再次尝试启动数据库就没有问题了
idle> alter database open;
Database altered.
这个时候查看归档路径下,会发现已经生成了3个归档文档
-rw-r--r-- 1 ora11g dba 5242880000 May 20 15:36 direct_5000M
-rw-r--r-- 1 ora11g dba 1048576000 May 20 15:37 direct_1000M
-rw-r--r-- 1 ora11g dba          0 May 20 15:39 direct_10M
-rw-r----- 1 ora11g dba       2048 May 20 15:55 1_6_879784710.dbf
-rw-r----- 1 ora11g dba     204800 May 20 15:55 1_5_879784710.dbf
-rw-r----- 1 ora11g dba    1808384 May 20 15:55 1_7_879784710.dbf
这个时候发现对于这些信息变更已经成功刷新到了归档中。这样就为数据恢复提供了强有力的基石,保证了数据在commit成功的情况下能够成功恢复。