由读一致性分析undo

来源:互联网 发布:c语言给数组赋初值 编辑:程序博客网 时间:2024/06/06 13:29
下面通过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.00665325
txn start scn: scn: 0x0000.006658a2 logon user: 91
 prev brb: 12594708 prev bcl: 0
KDO undo record:
KTB Redo 
op: 0x03  ver: 0x01  
compat bit: 4 (post-11) padding: 1
op: Z
Array Update of 1 rows: 
tabn: 0 slot: 0(0x0) flag: 0x2c lock: 0 ckix: 191
ncol: 2 nnew: 1 size: 0
KDO Op code:  21 row dependencies Disabled
  xtype: XAxtype KDO_KDOM2 flags: 0x00000080  bdba: 0x01001bae  hdba: 0x01001baa
itli: 2  ispac: 0  maxfr: 4858
vect = 3
col  1: [ 1]  61
 
End dump data blocks tsn: 2 file#: 3 minblk 11799 maxblk 11799

所以通过undo读取了61(代表a)
我们查看数据文件3是什么文件类型:
select * from dba_data_files where file_id=3;

是undo数据文件。
SQL> show parameter undo;


NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
undo_management                      string      AUTO
undo_retention                       integer     900
undo_tablespace                      string      UNDOTBS1

默认的是undotbs1表空间,可以创建很多undo表空间,但是一个实例只用一个undo表空间。
undo表空间是有undo segments 组成,查看有多少undo段:
select * from dba_rollback_segs;

注意上面的owner列,如果是public,则该实例创建的undo段可以被数据库其他实例使用,但是sys表示的是私有undo段,只可以被该undo段创建者使用。
注意到undo段的状态了没,现在默认的undo表空间是undotbs1,所以该undo段都是在线,undo_w表空间的undo段都是离线。
我们可以通过修改参数undo_tablespace设置默认undo表空间。
oracle对于处于online的undo段进行监视,通过视图v$rollstat查看:
 

上面总共有11条,usn是undo段编号
一个事务使用一个undo段
下面执行一个事物:
SQL> update t set name='c' where id=1;


已更新 1 行。

select * from v$transaction;

注意XIDUSN列表示的是undo段编号,此时该事务使用的是10号undo段
查看10号undo段:
select * from v$rollstat;
XACTS列表示的是该10号undo段上具有活动的事务数量
此时修改默认undo表空间:
SQL> alter system set undo_tablespace=undo_w;


系统已更改。


SQL>  show parameter undo;


NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
undo_management                      string      AUTO
undo_retention                       integer     900
undo_tablespace                      string      UNDO_W
此时查看undo段状态:
select  * from dba_rollback_segs;

undotbs1里的undo段除了10号,其他的都处于offline,因为它任被使用,事务结束后,自动变为offline
通过查看视图:
select * from v$rollstat;

发现10号undo段状态是pending  offline(pending在等待…期间)

会疑问,每个回滚段段上到底可以被几个事务使用呢?
SQL> show parameter roll


NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
fast_start_parallel_rollback         string      LOW
rollback_segments                    string
transactions_per_rollback_segment    integer     5

可以被5个事务使用,但是这是在undo表空间没有自动管理之前,自从undo表空间自动管理后,该parameter不起作用。
一个undo段只能被一个事务使用,若undo被事务用完后,则oracle background  process  smon  自动创建undo段.
如果一个回滚段被多个事务使用的话,undo段头会有等待,影响并发性,我们可以通过视图V$WAITSTAT查看等待事件:
select * from v$waitstat;

可以通过执行多个事务,模拟smon自动创建undo段,自行模拟试验。(smon创建的undo段不会因为事务结束而回收)
下面看一下一个很重要的参数:undo_retention单位是秒(表示的是事务提交以后,放在undo里的数据保留的时间)
SQL>  show parameter undo;


NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
undo_management                      string      AUTO
undo_retention                       integer     900
undo_tablespace                      string      UNDO_W
SQL> show parameter roll
很有名的oracle一个错误:ORA-01555(快照太旧)
实际情况下查询发生在修改之前,比较少。
出现这个错的可能情况:
undo表空间太小
查询数据的时间过长(sql查询性能差)
undo_rentention太小
我们通过视图dba_tablespaces,引出一个参数:
SELECT TABLESPACE_NAME,RETENTION FROM DBA_TABLESPACES;

retention这列,undo表空间缺省的是NOGUARANTEE,但是我们可以修改这个参数,强制保留。
SQL> alter tablespace undotbs1 retention GUARANTEE;                          


表空间已更改。

一定会保留900秒。
当让可以改undo_rentention

SQL> alter system set undo_retention=1200;


系统已更改。
上面列出的出现ORA-01555的三种情况,这三者之间有关系,比如增加了undo_rentention,从而需要的undo表空间要更多。
oracle里提供了undo  advisor(顾问),我们可以根据这个,来平衡这几者关系,进入到OEM:
[oracle@localhost ~]$ emctl start dbconsole
Oracle Enterprise Manager 11g Database Control Release 11.2.0.1.0 
Copyright (c) 1996, 2009 Oracle Corporation.  All rights reserved.
https://diy_os:1158/em/console/aboutApplication
Starting Oracle Enterprise Manager 11g Database Control .......

进入em后,在自动管理界面,提供了这一张图:

根据undo_rentention的大小,来确定所需的undo表空间的大小,可以更改分析时段,会提供建议图形界面。
图形是如何作出的呢?
有一个公式:
UndoSpace = [UR * (UPS * DBS)] + (DBS*24)
UR:undo_rentention in seconds
UPS:number of undo data blocks generated per second
DBS:overhead varies based on extent and file size(db_block_size)实际就是块大小:show parameter  db_block;
我们可以根据oracle的一个视图:v$undostat;

每十分钟计算undo的数量。可以根据这个视图可以画出上述图形。
0 0