SMON後臺進程的作用還包括維護SMON_SCN_TIME基表。
SMON_SCN_TIME基表用於記錄過去時間段中SCN(system change number)與具體的時間戳(timestamp)之間的映射關係,因爲是採樣記錄這種映射關係,所以SMON_SCN_TIME可以較爲較爲粗糙地(不精確地)定位某個SCN的時間信息。實際的SMON_SCN_TIME是一張cluster table簇表。
SMON_SCN_TIME時間映射表最大的用途是爲閃回類型的查詢(flashback type queries)提供一種將時間映射爲SCN的途徑(The SMON time mapping is mainly for flashback type queries to map a time to an SCN)。
Metalink文檔<Error ORA-01466 while executing a flashback query. [ID 281510.1]>介紹了SMON更新SMON_SCN_TIME的規律:
- 在版本10g中SMON_SCN_TIME每6秒鐘被更新一次(In Oracle Database 10g, smon_scn_time is updated every 6 seconds hence that is the minimum time that the flashback query time needs to be behind the timestamp of the first change to the table.)
- 在版本9.2中SMON_SCN_TIME每5分鐘被更新一次(In Oracle Database 9.2, smon_scn_time is updated every 5 minutes hence the required delay between the flashback time and table properties change is at least 5 minutes.)
另外從10g開始SMON也會清理SMON_SCN_TIME中的記錄了,SMON後臺進程會每5分鐘被喚醒一次,檢查SMON_SCN_TIME在磁盤上的映射記錄總數,若總數超過144000條,則會使用以下語句刪除最老的一條記錄(time_mp最小):
delete from smon_scn_time where thread = 0 and time_mp = (select min(time_mp) from smon_scn_time where thread = 0)
若僅僅刪除一條記錄不足以獲得足夠的空間,那麼SMON會反覆多次執行以上DELETE語句。
觸發場景
雖然Metalink文檔<Error ORA-01466 while executing a flashback query. [ID 281510.1]>指出了在10g中SMON會以每6秒一次的頻率更新SMON_SCN_TIME基表,但是實際觀測可以發現更新頻率與SCN的增長速率相關,在較爲繁忙的實例中SCN的上升極快時SMON可能會以6秒一次的最短間隔頻率更新 , 但是在空閒的實例中SCN增長較慢,則仍會以每5或10分鐘一次頻率更新,例如:
[oracle@vrh8 ~]$ ps -ef|grep smon|grep -v grep oracle 3484 1 0 Nov12 ? 00:00:02 ora_smon_G10R21 SQL> select * from v$version; BANNER ---------------------------------------------------------------- Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - 64bi PL/SQL Release 10.2.0.1.0 - Production CORE 10.2.0.1.0 Production TNS for Linux: Version 10.2.0.1.0 - Production NLSRTL Version 10.2.0.1.0 - Production SQL> select * from global_name; GLOBAL_NAME -------------------------------------------------------------------------------- www.askmaclean.com & www.askmaclean.com SQL> oradebug setospid 3484; Oracle pid: 8, Unix process pid: 3484, image: [email protected] (SMON) SQL> oradebug event 10500 trace name context forever,level 10 : 10046 trace name context forever,level 12; Statement processed. SQL> SQL> oradebug tracefile_name; /s01/admin/G10R21/bdump/g10r21_smon_3484.trc /* 等待一定時間 */
找出SMON trace文件中insert數據到SMON_SCN_TIME的記錄:
grep -A20 "insert into smon_scn_time" /s01/admin/G10R21/bdump/g10r21_smon_3484.trc insert into smon_scn_time (thread, time_mp, time_dp, scn, scn_wrp, scn_bas, num_mappings, tim_scn_map) values (0, :1, :2, :3, :4, :5, :6, :7) END OF STMT PARSE #4:c=0,e=43,p=0,cr=0,cu=0,mis=0,r=0,dep=1,og=4,tim=1290280848899596 BINDS #4: kkscoacd Bind#0 oacdty=02 mxl=22(22) mxlc=00 mal=00 scl=00 pre=00 oacflg=00 fl2=0001 frm=00 csi=00 siz=24 off=0 kxsbbbfp=7fb29844edb8 bln=22 avl=06 flg=05 value=767145793 Bind#1 oacdty=12 mxl=07(07) mxlc=00 mal=00 scl=00 pre=00 oacflg=10 fl2=0001 frm=00 csi=00 siz=8 off=0 kxsbbbfp=7fff023ae780 bln=07 avl=07 flg=09 value="11/14/2011 0:3:13" Bind#2 oacdty=02 mxl=22(04) mxlc=00 mal=00 scl=00 pre=00 oacflg=10 fl2=0001 frm=00 csi=00 siz=24 off=0 kxsbbbfp=7fff023ae70c bln=22 avl=04 flg=09 value=954389 Bind#3 -- insert into smon_scn_time (thread, time_mp, time_dp, scn, scn_wrp, scn_bas, num_mappings, tim_scn_map) values (0, :1, :2, :3, :4, :5, :6, :7) END OF STMT PARSE #1:c=0,e=21,p=0,cr=0,cu=0,mis=0,r=0,dep=1,og=4,tim=1290281434933390 BINDS #1: kkscoacd Bind#0 oacdty=02 mxl=22(22) mxlc=00 mal=00 scl=00 pre=00 oacflg=00 fl2=0001 frm=00 csi=00 siz=24 off=0 kxsbbbfp=7fb29844edb8 bln=22 avl=06 flg=05 value=767146393 Bind#1 oacdty=12 mxl=07(07) mxlc=00 mal=00 scl=00 pre=00 oacflg=10 fl2=0001 frm=00 csi=00 siz=8 off=0 kxsbbbfp=7fff023ae780 bln=07 avl=07 flg=09 value="11/14/2011 0:13:13" Bind#2 oacdty=02 mxl=22(04) mxlc=00 mal=00 scl=00 pre=00 oacflg=10 fl2=0001 frm=00 csi=00 siz=24 off=0 kxsbbbfp=7fff023ae70c bln=22 avl=04 flg=09 value=954720 Bind#3 -- insert into smon_scn_time (thread, time_mp, time_dp, scn, scn_wrp, scn_bas, num_mappings, tim_scn_map) values (0, :1, :2, :3, :4, :5, :6, :7) END OF STMT PARSE #3:c=0,e=20,p=0,cr=0,cu=0,mis=0,r=0,dep=1,og=4,tim=1290281727955249 BINDS #3: kkscoacd Bind#0 oacdty=02 mxl=22(22) mxlc=00 mal=00 scl=00 pre=00 oacflg=00 fl2=0001 frm=00 csi=00 siz=24 off=0 kxsbbbfp=7fb29844e960 bln=22 avl=06 flg=05 value=767146993 Bind#1 oacdty=12 mxl=07(07) mxlc=00 mal=00 scl=00 pre=00 oacflg=10 fl2=0001 frm=00 csi=00 siz=8 off=0 kxsbbbfp=7fff023ae780 bln=07 avl=07 flg=09 value="11/14/2011 0:23:13" Bind#2 oacdty=02 mxl=22(04) mxlc=00 mal=00 scl=00 pre=00 oacflg=10 fl2=0001 frm=00 csi=00 siz=24 off=0 kxsbbbfp=7fff023ae70c bln=22 avl=04 flg=09 value=954926 Bind#3 insert into smon_scn_time (thread, time_mp, time_dp, scn, scn_wrp, scn_bas, num_mappings, tim_scn_map) values (0, :1, :2, :3, :4, :5, :6, :7) END OF STMT PARSE #4:c=0,e=30,p=0,cr=0,cu=0,mis=0,r=0,dep=1,og=4,tim=1290282313990553 BINDS #4: kkscoacd Bind#0 oacdty=02 mxl=22(22) mxlc=00 mal=00 scl=00 pre=00 oacflg=00 fl2=0001 frm=00 csi=00 siz=24 off=0 kxsbbbfp=7fb29844edb8 bln=22 avl=06 flg=05 value=767147294 Bind#1 oacdty=12 mxl=07(07) mxlc=00 mal=00 scl=00 pre=00 oacflg=10 fl2=0001 frm=00 csi=00 siz=8 off=0 kxsbbbfp=7fff023ae780 bln=07 avl=07 flg=09 value="11/14/2011 0:28:14" Bind#2 oacdty=02 mxl=22(04) mxlc=00 mal=00 scl=00 pre=00 oacflg=10 fl2=0001 frm=00 csi=00 siz=24 off=0 kxsbbbfp=7fff023ae70c bln=22 avl=04 flg=09 value=955036 Bind#3
可以通過以上INSERT語句的TIME_DP綁定變量值中發現其更新SMON_SCN_TIME的時間規律,一般爲5或10分鐘一次。這說明SMON_SCN_TIME的更細頻率與數據庫實例的負載有關,其最短的間隔是每6秒一次,最長的間隔爲10分鐘一次。
由於SMON_SCN_TIME的更新頻率問題可能引起ORA-01466錯誤,詳見:
Error ORA-01466 while executing a flashback query. [ID 281510.1]
由於SMON_SCN_TIME的數據不一致可能引起ORA-00600[6711]或頻繁地執行”delete from smon_scn_time”刪除語句,詳見:
ORA-00600[6711]錯誤一例
High Executions Of Statement “delete from smon_scn_time…” [ID 375401.1]
SMON維護SMON_SCN_TIME時相關的Stack CALL,ktf_scn_time是更新SMON_SCN_TIME的主要函數:
ksedst ksedmp ssexhd kghlkremf kghalo kghgex kghalf kksLoadChild kxsGetRuntimeLock kksfbc
kkspsc0 kksParseCursor opiosq0 opiall0 opikpr opiodr rpidrus skgmstack rpidru rpiswu2 kprball
ktf_scn_time
ktmmon ktmSmonMain ksbrdp opirip opidrv sou2o opimai_real main main_opd_entry
SMON 還可能使用以下SQL語句維護SMON_SCN_TIME字典基表:
select smontabv.cnt, smontab.time_mp, smontab.scn, smontab.num_mappings, smontab.tim_scn_map, smontab.orig_thread from smon_scn_time smontab, (select max(scn) scnmax, count(*) + sum(NVL2(TIM_SCN_MAP, NUM_MAPPINGS, 0)) cnt from smon_scn_time where thread = 0) smontabv where smontab.scn = smontabv.scnmax and thread = 0 insert into smon_scn_time (thread, time_mp, time_dp, scn, scn_wrp, scn_bas, num_mappings, tim_scn_map) values (0, :1, :2, :3, :4, :5, :6, :7) update smon_scn_time set orig_thread = 0, time_mp = :1, time_dp = :2, scn = :3, scn_wrp = :4, scn_bas = :5, num_mappings = :6, tim_scn_map = :7 where thread = 0 and scn = (select min(scn) from smon_scn_time where thread = 0) delete from smon_scn_time where thread = 0 and scn = (select min(scn) from smon_scn_time where thread = 0)
如何禁止SMON更新SMON_SCN_TIME基表
可以通過設置診斷事件event=’12500 trace name context forever, level 10’來禁止SMON更新SMON_SCN_TIME基表(Setting the 12500 event at system level should stop SMON from updating the SMON_SCN_TIME table.):
SQL> alter system set events '12500 trace name context forever, level 10'; System altered.
一般我們不推薦禁止SMON更新SMON_SCN_TIME基表,因爲這樣會影響flashback Query閃回查詢的正常使用,但是在某些異常恢復的場景中SMON_SCN_TIME數據訛誤可能導致實例的Crash,那麼可以利用以上12500事件做到不觸發SMON_SCN_TIME被更新。
如何手動清除SMON_SCN_TIME的數據
因爲SMON_SCN_TIME不是bootstrap自舉核心對象,所以我們可以手動更新該表上的數據、及重建其索引。
如我在<ORA-00600[6711]錯誤一例>中介紹了因爲SMON_SCN_TIME與其索引的數據不一致時,可以通過重建索引來解決問題:
connect / as sysdba drop index smon_scn_time_scn_idx; drop index smon_scn_time_tim_idx; create unique index smon_scn_time_scn_idx on smon_scn_time(scn); create unique index smon_scn_time_tim_idx on smon_scn_time(time_mp); analyze table smon_scn_time validate structure cascade;
可以在設置了12500事件後手動刪除SMON_SCN_TIME上的記錄,重啓實例後SMON會繼續正常更新SMON_SCN_TIME。除非是因爲SMON_SCN_TIME表上的記錄與索引smon_scn_time_tim_idx或smon_scn_time_scn_idx上的不一致造成DELETE語句無法有效刪除該表上的記錄:文檔<LOCK ON SYS.SMON_SCN_TIME [ID 747745.1]>說明了該問題,否則我們沒有必要手動去清除SMON_SCN_TIME上的數據。
具體方法如下:
SQL> conn / as sysdba /* Set the event at system level */ SQL> alter system set events '12500 trace name context forever, level 10'; /* Delete the records from SMON_SCN_TIME */ SQL> delete from smon_scn_time; SQL> commit; SQL> alter system set events '12500 trace name context off'; 完成以上步驟後重啓實例restart instance shutdown immediate; startup;
SMON_SCN_TIME表存放的是SCN和Time之前的映射關係。 該表由SMON 進程負責維護。
SQL> desc smon_scn_time
Name Null? Type
------------------------------------------------- ----------------------------
THREAD NUMBER
TIME_MP NUMBER
TIME_DP DATE
SCN_WRP NUMBER
SCN_BAS NUMBER
NUM_MAPPINGS NUMBER
TIM_SCN_MAP RAW(1200)
SCN NUMBER
ORIG_THREAD NUMBER
SQL> alter session set nls_date_format='yyyy-mm-ddhh24:mi:ss';
Session altered.
SQL> select time_dp,scn from smon_scn_time where rownum<5;
TIME_DP SCN
------------------- ----------
2013-03-15 10:31:04 2092348
2013-03-15 10:35:49 2092452
2013-03-15 10:41:00 2092581
2013-03-15 10:45:46 2092682
在Oracle 11g中,該表的創建SQL在$ORACLE_HOME/rdbms/admin/dtxnspc.bsq 文件中。
create table smon_scn_time (
thread number, /* thread, compatibility */
time_mp number, /* time this recent scn represents */
time_dp date, /* time as date, compatibility */
scn_wrpnumber, /*scn.wrp, compatibility */
scn_bas number, /* scn.bas, compatibility */
num_mappings number,
tim_scn_map raw(1200),
scnnumber default 0, /* scn*/
orig_thread number default 0 /* for downgrade */
) cluster smon_scn_to_time_aux (thread)
/
create unique index smon_scn_time_tim_idxon smon_scn_time(time_mp)
tablespace SYSAUX
/
create unique index smon_scn_time_scn_idxon smon_scn_time(scn)
tablespace SYSAUX
/
我們可以直接delete掉SMON_SCN_TIME表中的記錄:
SQL> delete from smon_scn_time;
2120 rows deleted.
SQL> commit;
Commit complete.
SQL> select count(1) from smon_scn_time;
COUNT(1)
----------
0
二.SMON_SCN_TIME表記錄保存策略說明
2.1 Oracle 9i
根據MOS文檔的說明:
How To Map SCN To Timestamp Before 10g? [ID365536.1]
SYS.SMON_SCN_TIMEwill have a maximum of 1440 rows and each record will be for a 5 minute period.Oracle maintains this information for a maximum of 5 days after which therecords will be recycled.
This means thatdata is stored 12 times per hour * 24 hours * 5 days = 1440 rows.
在Oracle 9i版本中,SMON_SCN_TIME 表中最多存放1440條記錄。 SMON 進程每隔5分鐘生成一次SCN和TIME 之前的映射,並更新到SMON_SCN_TIME表。該表的維護週期是5天。
因此該表最多存放的記錄是:12*24*5=1440條記錄。
超過1440條的記錄在下次循環中會被刪除。
2.2 Oracle 10g以後的版本
在oracle 10g以後的版本,SMON_SCN_TIME表的維護策略發生了變化。
根據MOS文檔的說明:
High Executions Of Statement "deletefrom smon_scn_time..." [ID 375401.1]
The deletestatement deletes the oldest rows from smon_scn_time to clear space for newrows. SMON wakes up every 5 minutes and checks how many on-disk mappingswe have--the max is 144000.
--SMON進程每個5分鐘喚醒一次來更新SCN和TIME之間的映射關係,並且檢查SMON_SCN_TIME表中的記錄數,該表的記錄數最大是144000條。
The new mappingsare then added for the last period (since SMON last updated), and if this isover 144000, SMON will then issue the delete statement:
delete fromsmon_scn_time where thread=0 and time_mp = (select min(time_mp) fromsmon_scn_time where thread=0)
--SMON進程會把最新的SCN_TIME映射關係寫入SMON_SCN_TIME表,如果該表的記錄數超過144000條,那麼就會執行上面的delete操作,刪除最早的記錄。
There will be anexecution of this each time SMON wakes to update smon_scn_time, and if onedeletion does not free enough mappings, then there will be multiple executions.
--SMON進程每次被喚醒都會更新SMON_SCN_TIME表,如果一次delete操作不能釋放足夠的空間映射空間,就會執行多次delete操作。
三.禁用SMON 進程對SMON_SCN_TIME 表的更新
可以設置12500事件停止SMON進程對SMON_SCN_TIME。
具體操作如下:
SQL> select count(1) from smon_scn_time;
COUNT(1)
----------
2115
SQL> alter system set events '12500trace name context forever, level 10';
System altered.
SQL> select sysdate from dual;
SYSDATE
-------------------
2013-03-20 13:06:15
SQL> select count(1) from smon_scn_time;
COUNT(1)
----------
2115
SQL> alter system set events '12500 tracename context off';
System altered.
SQL> select sysdate from dual;
SYSDATE
-------------------
2013-03-20 13:19:58
SQL> select count(1) from smon_scn_time;
COUNT(1)
----------
2119
四.SMON_SCN_TIME 表相關的2個案例
4.1 Oracle 9i SMON_SCN_TIME 表被鎖
LOCK ON SYS.SMON_SCN_TIME [ID 747745.1]
4.1.1 現象
Oracle 9i,SYS.SMON_SCN_TIME 被 SMON 進程已排它鎖佔用,並且鎖不能釋放,導致數據庫出現性能問題,並且SMON_SCN_TIME表中有大量的記錄。
SQL> selectcount(*) from sys.smon_scn_time;
COUNT(*) ---------- 137545 1 row selected.
--正常情況下,9i最多隻能保存1440條記錄。
SQL> select object_id from dba_objectswhere object_name = 'SMON_SCN_TIME'; OBJECT_ID ---------- 575 1 row selected.
SQL> select * fromv$locked_object where object_id = 575;
XIDUSNXIDSLOT XIDSQN OBJECT_ID SESSION_ID ---------- ---------- ---------- ---------- ---------- ORACLE_USERNAME OS_USER_NAME PROCESS ------------------------------ ------------------------------ ------------ LOCKED_MODE ----------- 5 5 1494 575 164 dbadmin 4444350 3 <=Locked in row exclusive mode
4.1.2 處理方法
設置12500事件,停止SMON 進程更新SMON_SCN_TIME表,然後手工刪除表中的記錄。
SQL> alter system set events '12500 tracename context forever, level 10';
SQL> delete from smon_scn_time;
SQL> commit;
SQL> alter system set events '12500 tracename context off';
Now restart the instance.
4.2 Oracle 10g SMON_SCN_TIME 表頻繁的被delete
High Executions Of Statement "deletefrom smon_scn_time..." [ID 375401.1]
4.2.1 現象
AWR報告顯示smon_scn_time的刪除操作頻繁的被執行。
delete fromsmon_scn_time where thread=0 and time_mp = (select min(time_mp) fromsmon_scn_time where thread=0);
導致這種現象的原因是SMON_SCN_TIME表和表上的索引不一致。需要重建SMON_SCN_TIME上的索引。
SQL> analyze table smon_scn_timevalidate structure cascade; analyze table smon_scn_time validate structure cascade * ERROR at line 1 : ORA-01499: table/Index Cross Reference Failure - see trace file
4.2.2 處理方法
connect / as sysdba drop index smon_scn_time_scn_idx; drop index smon_scn_time_tim_idx; create unique index smon_scn_time_scn_idx on smon_scn_time(scn); create unique index smon_scn_time_tim_idx on smon_scn_time(time_mp); analyze table smon_scn_time validate structure cascade;