1oracle一致性读的背景知识
一致性读(Consistent Get)是Oracle一个非常优秀的特性.(当然它也是产生ora-1555错误的主要原因)在标准SQL中,为了防止并发事务中产生脏读,就需要通过加锁来控制.这样就会带来死锁、阻塞的问题,即时是粒度最小的行级锁,也无法避免这些问题. 为了解决这一矛盾,Oracle充分利用的回归段,通过会滚段进行一致性读取,即避免了脏读,又大大减少了系统的阻塞、死锁问题. Oracle是如何实现一致性读的: 当Oracle更新数据块(Data Block Oracle中最小的存储单位)时,会在两个地方记录下这一更新动作.一个是在Redo Segment,.一个是回滚段UNDO Segment.并在数据块头部标示出来是否有修改数据.一个语句在读取数据快时,如果发现这个数据块是在它读取的过程中被修改的(即开始执行读操作时并没有被修改),就不直接从数据块上读取数据,而是从相应的回滚段条目中读取数据.这就保证了最终结果应该是读操作开始时的那一时刻的快照(snapshot),而不会受到读期间其他事务的影响.这就是Oracle的一致性读,也可以叫做多版本(Multi-Versioning). |
2下面举例说明,oracle版本信息
SQL> select * from v$version Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - Production |
3undo 表空间信息
SQL> show parameter undo NAME TYPE VALUE ------------------------------------ ----------- ------------------------------ undo_management string AUTO undo_retention integer 3600 undo_tablespace string UNDOTBS1 |
4oracle11g,默认为我们创建10个undo 系统段信息。
SQL> select usn,name from v$rollname 2 / USN NAME ---------- ------------------------------ 0 SYSTEM 1 _SYSSMU1_592353410$ 2 _SYSSMU2_967517682$ 3 _SYSSMU3_1204390606$ ................................................. 9 _SYSSMU9_1735643689$ 10 _SYSSMU10_4131489474$ 11 rows selected. |
5v$rollstat 目前还没有活动的信息(为节省篇幅,有省略)
SQL> select usn,latch,xacts,status from v$rollstat 2 / USN LATCH XACTS STATUS ---------- ---------- ---------- --------------- 0 0 0 ONLINE 1 0 0 ONLINE 2 0 0 ONLINE 3 0 0 ONLINE 4 0 0 ONLINE .. ... ................ 11 rows selected. |
6也可以查看我们的v$transaction视图。
SQL> select xidusn,xidslot,status,name,ubafil,ubablk from v$transaction 2 / no rows selected |
7我们创建如下的测试表
SQL> show user USER is "SYS" SQL> drop table t purge 2 / Table dropped.
SQL> create table t(id number) 2 / Table created. |
作赋值操作。 declare i number; begin for i in 1..100 loop insert into t values(i); end loop; end; / PL/SQL procedure successfully completed. |
8此时在当前会话中,我们可以看到t表已经有值
SQL> select userenv('sid') from dual 2 / USERENV('SID') -------------- 34 SQL> select count(*) from t 2 / COUNT(*) ---------- 100 |
那么在其它会话中呢
SQL> select * from v$mystat where rownum<2 2 / SID STATISTIC# VALUE ---------- ---------- ---------- 38 0 0 SQL> select * from t 2 / no rows selected |
可以看到没有值。这只是oracle为我们构造的一致性读,最简单的一个阐述。
9在sid为34的会话中作提交操作,在sid38中立即可见。这里不再赘述。
10对表t作如下操作
SQL> alter table t add ( name varchar2(20)) 2 /
Table altered delete from t 赋值: declare i number; begin for i in 1..100 loop insert into t(id,name) values(i,'hdp'); end loop; end; /
|
11在34号会话中
SQL> select * from t where rownum<10 2 /
ID NAME ---------- -------------------- 1 hdp 2 hdp .......... .......... 8 hdp 9 hdp
9 rows selected.
SQL> update t set name='huangdp' where id=9 2 /
1 row updated.
SQL> select * from t where rownum<10 2 /
ID NAME ---------- -------------------- 1 hdp 2 hdp .......... 8 hdp 9 huangdp
9 rows selected. |
12在38号会话中
SQL> select userenv('sid') from dual 2 /
USERENV('SID') -------------- 38
SQL> select * from t where rownum<10 2 /
ID NAME ---------- -------------------- 1 hdp 2 hdp 3 hdp ......... 9 hdp
9 rows selected. |
13此时在v$transaction中有一未提交事务,就是我们刚刚的update操作。而sid为38
的会话,所查寻到的是undo段所构造的事务之前的镜像。
SQL> select addr,xidusn,status from v$transaction 2 /
ADDR XIDUSN STATUS -------- ---------- ---------------- 2E2BE6B8 1 ACTIVE |
14利用rowid,找到这条数据在数据库文件的具体地址
SQL> select rowid,id,name from t where rownum<10 2 / ROWID ID NAME ------------------ ---------- -------------------- AAASqmAABAAAVZRAAA 1 hdp AAASqmAABAAAVZRAAB 2 hdp AAASqmAABAAAVZRAAC 3 hdp ................................................. ......... AAASqmAABAAAVZRAAH 8 hdp AAASqmAABAAAVZRAAI 9 huangdp |
找到其具体所在的文件和block号
select dbms_rowid.rowid_relative_fno('AAASqmAABAAAVZRAAI') as file#, dbms_rowid.rowid_block_number('AAASqmAABAAAVZRAAI') as block# 3 from dual;
FILE# BLOCK# ---------- ---------- 1 87633 |
从我们的事务视图中,也可以窥见一斑
SQL> select addr,xidusn,status from v$transaction 2 / ADDR XIDUSN STATUS -------- ---------- ---------------- 2E2BE6B8 1 ACTIVE
|
让我们来dump 1号文件 87633号文件的数据,这个数据目前还是在内存中的
SQL> alter system dump datafile 1 block 87633 2 / System altered. SQL> @?/gettrcname.sql TRACE_FILE_NAME ------------------------------------------------------------------------------------------------------------------------------------ /opt/oracle/diag/rdbms/oa/oa/trace/oa_ora_4219.trc |
查看这个4219的dump文件
主要是看ITL事务槽的信息
lck为1 表示锁定了一条数据,‘----’代表一个数据块正在被修改。
我们修改的是T表中第9行,看下转存文件中的row8(即第九行)
让我们来看看 68..75.. 代表什么
SQL> select chr(to_number('68','xx')) obj from dual 2 / OBJ ---- h SQL> select chr(to_number('75','xx')) obj from dual 2 / OBJ ---- u |
(注释:这里的75等,都是ASCII代码)
如上,该处存放的其实就是’huangdp’,这里存放的就是被修改的临时值。如此,我们也知道,
未提交的数据是在system表空间中的。具体其实是在buffer cache中。因为oracle会将需要的数据读到内存中来。并在内存中进行修改。
而其它会话,是去oracle构造的一致性读,即undo中去读取的数据,这数据所在的地址
就是uba
0x00c001e9.0114.2d
SQL> select to_number('00c001e9','xxxxxxxx') from dual;
TO_NUMBER('00C001E9','XXXXXXXX') -------------------------------- 12583401
select dbms_utility.data_block_address_file(12583401) as file#, dbms_utility.data_block_address_block(12583401) as block# 3 from dual;
FILE# BLOCK# ---------- ---------- 3 489 |
dump这个文件
SQL> alter system dump datafile 3 block 489 2 /
System altered.
SQL> @?/gettrcname.sql
TRACE_FILE_NAME ------------------------------------------------------------------------------------------------------------------------------------ /opt/oracle/diag/rdbms/oa/oa/trace/oa_ora_4820.trc |
我们直接查看这个文件,找到0x2d,可以看到存放的是hdp,其它会话就是从这里读值。
注释:
col1 表示第二列
【3】表示共有三个字符
file#3就是我们的undo表空间。
SQL> col file_name for a25 SQL> select file_name,file_id,tablespace_name from dba_data_files 2 / FILE_NAME FILE_ID TABLESPACE_NAME ------------------------- ---------- ------------------------------ /huangdp/oa/users01.dbf 4 USERS /opt/oracle/oradata/oa/un 3 UNDOTBS1 dotbs01.dbf ........................ |
至此,我们对oracle的undo,和一致性读有了一个深刻的认识。