首页 > Linux操作系统 > Linux操作系统 > 完全无事务的数据库SCN增长之谜
在深入区有一个帖子讨论一个没有任何事务的Oracle数据库如果一直打开,那么SCN会不会增大?
http://www.itpub.net/thread-1221754-1-1.html
现象是显而易见的,SCN会随时间而增加。
然后有人说:SCN就像Oracle的一个内部时钟一样,会随时间的增加而相应的增加。
再然后又有人会问:SCN的增加到底是不是因为Oracle后台进程做了一些内部的change?
对于Oracle内部时钟的比喻,我觉得是非常感性的认识,很形象地描述了一种实际存在并发生的现象。但是我实在是非常好奇,Oracle自己到底是如何维护这个内部时钟的呢?
对于SCN是否是Oracle后台进程的内部change导致的,我起初是非常赞同的,因为我觉得这种解释是非常理性也看似合理的。
最后所有的问题还是通过自己的实验得到了验证,原来这里面其实包含了两种Oracle的行为,所以非常容易混淆大家的思路。
第一种行为是Oracle的内部每三秒的heartbeat checkpoint,它不产生任何redo,但是会增加SCN+1。
第二种行为是Oracle的内部维护一张SCN和时间的mapping关系的表--SMON_SCN_TIME,在9i中这个表大约每5分钟被更新一次。它会产生redo,当然也会增大SCN。这种行为是由SMON后台进程产生的。
由于这两种行为的共同作用,于是产生了我们可以看见的现象:SCN在完全没事务发生的数据库中增加了,redo也增加了。
结论阐明了,那么我是如何得出这两个结论的呢?
通过如下实验(也在我的回帖中)。
1.每三秒的heartbeat checkpoint产生的SCN+1
SQL> select sysdate,dbms_flashback.get_system_change_number scn from dual;
SYSDATE SCN
----------------- --------------------
20091010 22:50:19 11723811783
SQL> /
SYSDATE SCN
----------------- --------------------
20091010 22:50:20 11723811784
SQL> /
SYSDATE SCN
----------------- --------------------
20091010 22:50:22 11723811785
首先从一次的结果来看,确实是一个scn差了3秒。
让我们等待更久一点
SQL> /
SYSDATE SCN
----------------- --------------------
20091010 22:51:00 11723811797
SQL> /
SYSDATE SCN
----------------- --------------------
20091010 22:51:29 11723811806
两者时间相差29s,SCN相差trunc(29/3)=9
SQL> select sysdate,dbms_flashback.get_system_change_number scn from dual;
SYSDATE SCN
----------------- --------------------
20091010 23:02:05 11723812015
SQL> /
SYSDATE SCN
----------------- --------------------
20091010 23:03:55 11723812051
两者时间相差110s,SCN相差trunc(110/3)=36
于是查询v$sysstat的redo size,会发现一点都没有变。
SQL> select sysdate,s.value
2 from v$sysstat s,v$statname n
3 where s.STATISTIC#=n.STATISTIC#
and n.name='redo size'; 4
SYSDATE VALUE
----------------- --------------------
20091010 23:06:26 66608
SQL> /
SYSDATE VALUE
----------------- --------------------
20091010 23:08:00 66608
2.但是从更长的时间上来看,除了这每隔三秒增加的1个scn,还有其他scn增加,也有redo的少量产生,所以我认为我们应该区分开来前者和后者。
于是现在我需要寻找到底是谁产生了除了每隔3s产生的这个scn以外的scn和redo。
结论2:在空闲状态下的DB会产生一定的redo,而这些redo是由SMON后台进程产生的。
create table stat1 as select * from v$sesstat;
SQL>select sysdate,s.value
from v$sysstat s,v$statname n
where s.STATISTIC#=n.STATISTIC#
and n.name='redo size';
SYSDATE VALUE
----------------- --------------------
20091010 23:17:55 221544
SQL> select sysdate,s.value
from v$sysstat s,v$statname n
where s.STATISTIC#=n.STATISTIC#
and n.name='redo size';
SYSDATE VALUE
----------------- --------------------
20091010 23:26:37 227980
create table stat2 as select * from v$sesstat;
我们可以看到两个时间点相差了227980-221544=6436的redo。
SQL> select stat1.sid,n.name,stat1.value,stat2.value,
2 stat1.value-stat2.value diff
from stat1,stat2,v$statname n
where stat1.sid=stat2.sid
and stat1.STATISTIC#=stat2.STATISTIC#
and stat1.STATISTIC#=n.STATISTIC#
and stat1.value<>stat2.value
and n.name='redo size'
order by stat1.sid,diff
; 3 4 5 6 7 8 9 10
SID NAME VALUE VALUE DIFF
---------- ---------------------------------------------------------------- ---------- ---------- ----------
8 redo size 21776 28212 -6436
13 redo size 128200 164712 -36512
sid 13是我建stat1、2表的session,而sid 8 恰好就是产生着多余的6436 redo的 session。
我们可以看出redo的差量完全吻合。
ora sid2pid 8
Connected.
SPID sid/serial PROGRAM SQL_HASH_VALUE PREV_HASH_VALUE
------------ ---------- ------------------------------------------------ -------------- ---------------
23823 8,1 878649' where "THREAD" = '1' and "TIME_MP" = '1230774206' and "TIME_DP" = TO_DATE('31-DEC-08', 'DD-MON-RR') and "SCN_WRP" = '2' and "SCN_BAS
" = '3133713182' and ROWID = 'AAAAICAABAAADqRACn';
8
1.1724E+10 20091010 23:57:43
commit;
8
3 rows selected.
原来,我们都错怪SMON了,他产生了这些redo,原来是为了更新我们的SMON_SCN_TIME这个表。
这个表是作为time和scn的一个mapping关系,是需要时时更新的。
终于,知道原因了,可以睡个好觉了~
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/15415488/viewspace-616264/ ,如需转载,请注明出处,否则将追究法律责任。