生活随笔
收集整理的這篇文章主要介紹了
基于SCN的查询(AS OF SCN)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
仍以前文中創建的表為例,既然是基于SCN的查詢,我們首先就需要得到SCN,這里我們通過DBMS_FLASHBACK.GET_SYSTEM_CHANGE_NUMBER函數來獲取Oracle當前的SCN,之后再執行數據的修改操作
提 示
如何獲取Oracle數據庫當前的SCN?
獲取當前SCN的方式非常多,除了使用DBMS_FLASHBACK.GET_SYSTEM_CHANGE_NUMBER函數外,也可以通過查詢V$DATABASE視圖中的CURRENT_SCN列獲取。不過,不管是通過查詢視圖,或是通過過程獲取,操作的用戶都必須擁有要操作對象的訪問權限。
例如,授予用戶使用DBMS_FLASHBACK包的權限:
JSSPRE>?CONN/AS?SYSDBA ?Connected. ?JSSPRE>?GRANT?EXECUTE?ON?DBMS_FLASHBACK?TO?SCOTT; ?Grant?succeeded.?
又如,授予用戶查詢V$DATABASE視圖的權限:
JSSPRE>?CONN/AS?SYSDBA ?Connected. ?JSSPRE>?GRANT?SELECT?ON?V_$DATABASE?TO?SCOTT; ?Grant?succeeded.?
使用DBMS_FLASHBACK包獲取當前的SCN,然后執行刪除操作并提交:
JSSPRE>?SELECT?DBMS_FLASHBACK.GET_SYSTEM_CHANGE_NUMBER?FROM?DUAL; ?GET_SYSTEM_CHANGE_NUMBER ???????????????????1257245 ?JSSPRE>?DELETE?FLASH_TBL?WHERE?ID>10; ?10?rows?deleted. ?JSSPRE>?COMMIT; ?Commit?complete.?
執行SELECT語句并附加AS OF SCN子句,同時指定刪除前的SCN,就可以查詢到指定SCN時對象中的記錄:
JSSPRE>?SELECT?*?FROM?FLASH_TBL?AS?OF?SCN?1257245; ?????ID??VL ??????10??K ?????11??L ?????12??M ?????13??N ?????14??O ?????15??P ?????16??Q ?????17??R ?????18??S ?????19??T ?????20??U ?????1???A ?????2???B ?????3???C ?????4???D ?????5???E ?????6???F ?????7???G ?????8???H ?????9???I ?20?rows?selected.?
執行INSERT,將刪除的數據重新恢復回表JSS_TB1:
JSSPRE>?INSERT?INTO?FLASH_TBL?SELECT?*?FROM?FLASH_TBL? ?AS?OF?SCN?1257245?WHERE?ID>10; ?10?rows?created. ?JSSPRE>?commit; ?Commit?complete.?
使用SCN查詢會比TIMESTAMP更加精確,事實上,即使執行Flashback Query時指定的是AS OF TIMESTAMP,Oracle也會將其轉換成SCN,這是由于Oracle內部都是通過SCN來標記操作而不是時間。
不過在實際執行Flashback Query時,時間轉換后具體對應哪個SCN,是通過SYS用戶下的一個數據字典實現的,即SMON_SCN_TIME(時間與SCN的映射關系表):
JSSPRE>?DESC?SYS.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?
在10g中,系統平均每3秒產生一次系統時間與SCN的匹配并存入SYS.SMON_SCN_ TIME表,因此10g版本如果使用AS OF TIMESTAMP查詢UNDO中的數據,實際獲取的數據是以指定的時間對應的SCN時的數據為基準。
舉個例子,如SCN:339988,339989分別匹配2009-05-30 13:52:00和2009-05-30 13:57:00,則當你通過AS OF TIMESTAMP查詢2009-05-30 13:52:00或2009-05-30 13:56:59這段時間點內的任何時間,oracle都會將其匹配為SCN:339988到UNDO表空間中查找,也就說在這個時間內,不管你指定的時間點是什么,查詢返回的都將是2009-05-30 13:52:00這個時刻對應的SCN的數據。如果通過上述文字的描述仍覺得不夠形象,我想你親自執行一下SELECT SCN,TO_CHAR(TIME_DP,'YYYY-MM-DD HH24:MI:SS')FROM SYS.SMON_ SCN_TIME,會理解得更深刻一些。
在Oracle數據庫中也可以手動進行時間和SCN的相互轉換,Oracle提供了兩個函數SCN_TO_TIMESTAMP和TIMESTAMP_TO_SCN專門干這個,例如:
JSSPRE>?SELECT?TIMESTAMP_TO_SCN(SYSDATE)?FROM?DUAL; ?TIMESTAMP_TO_SCN(SYSDATE) ????????????????????1263291 ?JSSPRE>?SELECT?TO_CHAR(SCN_TO_TIMESTAMP(1263291),? ?'YYYY-MM-DD')?FROM?DUAL; ?TO_CHAR(SC ??2009-06-02?
提 示
上面的示例中TIMESTAMP類型經過TO_CHAR格式化,只顯示了日期,千萬別以為只能精確到日期喲。Oracle中的TIMESTAMP日期類型最大能夠精確到納秒(不過一般操作系統返回的精度只到毫秒,因此即使格式化顯示出納秒的精度也沒意義,毫秒后就全是零了)。
看起來很強大吧?其實這兩個函數的轉換依賴于SYS.SMON_SCN_TIME表,能夠轉換到的最小SCN,也正是這個表中的最小記錄,例如:
JSSPRE>?SELECT?SCN_WRP*4294967296+SCN_BAS?FROM?SYS.SMON_SCN_TIME ???2??WHERE?TIME_MP=(SELECT?MIN(TIME_MP)?FROM?SYS.SMON_SCN_TIME); ?SCN_WRP*4294967296+SCN_BAS ??????????????????????554140?
能夠轉換到的最小SCN值是554140,使用SCN_TO_TIMESTAMP查詢該SCN對應的時間:
JSSPRE>?SELECT?SCN_TO_TIMESTAMP(554140)?FROM?DUAL; ?SCN_TO_TIMESTAMP(554140) ??21-MAR-09?11.51.30.000000000?PM?
比該SCN哪怕只再小1的值也無法轉換了,因為SYS.SMON_SCN_TIME表中沒有對應的映射關系:
JSSPRE>?SELECT?SCN_TO_TIMESTAMP(554139)?FROM?DUAL; ?select?scn_to_timestamp(554139)?from?dual ????????* ?ERROR?at?line?1: ?ORA-08181:?specified?number?is?not?a?valid?system?change?number ?ORA-06512:?at?"SYS.SCN_TO_TIMESTAMP",?line?1?
時間的轉換也是同理,所以你看,如果SYS.SMON_SCN_TIME表中不存在時間和SCN的映射關系,則執行函數轉換時就會報錯,也就是說時間和SCN之間并不存在絕對的對應關系。一切都是Oracle提供給你的,只有當它愿意讓你看,你才能夠看到。
總結
以上是生活随笔為你收集整理的基于SCN的查询(AS OF SCN)的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。