由读一致性分析undo(一)

2015-07-24 08:56:47 · 作者: · 浏览: 0
下面通过undo的一致性读分析undo:
[oracle@localhost ~]$ lsb_release -a
LSB Version: :core-3.1-ia32:core-3.1-noarch:graphics-3.1-ia32:graphics-3.1-noarch
Distributor ID: EnterpriseEnterpriseServer
Description: Enterprise Linux Enterprise Linux Server release 5.5 (Carthage)
Release: 5.5
Codename: Carthage

SQL> select * from v$version where rownum<2;

BANNER
--------------------------------------------------------------------------------
Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - Production

SQL> create table t(id number,name varchar2(10)); 表已创建。

已用时间: 00: 00: 00.15
SQL> set timing off;
SQL> show user;
USER 为 "HR"
SQL> insert into t values(1,'a');
已创建 1 行。

SQL> insert into t values(2,'b');
已创建 1 行。
SQL> commit;
提交完成。

SQL> update t set name='c' where id=1;

已更新 1 行。
SQL> select * from t;


ID NAME
---------- ----------
1 c
2 b



注意没提交。
重新打开一个session: SQL> select * from t;


ID NAME
---------- ----------
1 a
2 b

此时还是读取到修改之前的数据,这里的a是重undo里读取的,下面dump分析这个过程:
SQL> select t.*,rowid from t;


ID NAME ROWID
---------- ---------- ------------------
1 c AAASunAAEAAABuuAAA
2 b AAASunAAEAAABuuAAB

我们利用oracle提供的包,可以获得第一条数据所在的数据文件号及块号:
SQL> show user;
USER 为 "SYS"
SQL> select dbms_rowid.rowid_relative_fno(rowid) fno,dbms_rowid.rowid_block_number(rowid) bno from hr.t;


FNO BNO
---------- ----------
4 7086
4 7086

此时我们可以dump 4号文件的第7086块:
SQL> alter system dump datafile 4 block 7086;


系统已更改。
下面是摘自部分转储文件: *** 2015-04-20 15:26:34.151
Block header dump: 0x01001bae
Object id on Block? Y
seg/obj: 0x12ba7 csc: 0x00.6658e2 itc: 2 flg: E typ: 1 - DATA
brn: 0 bdba: 0x1001ba8 ver: 0x01 opc: 0
inc: 0 exflg: 0

Itl Xid Uba Flag Lck Scn/Fsc
0x01 0x0003.017.0000098a 0x00c009ac.02f0.24 C--- 0 scn 0x0000.0066582c
0x02 0x0008.00d.00000a84 0x00c02e17.0258.28 ----(表示事务锁定) 1(锁定一条数据) fsc 0x0000.00000000 =>0x2列已经被锁定了
bdba: 0x01001bae uba:undo block address
data_block_dump,data header at 0xa18264
===============
tsiz: 0x1f98
hsiz: 0x16
pbl: 0x00a18264
76543210
flag=--------
ntab=1
nrow=2
frre=-1
fsbo=0x16
fseo=0x1f88
avsp=0x1f70
tosp=0x1f70
0xe:pti[0] nrow=2 offs=0
0x12:pri[0] offs=0x1f90
0x14:pri[1] offs=0x1f88
block_row_dump:

tab 0, row 0, @0x1f90

tl: 8 fb: --H-FL-- lb(锁标记): 0x2 cc: 2 第一行第二列已经被上锁了,被一个事务锁定。 lb:lock byte
col 0: [ 2] c1 02 =>这列是从4号文件7086块中读取的
col 1: [ 1] 63 63代表是c,实际已经被改了
tab 0, row 1, @0x1f88
tl: 8 fb: --H-FL-- lb: 0x0 cc: 2
col 0: [ 2] c1 03
col 1: [ 1] 62

end_of_block_dump
End dump data blocks tsn: 4 file#: 4 minblk 7086 maxblk 7086


第二个session我们查出的第一行第二列却是a,也是从4号文件7086个块上读取得,但是发现第二列已经被上锁,不能读取。
我们通过uba提供的地址,可以获取修改之前的数据a存放的位置:

uba:
0x00c02e17.0258.28
先把这个十六进制数转换成十进制数,oracle提供的十进制包可以获取文件号及块号:
SQL> select to_number('00c02e17','XXXXXXXXXXXXXXXXXX') from dual;


TO_NUMBER('00C02E17','XXXXXXXXXXXXXXXXXX')
------------------------------------------
12594711

SQL> select dbms_utility.data_block_address_file(12594711) from dual;


DBMS_UTILITY.DATA_BLOCK_ADDRESS_FILE(12594711)
----------------------------------------------
3

SQL> select dbms_utility.data_block_address_block(12594711) from dual;


DBMS_UTILITY.DATA_BLOCK_ADDRESS_BLOCK(12594711)
-----------------------------------------------
11799


在第二个session中,oracle提示读取第一行第二列需要到3号文件上第11799号块上读取:
SQL> alter system dump datafile 3 block 11799;

系统已更改。
下面宅在部分转储文件:
uba: 0x00c02e17.0258.25 ctl max scn: 0x0000.00665307 prv tx scn: 0x0000.00665