ITPub博客

首页 > 数据库 > Oracle > 不那么靠谱的ORA_ROWSCN

不那么靠谱的ORA_ROWSCN

原创 Oracle 作者:zhang41082 时间:2019-06-08 17:39:04 0 删除 编辑


很多人都知道ORA_ROWSCN可以表示表中某行记录的SCN号,从这个SCN号可以大致推算出这行记录最后修改的时间是什么时候。不过创建表的时候如 果没有显示的指定表的rowdependencies属性,那么这里的ORA_ROWSCN就是指这个BLOCK中的所有行的最后修改时间,这个时候使用 ORA_ROWSCN来判断单条记录的修改时间就不那么靠谱了(不过标题里的不靠谱并不是指这个),但如果应用比较特殊,比如是记录日志,表中数据不停的 插入,没有更改和删除,那这个ORA_ROWSCN还是可以基本判断每条记录的大致插入时间的,所以这要具体情况具体分析,不能一棍子打死。其实未显示设 置rowdependencies属性的时候,ORA_ROWSCN就是取的BLOCK的SCN,所以就会出现BLOCK中所有记录都是同一个 ORA_ROWSCN。这里的不靠谱讲的是另外一个故事。。。[@more@]

LINUX平台的ORACLE 10G,业务表是压缩表,存放历史数据,每天凌晨把历史数据导入进来,大概整个过程不到20分钟,数据进来后不会做更新、删除等操作。可是凌晨运行的业务无意中却发现通过ORA_ROWSCN转换出来的时间却是下午的时间,吓了一跳,难道凌晨跑完下午还有人更改过这些数据?这不符合业务逻辑的,于是开始深入的查找。

首先来看看这个表里的数据的信息(拿一条数据为例):
SQL> SELECT TO_CHAR(SCN_TO_TIMESTAMP(ORA_ROWSCN), 'yyyy-mm-dd hh24:mi:ss') TM,
2 ORA_ROWSCN,
3 ROWID,
4 DBMS_ROWID.ROWID_RELATIVE_FNO(ROWID) FID,
5 DBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID) BID
6 FROM HISTORY --as of scn 14744229299
7 WHERE ROWID = 'AAA+wtABKAABJCfABW';

TM ORA_ROWSCN ROWID FID BID
------------------- ---------- ------------------ ---------- ----------
2009-12-23 17:05:45 1474422929 AAA+wtABKAABJCfABW 74 299167

这里可以看到,凌晨插入的数据,最后更新时间却变成了下午5点多,而这个表的数据在下午是不会有变化的,更不要说具体到某个BLOCK了,那么就DUMP这个BLOCK出来看看,结果如下:
Start dump data blocks tsn: 35 file#: 74 minblk 299167 maxblk 299167
buffer tsn: 35 rdba: 0x1284909f (74/299167)
scn: 0x0003.6ed70907 seq: 0x01 flg: 0x04 tail: 0x09070601
frmt: 0x02 chkval: 0x1062 type: 0x06=trans data
Hex dump of block: st=0, typ_found=1

这里可以看到BLOCK的SCN为:0x0003.6ed70907,转换成十进制为:14744488199,跟我们查询出来的ORA_ROWSCN对不上,这个SCN转换成时间为:2009-12-23 17:12:59,这就怪异了!!难道中间谁改过这个BLOCK了,立马重新运行上面的查询:
SQL> SELECT TO_CHAR(SCN_TO_TIMESTAMP(ORA_ROWSCN), 'yyyy-mm-dd hh24:mi:ss') TM,
2 ORA_ROWSCN,
3 ROWID,
4 DBMS_ROWID.ROWID_RELATIVE_FNO(ROWID) FID,
5 DBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID) BID
6 FROM HISTORY --as of scn 14744229299
7 WHERE ROWID = 'AAA+wtABKAABJCfABW';

TM ORA_ROWSCN ROWID FID BID
------------------- ---------- ------------------ ---------- ----------
2009-12-23 17:05:45 1474422929 AAA+wtABKAABJCfABW 74 299167

可以看到结果一摸一样,说明ORA_ROWSCN查出来的并不是BLOCK的SCN,而且BLOCK的SCN怎么也会变成下午的SCN号呢?更奇怪的还在下面,我想看看这个表凌晨时候是什么情况,所以使用FLASHBACK QUERY的特性来查查看,先搞个大概的早上的时候的SCN:
SQL> SELECT TO_CHAR(SCN_TO_TIMESTAMP(14730288199), 'yyyy-mm-dd hh24:mi:ss')
2 FROM DUAL;

TO_CHAR(SCN_TO_TIMESTAMP(14730
------------------------------
2009-12-23 09:58:32

那么使用14730288199去FLASHBACK QUERY:
SQL> SELECT TO_CHAR(SCN_TO_TIMESTAMP(ORA_ROWSCN), 'yyyy-mm-dd hh24:mi:ss') TM,
2 ORA_ROWSCN,
3 ROWID,
4 DBMS_ROWID.ROWID_RELATIVE_FNO(ROWID) FID,
5 DBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID) BID
6 FROM HISTORY AS OF SCN 14730288199
7 WHERE ROWID = 'AAA+wtABKAABJCfABW';

TM ORA_ROWSCN ROWID FID BID
------------------- ---------- ------------------ ---------- ----------
2009-12-23 09:58:32 1473028808 AAA+wtABKAABJCfABW 74 299167

这个时候的ORA_ROWSCN往前跳了,跳到了FLASHBACK附近的SCN,但还是不一样的,把SCN再往前挪一点看看:
SQL> SELECT TO_CHAR(SCN_TO_TIMESTAMP(ORA_ROWSCN), 'yyyy-mm-dd hh24:mi:ss') TM,
2 ORA_ROWSCN,
3 ROWID,
4 DBMS_ROWID.ROWID_RELATIVE_FNO(ROWID) FID,
5 DBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID) BID
6 FROM HISTORY AS OF SCN 14730008199
7 WHERE ROWID = 'AAA+wtABKAABJCfABW';

TM ORA_ROWSCN ROWID FID BID
------------------- ---------- ------------------ ---------- ----------
2009-12-23 09:48:30 1473000743 AAA+wtABKAABJCfABW 74 299167

还是一样的情况,那么把这个BLOCK重新DUMP出来看看:
Start dump data blocks tsn: 35 file#: 74 minblk 299167 maxblk 299167
buffer tsn: 35 rdba: 0x1284909f (74/299167)
scn: 0x0003.6ee25256 seq: 0x01 flg: 0x04 tail: 0x52560601
frmt: 0x02 chkval: 0x4e2f type: 0x06=trans data
Hex dump of block: st=0, typ_found=1

BLOCK的SCN为:0x0003.6ee25256,转换成十进制是:14745227862,然后转换成时间:2009-12-23 17:38:37,还是到处对不上。这时我在执行原先的查询(不FLASHBACK):
SQL> SELECT TO_CHAR(SCN_TO_TIMESTAMP(ORA_ROWSCN), 'yyyy-mm-dd hh24:mi:ss') TM,
2 ORA_ROWSCN,
3 ROWID,
4 DBMS_ROWID.ROWID_RELATIVE_FNO(ROWID) FID,
5 DBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID) BID
6 FROM HISTORY --AS OF SCN 14730008199
7 WHERE ROWID = 'AAA+wtABKAABJCfABW';

TM ORA_ROWSCN ROWID FID BID
------------------- ---------- ------------------ ---------- ----------
2009-12-23 09:48:30 1473000743 AAA+wtABKAABJCfABW 74 299167

可以惊奇的看到ORA_ROWSCN固定在之前FLASHBACK QUERY的时候了,完全乱套了,所以这才是标题所指的ORA_ROWSCN不靠谱的原因。相同的测试,在普通表上没有这样的问题,难道是压缩表每次访问的时候进行了一次解压?

无意中发现ITL那边有点线索:
Itl Xid Uba Flag Lck Scn/Fsc
0x01 0x004c.012.000a33b2 0x00000000.0000.00 C-U- 0 scn 0x0003.6dfa1386

其中的SCN 0x0003.6dfa1386转换成十进制:14730007430,居然正好是ORA_ROWSCN的值,而且FLASHBACK的SCN如果往后跳的话,这个值不变,查询出来的ORA_ROWSCN也不变,并且重新开其他的SESSION查询结果也一样。但是当FLASHBACK QUERY的SCN往前跳的时候,这里的SCN也跟着往前跳,并且等于ITL这里显示的SCN(不是每跳一个SCN都会改变这里的ORA_ROWSCN,是要跳一段,至于这个段是多大?疑惑中)。然后当你干脆跳到这条记录插入之前的SCN,这时候查询记录结果为空,然后再把SCN往后挪,挪到记录插入之后的时间,之后再显示的SCN就是记录真正插入的时候的SCN了:
SQL> SELECT TO_CHAR(SCN_TO_TIMESTAMP(ORA_ROWSCN), 'yyyy-mm-dd hh24:mi:ss') TM,
2 ORA_ROWSCN,
3 ROWID,
4 DBMS_ROWID.ROWID_RELATIVE_FNO(ROWID) FID,
5 DBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID) BID
6 FROM SEASHELL.BALANCE_HISTORY AS OF SCN 14730000000
7 WHERE ROWID = 'AAA+wtABKAABJCfABW';

TM ORA_ROWSCN ROWID FID BID
------------------- ---------- ------------------ ---------- ----------
2009-12-23 07:51:55 1472795708 AAA+wtABKAABJCfABW 74 299167

凌晨7点多,这个时间才是记录真正进来的时间!

那么,疑惑还没有解开,还得来看看ITL这里显示的SCN/FSC是何方神圣。这里的SCN和FSC其实就是这个ITL对应的事务提交时候的SCN,那么这里所有槽位上的最大的一个SCN号就表示这个BLOCK最后被更新的时候的SCN。之所以使用SCN和FSC来区分开来,是因为这里还涉及到一个延迟块清除的问题。如果是延迟块清除,那这里就显示的是SCN;如果没有延迟的,那这里显示的就是FSN。

又来回折腾了几次,发现压缩表每次都很不靠谱,没思路了,不过发现在FLASHBACK的时候,有时候ORA_ROWSCN显示的并不是BLOCK HEADER的SCN而是ITL这里的SCN。

总之,对于压缩表的ORA_ROWSCN使用要小心,不知道是不是因为查询的时候要解压,然后解压的时候也去更新这个SCN?





UPDATE:
了解到延迟块清除后,难道这些BLOCK是因为这个原因?还没有COMMIT的时候,BLOCK已经写入磁盘了,然后到查询之前一直没有人来读取过,所以在读取的时候会清除BLOCK上的事务的信息,那么BLOCK_HEADER的SCN就变成了ITL上的事务对应的UNDO段的CONTROL SCN?


来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/25016/viewspace-1030149/,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论

注册时间:2002-10-11

  • 博文量
    105
  • 访问量
    80926