Oracle里未成功commit的数据我们也可能能看到
Posted: January 28, 2012 | Author: Cui Hua | Filed under: Oracle | Leave a comment »我们大家都知道的一个常识是——Oracle里未commit的数据除了当前session之外,其他session是看不到的。
我这里演示了一个有趣的例子,在这个例子里我们可以看到,Oracle里未成功commit的数据我们也可能能看到。
我同时启4个session。
先在session 1里创建一个表t1,插入一条数据但不commit:
Session 1:
Connected to Oracle Database
Connected as scott
SQL> create table t1(id number, name varchar2(10));
Table created
SQL> insert into t1 values(1,’CUIHUA’);
1 row inserted
SQL> select * from t1;
ID NAME
———- ———-
1 CUIHUA
此时跳到session 2,因session 1里刚插入的那条数据还未commit,所以这个时候session 2是看不到这条数据的:
Session 2:
SQL> select * from t1;
ID NAME
———- ———-
接着我们跳到session 3,把lgwr进程suspend住:
Session 3:
SQL> select spid from v$process where pname=’LGWR’;
SPID
————————
2316
SQL> oradebug setospid 2316
Oracle pid: 11, Windows thread id: 2316, image: ORACLE.EXE (LGWR)
SQL> oradebug suspend
已处理的语句
现在我们回到session 1,执行commit命令,因为lgwr进程已经被我们suspend住了,所以当前session 1里要执行的commit操作一定会被hang住:
Session1:
SQL> commit;
……这里hang住了
Oracle里commit操作的流程是这样的:
1、Oracle先去改这个transaction所对应的undo segment header中slot的状态;
2、改完状态后再flush log buffer;
现在我们把lgwr hold住了,所以上述步骤2 Oracle是没法做了,但步骤1还是可以做的。而只要步骤1做完了,其他的session就能看到这个transaction所做的改变了(通过ITL中记录的transaction id去check相应的undo segment header中slot的状态),也就是说对于其他session而言,这个transaction已经commit了,虽然这个transaction其实并没有成功commit。
好了,我们现在回到session 2,看一下我们现在能否看到刚才insert的那条记录:
Session 2:
SQL> select * from t1;
ID NAME
———- ———-
1 CUIHUA
从结果里可以看到,刚才看不到的那条记录现在我们已经能看到了,即session 1对于session2而言已经commit了,虽然session1的commit操作其实并没有成功的做完。
现在我们跳到session 4,执行shutdown abort:
Session 4:
SQL> shutdown abort
ORACLE 例程已经关闭。
然后我们再在session 4中执行startup,startup后我们从alert log里可以很明显的看到Oracle做了instance recovery:
Sat Jan 28 19:14:03 2012
alter database mount exclusive
Successful mount of redo thread 1, with mount id 4288810811
Database mounted in Exclusive Mode
Lost write protection disabled
Completed: alter database mount exclusive
alter database open
Beginning crash recovery of 1 threads
parallel recovery started with 2 processes
Started redo scan
Completed redo scan
read 918 KB redo, 126 data blocks need recovery
Started redo application at
Thread 1: logseq 44, block 77312
Recovery of Online Redo Log: Thread 1 Group 2 Seq 44 Reading mem 0
Mem# 0: C:\APP\CUIHUA\ORADATA\CUIHUA112\REDO02.LOG
Completed redo application of 0.52MB
Completed crash recovery at
Thread 1: logseq 44, block 79149, scn 1652578
126 data blocks read, 95 data blocks written, 918 redo k-bytes read
等待上述库成功startup后,我们再次回到session 1,看一下刚才我们已经commit的那条数据是否还在:
Session 1:
SQL> select * from t1;
ID NAME
———- ———-
从结果里可以看到,刚才我们insert且执行了commit操作的那条记录现在已经丢失了。
MSSM的段头中CCNT的含义(续)
Posted: December 16, 2011 | Author: Cui Hua | Filed under: Oracle | Tags: CCNT | Leave a comment »其实这篇文章的结论并不重要,最关键的是当你碰到一个在google、baidu、MOS甚至Oracle内部的webiv上都查不到相关内容的时候,你处理的思路是什么。
经过简单的测试,我们猜测——MSSM的段头中CCNT的含义就是Change CouNT的缩写,它的含义是Oracle对MSSM中段头的free list的修改次数,一次修改通常会包括move hwm+link block+unlink block这一组动作。
我们现在来证明一下上述结论:
SQL> create table t1 as select * from dba_objects where rownum<100;
Table created
SQL> insert into t1 select * from dba_objects where rownum<1000;
999 rows inserted
SQL> commit;
Commit complete
SQL> select header_file,header_block from dba_segments where segment_name=’T1′;
HEADER_FILE HEADER_BLOCK
———– ————
1 51065
表t1之前的段头内容为:
buffer tsn: 0 rdba: 0x
scn: 0×0000.000ec812 seq: 0×04 flg: 0×00 tail: 0xc8121004
frmt: 0×02 chkval: 0×0000 type: 0×10=DATA SEGMENT HEADER – UNLIMITED
Extent Control Header
—————————————————————–
Extent Header:: spare1: 0 spare2: 0 #extents: 10 #blocks: 79
last map 0×00000000 #maps: 0 offset: 4128
Highwater:: 0x
#blocks in seg. hdr’s freelists: 3
#blocks below: 76
mapblk 0×00000000 offset: 9
Unlocked
Map Header:: next 0×00000000 #extents: 10 obj#: 30547 flag: 0×40000000
Extent Map
—————————————————————–
0x
0x
0x
0x
0x
0x
0x
0x
0x
0x
nfl = 1, nfb = 1 typ = 1 nxf = 0 ccnt = 21
SEG LST:: flg: USED lhd: 0x
当我对t1执行insert大量数据的操作时,Oracle必然要去修改t1段头中的freelist:
SQL> insert into t1 select * from t1 where rownum<1000;
999 rows inserted
SQL> commit;
Commit complete
执行完上述插入操作后,t1的段头中内容如下所示,从结果里我们可以看到ccnt从21变成了25:
Start dump data blocks tsn: 0 file#: 1 minblk 51065 maxblk 51065
buffer tsn: 0 rdba: 0x
scn: 0×0000.000ed214 seq: 0×02 flg: 0×00 tail: 0xd2141002
frmt: 0×02 chkval: 0×0000 type: 0×10=DATA SEGMENT HEADER – UNLIMITED
Extent Control Header
—————————————————————–
Extent Header:: spare1: 0 spare2: 0 #extents: 12 #blocks: 95
last map 0×00000000 #maps: 0 offset: 4128
Highwater:: 0x
#blocks in seg. hdr’s freelists: 5
#blocks below: 92
mapblk 0×00000000 offset: 11
Unlocked
Map Header:: next 0×00000000 #extents: 12 obj#: 30547 flag: 0×40000000
Extent Map
—————————————————————–
0x
0x
0x
0x
0x
0x
0x
0x
0x
0x
0x
0x
nfl = 1, nfb = 1 typ = 1 nxf = 0 ccnt = 25
SEG LST:: flg: USED lhd: 0x
现在的关键问题是,这个ccnt的修改之后的值25是如何来的?只有在我们清楚了这个25的来历,我们才算真正的对上述问题有了一个初步的了解。
这时候我们的思路就是dump一下redo,然后看看redo的内容我们就什么都清楚了,dump之后的redo中清晰的显示出了ccnt的值的变化过程:
过程1:
REDO RECORD – Thread:1 RBA: 0x
SCN: 0×0000.000ed210 SUBSCN: 1 05/16/2011 17:07:29
CHANGE #1 TYP:0 CLS: 4 AFN:1 DBA:0x
KTSFRGRP (fgb/shdr modify freelist) redo:
Opcode: LUPD_UNLBLK (unlink block)
Slot no: 0, Count: 1
Flag: = 1 xid or slot0 ccnt: 0×0000.000.00000015 Head: 0x
CHANGE #2 TYP:0 CLS: 1 AFN:1 DBA:0x
KTSFRBLNK (block link modify) redo: Opcode: LCLR (lock clear)
Next dba: 0×00000000 itli: 0
过程2:
REDO RECORD – Thread:1 RBA: 0x
SCN: 0×0000.000ed210 SUBSCN: 1 05/16/2011 17:07:29
CHANGE #1 TYP:0 CLS: 4 AFN:1 DBA:0x
KTSFRGRP (fgb/shdr modify freelist) redo:
Opcode: LUPD_UNLBLK (unlink block)
Slot no: 0, Count: 1
Flag: = 1 xid or slot0 ccnt: 0×0000.000.00000015 Head: 0x
CHANGE #2 TYP:0 CLS: 1 AFN:1 DBA:0x
KTSFRBLNK (block link modify) redo: Opcode: LCLR (lock clear)
Next dba: 0×00000000 itli: 0
过程3:
REDO RECORD – Thread:1 RBA: 0x
SCN: 0×0000.000ed210 SUBSCN: 1 05/16/2011 17:07:29
CHANGE #1 TYP:0 CLS: 4 AFN:1 DBA:0x
KTSFRGRP (fgb/shdr modify freelist) redo:
Opcode: LUPD_UNLBLK (unlink block)
Slot no: 0, Count: 1
Flag: = 1 xid or slot0 ccnt: 0×0000.000.00000015 Head: 0×00000000 Tail: 0×00000000
CHANGE #2 TYP:0 CLS: 1 AFN:1 DBA:0x
KTSFRBLNK (block link modify) redo: Opcode: LCLR (lock clear)
Next dba: 0×00000000 itli: 0
过程4:
REDO RECORD – Thread:1 RBA: 0x
SCN: 0×0000.000ed210 SUBSCN: 1 05/16/2011 17:07:29
CHANGE #1 TYP:0 CLS: 1 AFN:1 DBA:0x
KTSFRBLNK (block link modify) redo: Opcode: LWRT (lock write)
Next dba: 0×00000000 itli: 0
CHANGE #2 TYP:0 CLS: 4 AFN:1 DBA:0x
KTSFRGRP (fgb/shdr modify freelist) redo:
Opcode: HWMMV (move hwm)
NBK: 3
Opcode: LUPD_LLIST (link a list)
Slot no: 0, Count: 3
Flag: = 1 xid or slot0 ccnt: 0×0000.000.00000016 Head: 0x
过程5:
REDO RECORD – Thread:1 RBA: 0x
SCN: 0×0000.000ed210 SUBSCN: 1 05/16/2011 17:07:29
CHANGE #1 TYP:0 CLS: 4 AFN:1 DBA:0x
KTSFRGRP (fgb/shdr modify freelist) redo:
Opcode: LUPD_UNLBLK (unlink block)
Slot no: 0, Count: 1
Flag: = 1 xid or slot0 ccnt: 0×0000.000.00000016 Head: 0x
CHANGE #2 TYP:0 CLS: 1 AFN:1 DBA:0x
KTSFRBLNK (block link modify) redo: Opcode: LCLR (lock clear)
Next dba: 0×00000000 itli: 0
过程6:
REDO RECORD – Thread:1 RBA: 0x
SCN: 0×0000.000ed210 SUBSCN: 1 05/16/2011 17:07:29
CHANGE #1 TYP:0 CLS: 4 AFN:1 DBA:0x
KTSFRGRP (fgb/shdr modify freelist) redo:
Opcode: LUPD_UNLBLK (unlink block)
Slot no: 0, Count: 1
Flag: = 1 xid or slot0 ccnt: 0×0000.000.00000016 Head: 0x
CHANGE #2 TYP:0 CLS: 1 AFN:1 DBA:0x
KTSFRBLNK (block link modify) redo: Opcode: LCLR (lock clear)
Next dba: 0×00000000 itli: 0
过程7:
REDO RECORD – Thread:1 RBA: 0x
SCN: 0×0000.000ed210 SUBSCN: 1 05/16/2011 17:07:29
CHANGE #1 TYP:0 CLS: 4 AFN:1 DBA:0x
KTSFRGRP (fgb/shdr modify freelist) redo:
Opcode: LUPD_UNLBLK (unlink block)
Slot no: 0, Count: 1
Flag: = 1 xid or slot0 ccnt: 0×0000.000.00000016 Head: 0×00000000 Tail: 0×00000000
CHANGE #2 TYP:0 CLS: 1 AFN:1 DBA:0x
KTSFRBLNK (block link modify) redo: Opcode: LCLR (lock clear)
Next dba: 0×00000000 itli: 0
过程8:
REDO RECORD – Thread:1 RBA: 0x
SCN: 0×0000.000ed212 SUBSCN: 1 05/16/2011 17:07:29
CHANGE #1 TYP:0 CLS: 1 AFN:1 DBA:0x
KTSFRBLNK (block link modify) redo: Opcode: LWRT (lock write)
Next dba: 0×00000000 itli: 0
CHANGE #2 TYP:0 CLS: 4 AFN:1 DBA:0x
KTSFRGRP (fgb/shdr modify freelist) redo:
Opcode: HWMMV (move hwm)
NBK: 5
Opcode: LUPD_LLIST (link a list)
Slot no: 0, Count: 5
Flag: = 1 xid or slot0 ccnt: 0×0000.000.00000017 Head: 0x
……省略显示其他类似过程
过程18:
REDO RECORD – Thread:1 RBA: 0x
SCN: 0×0000.000ed214 SUBSCN: 1 05/16/2011 17:07:29
CHANGE #1 TYP:0 CLS: 1 AFN:1 DBA:0x
KTSFRBLNK (block link modify) redo: Opcode: LWRT (lock write)
Next dba: 0×00000000 itli: 0
CHANGE #2 TYP:0 CLS: 4 AFN:1 DBA:0x
KTSFRGRP (fgb/shdr modify freelist) redo:
Opcode: HWMMV (move hwm)
NBK: 5
Opcode: LUPD_LLIST (link a list)
Slot no: 0, Count: 5
Flag: = 1 xid or slot0 ccnt: 0×0000.000.00000019 Head: 0x
从上述过程1一直到过程18,非常完整的显示了Oracle是如何将ccnt的值从21(0×15)递增到25(0×19)的。
现在我们来尝试解释一下上述过程的含义:
上述过程1、2、3为一组,清晰的表示了Oracle在insert大量数据后是如何开始修改MSSM的段头的freelist的,从t1在insert之前的段头的dump内容中我们可以看到如下内容:
nfl = 1, nfb = 1 typ = 1 nxf = 0 ccnt = 21
SEG LST:: flg: USED lhd: 0x
即表明t1的main freelist已经存在且header指向0x
那么现在当Oracle插入大量数据的时候,因为freelist上已经存在3个block(分别是0x
等到过程1、过程2、过程3都执行完了,现在t1的main freelist上已经不存在可用的block,所以Oracle这时候要扩展高水位线,给t1的main freelist先分配一些可用的free block,也就是过程4所表明的含义。在过程4里,Oracle额外分配了3个block(分别是0x
后续的分析与上面类似,最后的结果就是ccnt递增到0×19就终止了,即这次insert操作做完了后,t1的main free list中的free block变成了5个(从0x
所以,从上面的分析我们可以得出结论:ccnt其实记录的是在MSSM下Oracle对段头的freelist的一组修改操作所对应的sequence number,相邻的组与组之间的ccnt会递增1。
一组修改操作的含义是如下三种情况之一:
1、 单纯的unlink block(例如过程1、2、3);
2、 link block + unlink block (例如过程4、5、6、7)
3、 单纯的link block (例如过程18)
简单总结一下:MSSM的段头中CCNT我猜是Change CouNT的缩写,它的含义是Oracle对MSSM中段头的free list的修改次数,一次修改通常会包括move hwm+link block+unlink block这一组动作。

Recent Comments