Oracle检索数据一致性与事务恢复(转)

在Oracle数据库中,undo主要有三大作用:提供一致性读(Consistent Read)、回滚事务(Rollback Transaction)以及实例恢复(Instance Recovery)。  
      一致性读是相对于脏读(Dirty Read)而言的。假设某个表T中有10000条记录,获取所有记录需要15分钟时间。当前时间为9点整,某用户A发出一条查询语句:select * from T,该语句在9点15分时执行完毕。当用户A执行该SQL语句到9点10分的时候,另外一个用户B发出了一条delete命令,将T表中的最后一条记录删除并提交了。  
那么到9点15分时,A用户将返回多少条记录?  
如果返回9999条记录,则说明发生了脏读;如果仍然返回10000条记录,则说明发生了一致性读。很明显,在9点钟那个时间点发出查询语句时,表T中确实有10000条记录,只不过由于I/O的相对较慢,所以才会花15分钟完成所有记录的检索。对于Oracle数据库来说,没有办法实现脏读,必须提供一致性读,并且该一致性读是在没有阻塞用户的DML的前提下实现的。  
那么undo数据是如何实现一致性读的呢?还是针对上面的例子。用户A在9点发出查询语句时,服务器进程会将9点那个时间点上的SCN号记录下来,假设该SCN号为SCN9.00。那么9点整的时刻的SCN9.00一定大于等于记录在所有数据块头部的ITL槽中的SCN号(如果有多个ITL槽,则为其中最大的那个SCN号)。  
服务器进程在扫描表T的数据块时,会把扫描到的数据块头部的ITL槽中的SCN号与SCN9:00之间进行比较,哪个更大。如果数据块头部的SCN号比SCN9.00要小,则说明该数据块在9点以后没有被更新,可以直接读取其中的数据;否则,如果数据块ITL槽的SCN号比SCN9.00要大,则说明该数据块在9点以后被更新了,该块里的数据已经不是9点那个时间点的数据了,于是要借助undo块。  
9点10分,B用户更新了表T的最后一条记录并提交(注意,在这里,提交或者不提交并不是关键,只要用户B更新了表T,用户A就会去读undo数据块)。假设被更新记录属于N号数据块。那么这个时候N号数据块头部的ITL槽的SCN号就被改为SCN9.10。当服务器进程扫描到被更新的数据块(也就是N号块)时,发现其ITL槽中的SCN9.10大于发出查询时的SCN9.00,说明该数据块在9点以后被更新了。于是服务器进程到N号块的头部,找到SCN9.10所在的ITL槽。由于ITL槽中记录了对应的undo块的地址,于是根据该地址找到undo块,将undo块中的被修改前的数据取出,再结合N号块里的数据行,从而构建出9点10分被更新之前的那个时间点的数据块内容,这样的数据块叫做CR块(Consistent Read)。对于delete来说,其undo信息就是insert,也就是说该构建出来的CR块中就插入了被删除的那条记录。随后,服务器进程扫描该CR块,从而返回正确的10000条记录。  
让我们继续把问题复杂化。假设在9点10分B用户删除了最后一条记录并提交以后,紧跟着9点11分,C用户在同一个数据块里(也就是N号块)插入了2条记录。这个时候Oracle又是如何实现一致性读的呢(假设表T的initrans为1,也就是只有一个ITL槽)?因为我们已经知道,事务需要使用ITL槽,只要该事务提交或回滚,该ITL槽就能够被重用。换句话说,该ITL槽里记录的已经是SCN9.11,而不是SCN9.10了。这时,ITL槽被覆盖了,Oracle的服务器进程又怎能找回最初的数据呢?

其中的秘密就在于,Oracle在记录undo数据的时候,不仅记录了改变前的数据,还记录了改变前的数据所在的数据块头部的ITL信息。因此,9点10分B用户删除记录时(位于N号块里,并假设该N号块的ITL信息为[Undo_block0 / SCN8.50]),则Oracle会将改变前的数据(也就是insert)放到undo块(假设该undo块地址为Undo_block1)里,同时在该undo块里记录删除前ITL槽的信息(也就是[Undo_block0 / SCN8.50])。删除记录以后,该N号块的ITL信息变为 [Undo_block1 / SCN9.10];到了9点11分,C用户又在N号块里插入了两条记录,则Oracle将插入前的数据(也就是delete两条记录)放到undo块(假设该undo块的地址为Undo_block2)里,并将9点11分时的ITL槽的信息(也就是[Undo_block1 / SCN9.10])也记录到该undo块里。插入两条记录以后,该N号块的ITL槽的信息改为 [Undo_block2 / SCN9.11]。 
那么当执行查询的服务器进程扫描到N号块时,发现SCN9.11大于SCN9.00,于是到ITL槽中指定的Undo_block2处找到该undo块。发现该undo块里记录的ITL信息为[Undo_block1 / SCN9.10],其中的SCN9.10仍然大于SCN9.00,于是服务器进程继续根据ITL中记录的Undo_block1,找到该undo块。发现该undo块里记录的ITL信息为[Undo_block0 / SCN8.50],这时ITL里的SCN8.50小于发出查询时的SCN9.00,说明这时undo块包含合适的undo信息,于是服务器进程不再找下去,而是将N号块、Undo_block2以及Undo_block1的数据结合起来,构建CR块。将当前N号的数据复制到CR块里,然后在CR块里先回退9点11分的事务,也就是在CR块里删除两条记录,然后再回退9点10分的事务,也就是在CR块里插入被删除的记录,从而构建出9点钟时的数据。Oracle就是这样,以层层嵌套的方式,查找整个undo块的链表,直到发现ITL槽里的SCN号小于等于发出查询时的那个SCN号为止。正常来说,当前undo块里记录的SCN号要比上一个undo块里记录的SCN号要小。 但是在查找的过程中,可能会发现当前undo块里记录的ITL槽的SCN号比上一个undo块里记录的SCN号还要大。这种情况说明由于事务被提交或回滚,导致当前找到的undo块里的数据已经被其他事务覆盖了,于是我们无法再找出小于等于发出查询时的那个时间点的SCN号,这时Oracle就会抛出一个非常经典的错误——ORA-1555,也就是snapshot too old的错误。

Oracle为了保证用户检索数据的一致性, 通过UNDO记录,当用户检索数据库数据时,Oracle总是使用户只能看到被提交过的数据或特定时间点的数据(select语句时间点),UNDO记录会被存放到回滚段中,假如该数据未提交,用户检索数据时,都是从UNDO记录中取得的.(如下图:)

1. ORACLE检索数据一致性

先打开一个SecureCRT.(第一个session)

先建一个表

  1. SQL> create table c(a int);
  2. Table created.
  3. SQL> alter table c add b number;
  4. Table altered.
  5. SQL> desc c
  6. Name                                      Null?    Type
  7. ----------------------------------------- -------- --------------------------------------------
  8. A                                                  NUMBER(38)
  9. B                                                  NUMBER

表中插入数据并提交

  1. SQL> insert into c values(1,2);
  2. 1 row created.
  3. SQL> insert into c values(3,4);
  4. 1 row created.
  5. SQL> select * from c;
  6. A          B
  7. ---------- -----------------------------
  8. 1          2
  9. 3          4
  10. SQL> commit;
  11. Commit complete.

再打开一个SecureCRT.(第二个session)

查询

  1. SQL> select * from c;
  2. A          B
  3. ---------- --------------------------
  4. 1          2
  5. 3          4

第一个session更改表中的数据但不提交

  1. SQL> update c set b=10 where a=1;
  2. 1 row updated.

第二个session查询(修改但没有提交检索的是UNDO中的数据)

  1. SQL> select * from c;
  2. A          B
  3. ---------- --------------------------
  4. 1          2
  5. 3          4

第一个session提交

  1. SQL> commit;
  2. Commit complete.

第二个会话查询(可见只有提交后才能检索到数据段的数据)

  1. SQL> select * from c;
  2. A          B
  3. ---------- -------------------------
  4. 1         10
  5. 3          4

结论:如果用户修改数据但没有提交,其它用户检索的都是UNDO段的数据,这样就保证了数据的一致性

2.回滚数据(事务恢复)

1.当用户updata数据但还没有提交

  1. SQL> select * from c;
  2. A          B
  3. ---------- -----------------------------
  4. 1          10
  5. 3          4
  6. SQL> update c set b=2 where a=1;
  7. SQL> select * from c;
  8. A          B
  9. ---------- -----------------------------
  10. 1          2
  11. 3          4

这时用户突然后悔了,想恢复到原来的状态

  1. SQL> rollback;
  2. Rollback complete.
  3. SQL> commit;
  4. SQL> select * from c;
  5. A          B
  6. ---------- -----------------------
  7. 1         10
  8. 3          4

可见当用户用命今rollback还能回滚到初始状态.

2.当用户updata数据且已提交

当用户updata数据且已提交后,可以根据SCN记录把数据还源.

先查看原始数据

  1. SQL> select * from c;
  2. A          B
  3. ---------- ----------
  4. 1         10
  5. 3          4

找到SCN

  1. SQL> select current_scn from v$database;
  2. CURRENT_SCN
  3. -----------
  4. 693636

现在删除表中的数据并提交

  1. SQL> delete from c;
  2. 2 rows deleted.
  3. SQL> commit;
  4. Commit complete.

查询(现在表中已没有数据了)

  1. SQL> select * from c;
  2. no rows selected

检索特定SCN的数据

  1. SQL> select * from c as of scn 693636;
  2. A          B
  3. ---------- ----------
  4. 1         10
  5. 3          4

恢复数据

  1. SQL> insert into c select * from c as of scn 693636;
  2. 2 rows created.
  3. SQL> commit;
  4. Commit complete.

现在再查询

  1. SQL> select * from c;
  2. A          B
  3. ---------- ----------------------
  4. 1         10
  5. 3          4

可见可以根据SCN恢复到某一检查点的数据,如果把SCN转换成时间,,就可以把数据恢复到某一时间点.

时间: 2024-10-07 03:42:06

Oracle检索数据一致性与事务恢复(转)的相关文章

[转]Oracle DB 使用RMAN执行恢复

? 在丢失关键或非关键数据文件后执行完全恢复 ? 使用增量更新的备份进行恢复 ? 切换到映像副本进行快速恢复 ? 将数据库还原到新主机上 ? 使用备份控制文件进行恢复 使用RMAN RESTORE和RECOVER命令 ? RESTORE命令:从备份中还原数据库文件 ? RECOVER命令:通过应用增量备份和重做日志文件中记录的更改来恢复已还原文件 RMAN> SQL 'ALTER TABLESPACE inv_tbs OFFLINE IMMEDIATE'; RMAN> RESTORE TABL

Oracle在归档模式下恢复

=============== 数据库的完全恢复 =============== 在归档模式下数据库完全恢复时,数据库所经过的状态如下: 1.利用备份修复(Restores)损坏或丢失的数据文件,即将备份的文件复制到数据库中原来的位置 2. 将从备份到系统崩溃这段时间所提交的数据由归档日志文件和重做日志文件中还原成数据文件所需要的数据块,这也叫前滚(Roll Forward) 3. 此时数据块中包含了所有提交的数据,也可能包含没提交的数据 4. 系统利用还原数据块回滚未提交的数据,这也叫回滚或者

Oracle基础 数据库备份和恢复

原文:Oracle基础 数据库备份和恢复 一.为什么需要数据备份 造成数据丢失的主要原因: 1.介质故障. 2.用户的错误操作. 3.服务器的彻底崩溃. 4.计算机病毒. 5.不可预料的因素. Oracle中故障类型分为以下4种. 1.语句故障: 执行SQL语句过程发生的逻辑故障可导致语句故障.如果用户编写的SQL语句无效,就会发生语句故障.Oracle可自我修复语句故障,撤销语句产生的而印象,并将控制权交给应用程序. 2.用户进程故障 当用户程序出错而无法访问Oracle数据库时,就会发生用户

【翻译自mos文章】当并行事务恢复进程在执行时,禁用并行事务恢复的方法

当并行事务恢复进程在执行时,禁用并行事务恢复的方法 How to Disable Parallel Transaction Recovery When Parallel Txn Recovery is Active (Doc ID 238507.1) 适用于: Oracle Database - Enterprise Edition - Version 8.1.5.0 to 11.2.0.4 [Release 8.1.5 to 11.2] Oracle Database - Personal E

【翻译自mos文章】当并行事务恢复进程在运行时,禁用并行事务恢复的方法

当并行事务恢复进程在运行时,禁用并行事务恢复的方法 How to Disable Parallel Transaction Recovery When Parallel Txn Recovery is Active (Doc ID 238507.1) 适用于: Oracle Database - Enterprise Edition - Version 8.1.5.0 to 11.2.0.4 [Release 8.1.5 to 11.2] Oracle Database - Personal E

Oracle数据库中闪回恢复的详细分析

Oracle9i开始提供闪回查询,以便能在需要的时候查到过去某个时刻的一致性数据,这是通过Undo实现的.这个功能有很大的限制,就是相关事务的undo不能被覆盖,否则就无力回天了.oracle10g大大的增强了闪回查询的功能,并且提供了将整个数据库回退到过去某个时刻的能力,这是通过引入一种新的flashback log实现的. flashback log有点类似redo log,只不过redo log将数据库往前滚,flashback log则将Oracle数据库往后滚.为了保存管理和备份恢复相

Veritas Netbackup Oracle数据库本机备份恢复

概述: 本次实验环境采用Veritas Netbackup 7.7.3软件版本,对Redhat Linux Oracle数据库的备份和恢复. 操作系统 主机名 IP地址 Windows Server 2008R2  nbumaster 192.168.60.59 Redhat Linux 6.5 x86_64 rhel6 192.168.60.100 Oracle备份恢复实验拓扑: 备份RedHat Linux环境下的Oracle 11gR2数据库到Master Server端: 通过Maste

Oracle简单的备份和恢复-导出和导入(2)

ylbtech-Oracle:Oracle简单的备份和恢复-导出和导入(2) 简单的备份和恢复-导出和导入(2) 1. 用户导入导出文件中的一张表(emp)返回顶部 0.1, 我们在sql plus中删除掉一张表emp,把dept表的记录删空. drop table emp; delete from dept; 之后我们先利用刚才导出的mytable.dmp导入emp表.具体导入步骤如下: 1.在命令行下输入imp命令. 2.系统首先提示我们输入用户名和密码,在这里我们可以用scott/tige

案例:Oracle dul数据挖掘 非常规对ORACLE 12C CDB数据库进行恢复

没有数据库备份的情况下,非常规对ORACLE 12C CDB数据库进行恢复 熟悉dul的朋友都知道dul是通过file# 1 block 1的kcvfhrdb找到bootstarp$的segment header(其实kcvfhrdb就是bootstarp$ segment header的rdba地址),然后通过bootstarp$中存储的相关sql找对一些基础的基表对象(obj$,tab$,col$,seg$等),然后通过他们定位到具体的对象的segment记录,从而通过segment找到ex