一、数据库的变更与事物
数据库的任何变更都会产生一条重做记录,是定义哪些操作必须在一起,并且按顺序执行。包含了一系列操作。
一个变更对应一条重做记录,一个重做记录包含一个或多个CHANGE VECTOR,change vector记录了对一个数据块的原子操作。所以,Change Vector保证了数据块在修改前后的一致性,而其容器——重做记录则保证了数据库修改前后的一致性。
理解SCN、数据库版本号(SCN+SEQ)和RBA(重做字节地址)
SCN: 4个Base字节 2个Wrap字节组成 Base随时间流失和变更操作的执行而递增,用尽之后开始循环,此时Wrap递增(进位)。
任何数据库的变更的操作都会产生新的SCN,如果没有发生任何事,每3秒SCN也要增加1。
v$database大部分信息来自控制文件,调用v$database.CURRENT_SCN相当于调用序列的NEXTVAL,ORACLE将访问控制文件也视为一种变更,因此,两次查询肯定会返回两个不同的SCN。Dbms_flashback.get_system_change_number会得到当前的SCN。
每个能够对数据库状态修改的操作,都会产生一个新的SCN写入到重做记录中,这样重做记录之间就可以分清在时间顺序上对应的操作的先后顺序。
如果在两个重做记录中的SCN是相同的,这是由于ORACLE的某些内部操作导致的,所以又有了SUBSCN,用以标记同一个SCN下的多次变更。
转储文件中的SCN和SUBSCN: SCN:0xffff.ffffffff subscn:n
修改操作完成后,SCN和SUBSCN都会保存到数据块头部,占用7字节,SCN不变,但是SUBSCN改为SEQ,加起来就是数据块版本号。
这样修改操作的SCN就出现在了两个地方:重做日志和数据文件中。
RBA:重做记录地址,重做记录中记录了SCN和SUBSCN来说明变更操作的时间,而记录RBA说明变更操作的地址(在哪个重做日志的哪个字节处能找到其自身)。
转储文件中的RBA:THREAD:n RBA:0xffffff.ffffffff.ffff
比如:Thread:1RBA:0x000013.00000004.0010,标志在1号线程的19号序列号的重做日志文件的第4个块的第16字节处。
关于rowid:关于oracle rowid的一些内容
看一下一个简单的update产生的重做记录:
SQL>alter system switch logfile;
Systemaltered.
SQL>select * from v$log;
GROUP# THREAD# SEQUENCE# BYTES MEMBERS ARC STATUS FIRST_CHANGE# FIRST_TIM
-------------------- ---------- ---------- ---------- --- ---------------- ----------------------
1 1 53101 52428800 1 NO ACTIVE 1.1633E+11 19-JUL-13
2 1 53102 52428800 1 NO CURRENT 1.1633E+11 19-JUL-13
3 1 53100 52428800 1 NO ACTIVE 1.1633E+11 19-JUL-13
4 1 53097 524288000 1 NO INACTIVE 1.1618E+11 16-JUL-13
5 1 53098 524288000 1 NO INACTIVE 1.1632E+11 19-JUL-13
6 1 53099 524288000 1 NO ACTIVE 1.1633E+11 19-JUL-13
6rows selected.
SQL>conn dptwm/dptwm
Connected.
SQL>select * from emp;
SQL>/
EMPNO ENAME JOB MGRHIREDATE SAL COMM DEPTNO
-------------------- --------- ---------- --------- ---------- ---------- ----------
7369 SMITH CLERK 790217-DEC-80 800 20
7499 ALLEN SALESMAN 769820-FEB-81 1600 300 30
7521 WARD SALESMAN 769822-FEB-81 1250 500 30
7566 JONES MANAGER 783902-APR-81 2975 20
7654 MARTIN SALESMAN 769828-SEP-81 1250 1400 30
7698 BLAKE MANAGER 783901-MAY-81 2850 30
7782 CLARK MANAGER 783909-JUN-81 2450 10
7788 SCOTT ANALYST 756609-DEC-82 4320 20
7844 TURNER SALESMAN 769808-SEP-81 1500 0 30
7876 ADAMS CLERK 778812-JAN-83 1100 20
7900 JAMES CLERK 769803-DEC-81 950 30
EMPNO ENAME JOB MGRHIREDATE SAL COMM DEPTNO
-------------------- --------- ---------- --------- ---------- ---------- ----------
7902 FORD ANALYST 756603-DEC-81 3000 20
7934 MILLER CLERK 778223-JAN-82 1300 10
13rows selected.
SQL>update emp set sal=sal*1.2 where empno=7788;
1row updated.
SQL>commit;
Commitcomplete.
SQL>alter system dump logfile '/u01/oracle/oradata/dipdb/redo02.log';
Systemaltered.
-->以上操作为update一行
[oracle@OAudump]$ cat dipdb_ora_10521.trc |less
/u01/oracle/admin/dipdb/udump/dipdb_ora_10521.trc
OracleDatabase 10g Enterprise Edition Release 10.2.0.1.0 - 64bit Production
Withthe Partitioning, OLAP and Data Mining options
ORACLE_HOME= /u01/oracle/product/10.2.0/db_1
Systemname: Linux
Nodename: OA
Release: 2.6.18-128.el5
Version: #1 SMP Wed Dec 17 11:41:38 EST 2008
Machine: x86_64
Instancename: dipdb
Redothread mounted by this instance: 1
Oracleprocess number: 42
Unixprocess pid: 10521, image: oracle@OA (TNS V1-V3)
REDORECORD - Thread:1 RBA: 0x00cf6e.0000000e.0010 LEN: 0x0220 VLD: 0x0d
SCN:0x001b.16034844 SUBSCN: 2 07/19/201314:25:49
CHANGE #1 TYP:2 CLS: 1 AFN:4 DBA:0x01005956 OBJ:224326SCN:0x001b.15fb1f87 SEQ: 1 OP:11.5
KTBRedo
op:0x11 ver: 0x01
op:F xid: 0x0005.017.0001733b uba:0x00800097.eef8.1a
Blockcleanout record, scn: 0x001b.16034843ver: 0x01 opt: 0x02, entries follow...
itli: 2 flg: 2 scn: 0x001b.15fb1f87
KDOOp code: URP row dependencies Disabled
xtype: XA flags: 0x00000000 bdba: 0x01005956 hdba: 0x01005953
itli:1 ispac: 0 maxfr: 4858
tabn:0slot: 7(0x7) flag: 0x2c lock: 1 ckix: 0
ncol:8 nnew: 1 size: 1
col 5: [3] c2 2c 15
-->AFN :绝对文件编号,表示数据库写入到哪个文件中
-->DBA:相对数据库地址,包含相对文件标号和数据块编号,可以通过以前语句查到。
例上面DBA为:0x01005956转换为10进制为:16800086
SQL>select dbms_utility.data_block_address_file(16800086) asrfile,dbms_utility.data_block_address_block(16800086) as block from dual;
RFILE BLOCK
--------------------
4 22870
该变量表示的是我们要做的操作是修改文件4(AFN)中的22870(DBA)这个数据块的第8行(slot)的第5个字段(col),修改为c2 2c 15。
CHANGE #2 TYP:0 CLS:25 AFN:2 DBA:0x00800049OBJ:4294967295SCN:0x001b.16034832 SEQ: 2 OP:5.2
ktudhredo: slt: 0x0017 sqn: 0x0001733b flg: 0x0012 siz: 156 fbi: 0
uba: 0x00800097.eef8.1a pxid: 0x0000.000.00000000
-->第二个矢量向量是分配的左右是负责创建事务表 PS:按道理应该是先分配一个undo段,在undo段中创建一个事务表,才开始事务,不知道这里为什么是先写了数据库的修改(矢量变量1),再分配了undo段。
CHANGE #3 TYP:0 CLS:25 AFN:2 DBA:0x00800049OBJ:4294967295SCN:0x001b.16034844 SEQ: 1 OP:5.4
ktucmredo: slt: 0x0017 sqn: 0x0001733b srt: 0 sta: 9 flg: 0x2
ktucfredo: uba: 0x00800097.eef8.1a ext: 3 spc: 4550 fbi: 0
-->第三个矢量和第二个写的是同一个undo块,分配了两个表,可能是因为改表有外键关系
CHANGE #4 TYP:0 CLS:26 AFN:2 DBA:0x00800097OBJ:4294967295SCN:0x001b.16034832 SEQ: 1 OP:5.1
ktudbredo: siz: 156 spc: 4708 flg: 0x0012 seq: 0xeef8 rec: 0x1a
xid: 0x0005.017.0001733b
ktublredo: slt: 23 rci: 0 opc: 11.1 objn: 224326 objd: 224326 tsn: 4
Undotype: Regular undo Begin trans Last buffer split: No
TempObject: No
TablespaceUndo: No
0x00000000 prev ctl uba: 0x00800097.eef8.19
prevctl max cmt scn: 0x001b.16010657 prev tx cmt scn: 0x001b.1601065b
txnstart scn: 0x0000.00000000 logon user: 92 prev brb: 8388756 prev bcl: 0 KDO undo record:
KTBRedo
op:0x04 ver: 0x01
op:L itl: xid: 0x0005.00a.000172f9 uba: 0x008001ac.eef7.1d
flg: C--- lkc: 0 scn: 0x001b.15fb0f18
KDOOp code: URP row dependencies Disabled
xtype: XA flags: 0x00000000 bdba: 0x01005956 hdba: 0x01005953
itli:1 ispac: 0 maxfr: 4858
tabn:0 slot: 7(0x7) flag: 0x2c lock: 0 ckix: 0
ncol:8 nnew: 1 size: -1
col 5: [ 2] c2 25
-->这个矢量是表示在2号文件的8388759号数据块中保存撤销数据,以保证事务可被回滚。
转换进制可以使用一下语句来验证:
例:
SQL>Select dump(3600,16) from dual;
DUMP(3600,16)
------------------
Typ=2Len=2: c2,25
反向计算的话为:
指数位换算:
正数:指数=符号/指数位 - 193 (最高位为1是代表正数)
负数:指数=62 -第一字节
16进制转化为10进制 c2=194 25=37
194-193=1 指数位为1表示正数
每个<数字位>乘以100^(指数-N) (N是有效位数的顺序位,第一个有效位的N=0)
37-1=36*100^(1-0)=3600
具体算法可以参考: How Oracle Store Number internal?
以上就是一条重做记录的组成。
重要的事:
一个重做记录中记录的操作,需要在记录到log buffer之后,才会按照重做记录去执行。