【體系結構】有關Oracle SCN知識點的整理


體系結構有關Oracle SCN知識點整理

 BLOG文檔結構圖

wpsDE64.tmp_thumb 
BLOG_Oracle_lhr_Oracle SCN的一點研究.pdf

 

 前言部分

2.1  導讀和注意事項

各位技術愛好者,看完本文后,你可以掌握如下的技能,也可以學到一些其它你所不知道的知識,~O(∩_∩)O~

① Oracle中的SCN是什么?(重點)

② 如何查詢SCN?(重點)

③ SCN有哪些分類?(重點)

④ SCN和系統恢復的關系?(重點)

④ 實例恢復和介質恢復的區別是什么?RAC中的實例恢復是什么樣的?(重點)

⑥ SCN和時間的轉換

⑦ SMON_SCN_TIME系統表的認識

⑧ 不完全恢復的一些分類及其寫法

Tips

① 本文在itpubhttp://blog.itpub.net/26736162)、博客園(http://www.cnblogs.com/lhrbest)和微信公眾號(xiaomaimiaolhr有同步更新

② 文章中用到的所有代碼相關軟件相關資料及本文的pdf版本都請前往小麥苗的360雲盤下載,我的360雲盤地址見:http://blog.itpub.net/26736162/viewspace-1624453/

③ 若網頁文章代碼格式有錯亂,請嘗試以下辦法:使用360瀏覽器去博客園地址閱讀下載pdf格式的文檔來閱讀

④ 本篇BLOG,代碼輸出部分一般放在一行一列的表格中。其中,需要特別關注的地方我都用灰色背景和粉紅色字體來表示,比如下邊的例子中,thread 1的最大歸檔日志號為33thread 2的最大歸檔日志號為43是需要特別關注的地方;而命令一般使用黃色背景和紅色字體注;對代碼或代碼輸出部分的注釋一般采用藍色字體表示

  List of Archived Logs in backup set 11

  Thrd Seq     Low SCN    Low Time            Next SCN   Next Time

  ---- ------- ---------- ------------------- ---------- ---------

  1    32      1621589    2015-05-29 11:09:52 1625242    2015-05-29 11:15:48

  1    33      1625242    2015-05-29 11:15:48 1625293    2015-05-29 11:15:58

  2    42      1613951    2015-05-29 10:41:18 1625245    2015-05-29 11:15:49

  2    43      1625245    2015-05-29 11:15:49 1625253    2015-05-29 11:15:53

[ZHLHRDB1:root]:/>lsvg -o

T_XLHRD_APP1_vg

rootvg

[ZHLHRDB1:root]:/>

00:27:22 SQL> alter tablespace idxtbs read write;

====2097152*512/1024/1024/1024=1G

本文如有錯誤或不完善的地方請大家多多指正,ITPUB留言或QQ皆可,您的批評指正是我寫作的最大動力。

 

2.2  本文簡介

由於寫書遇到了SCN的概念,所以就找了點資料,整理了一下有關SCN的一些知識。順便復習了一下SCN和數據庫恢復的關系。

 Oracle SCN

3.1  簡介

SCN(System Change Number,系統改變號)是一個由系統內部維護的序列號。當系統需要更新的時候自動增加,它是系統中維持數據的一致性和順序恢復的重要標志,是數據庫非常重要的一種數據結構。SCN的最大值是0xffff.ffffffff。在數據庫中SCN作為一種時鍾機制來標記數據庫動作,比如當事務的發生,數據庫會用一個SCN來標記它。同時這個SCN在數據庫全局也是唯一的,它隨時間的增長而增長除非重建數據庫。

在數據庫中,SCN可以說是無處不在,數據文件頭,控制文件,數據塊頭,日志文件等等都標記着SCN。也正是這樣,數據庫的一致性維護和SCN密切相關。不管是數據的備份,恢復都是離不開SCN的。

3.2  官方文檔

A system change number (SCN) is a logical, internal time stamp used by Oracle Database. SCNs order events that occur within the database, which is necessary to satisfy the ACID properties of a transaction. Oracle Database uses SCNs to mark the SCN before which all changes are known to be on disk so that recovery avoids applying unnecessary redo. The database also uses SCNs to mark the point at which no redo exists for a set of data so that recovery can stop.

SCNs occur in a monotonically increasing sequence. Oracle Database can use an SCN like a clock because an observed SCN indicates a logical point in time and repeated observations return equal or greater values. If one event has a lower SCN than another event, then it occurred at an earlier time with respect to the database. Several events may share the same SCN, which means that they occurred at the same time with respect to the database.

Every transaction has an SCN. For example, if a transaction updates a row, then the database records the SCN at which this update occurred. Other modifications in this transaction have the same SCN. When a transaction commits, the database records an SCN for this commit.

Oracle Database increments SCNs in the system global area (SGA). When a transaction modifies data, the database writes a new SCN to the undo data segment assigned to the transaction. The log writer process then writes the commit record of the transaction immediately to the online redo log. The commit record has the unique SCN of the transaction. Oracle Database also uses SCNs as part of its instance recovery and media recovery mechanisms.

怎么理解這個“SCN(系統變更號)是供Oracle數據庫使用的一個邏輯的、內部的時間戳呢?要理解這個先需要理解Oracle中的事務(Transaction)和數據一致性(Data Consistency)的概念。

先說說數據一致性的概念。數據一致性指的是數據的可用性。比如說管理一個財務的系統,需要從A賬戶將100元轉入到B賬戶,正常的操作是從A賬戶減去100元,然后給B賬戶加上100元,如果這兩步操作都正常完成了,那我們可以說完成轉賬操作之后的數據是一致可用的;但是如果在操作的過程中出了問題,A賬戶的100元給減掉了,但是B賬戶卻沒有加上100元,這樣的情況下產生的結果數據就有問題了,因為部分操作的失敗導致了數據的不一致而不可用,在實際中肯定是要避免這種讓數據不一致的情況發生的。在Oracle數據庫中,保證數據一致性的方法就是事務。

事務是一個邏輯的、原子性的作業單元,通常由一個或者是多個SQL組成,一個事務里面的所有SQL操作要么全部失敗回滾(Rollback),要么就是全部成功提交(Commit)。就像上面轉賬的例子,為保證數據的一致性,就需要將轉賬的兩步操作放在一個事務里面,這樣不管哪個操作失敗了,都需要將所有已進行的操作回滾,以保證數據的可用性。進行事務管理是數據庫區別於別的文件系統的一個最主要的特征,在數據庫中事務最主要的作用就是保證了數據的一致性,每次事務的提交都是將數據庫從一種一致性的狀態帶入到另外一種一致性的狀態中,SCN就是用來對數據庫的每個一致狀態進行標記的,每當數據庫進入到一個新的一致的狀態,SCN就會加1,也就是每個提交操作之后,SCN都會增加。也許你會想為什么不直接記錄事務提交時候的時間戳呢?這里面主要是涉及了兩個問題,一個是時間戳記錄的精度有限,再一個就是在分布式系統中記錄時間戳會存在系統時鍾同步的問題,詳細的討論可以查看Ordering Events in Oracle

SCN在數據庫中是一個單一的不斷的隨着數據庫一致性狀態的改變而自增的序列。正如一個時間戳代表着時間里面的某一個固定的時刻點一樣,每一個SCN值也代表着數據庫在運行當中的一個一致性的點,大的SCN值所對應的事務總是比小SCN值的事務發生的更晚。因此把SCN說成是Oracle數據庫的邏輯時間戳是很恰當的。

3.3  SCN的分類

嚴格來說SCN是沒有分類的,之所以會有不同類型的SCN並不是說這些SCN的概念不一樣,而是說不同分類的SCN代表的意義不一樣,不管什么時候SCN所指代的都是數據庫的某個一致性的狀態。就像我們給一天中的某個時間點定義上班時間、另外的某個時間點定義成下班時間一樣,數據庫Checkpoint發生點的SCN被稱為Checkpoint SCN,僅此而已。

SCN可以分為4類,系統檢查點SCNSystem Checkpoint SCN)、文件檢查點SCNDatafile Checkpoint SCN)、開始SCNStart SCN)和結束SCNStop SCN),參考如下表格:

 

3.4  查詢4SCN常用的SQL語句

col status for a10

select GROUP# ,SEQUENCE#,STATUS,FIRST_CHANGE#,FIRST_TIME from v$log;

 

SELECT A.FILE#,

       A.NAME,

       (SELECT CHECKPOINT_CHANGE# FROM V$DATABASE) SYSTEM_CKPT_SCN,

       A.CHECKPOINT_CHANGE# DF_CKPT_SCN,

       A.LAST_CHANGE# END_SCN,

       B.CHECKPOINT_CHANGE# START_SCN,

       B.RECOVER,

       A.STATUS

  FROM VDATAFILEA,VDATAFILEA,VDATAFILE_HEADER B

WHERE A.FILE# = B.FILE#;

SELECT FILE#,ONLINE_STATUS,CHANGE#,ERROR FROM V$RECOVER_FILE;

 

3.4.1  文件檢查點SCN (Datafile Checkpoint SCN)

SYS@lhrdb>  select file#,checkpoint_change# from v$datafile;

 

     FILE# CHECKPOINT_CHANGE#

---------- ------------------

         1            9026292

         2            9026292

         3            9026292

         4            9026292

         5            9026292

         6            9026292

         7            9026292

 

7 rows selected.

 

SYS@lhrdb>  alter tablespace users read only;

 

Tablespace altered.

 

SYS@lhrdb> select file#,checkpoint_change# from v$datafile;

 

     FILE# CHECKPOINT_CHANGE#

---------- ------------------

         1            9026292

         2            9026292

         3            9026292

         4            9028165

         5            9026292

         6            9026292

         7            9026292

 

7 rows selected.

 

SYS@lhrdb> select checkpoint_change# from v$database;

 

CHECKPOINT_CHANGE#

------------------

           9026292

 

可以看到4號文件也就是users表空間所屬的文件scn值和其他文件不一致,且比系統檢查點的scn要大。

3.4.2  Stop SCN

每個數據文件的終止scn都存儲在控制文件中,在數據庫正常運行的情況下,對可讀寫的,online的數據文件,該SCN號為NULL

SQLSELECT NAME,status,enabled,Checkpoint_change# ,checkpoint_time,last_change# FROM v$datafile;

在數據庫打開過程中,Oracle會比較各文件的stop scncheckpoint scn,如果值不一致,表明數據庫先前沒有正常關閉,需要做恢復。

SYS@lhrdb> SELECT TABLESPACE_NAME,STATUS FROM DBA_TABLESPACES;

 

TABLESPACE_NAME                STATUS

------------------------------ ---------

SYSTEM                         ONLINE

SYSAUX                         ONLINE

UNDOTBS1                       ONLINE

TEMP                           ONLINE

USERS                          READ ONLY

EXAMPLE                        ONLINE

TS_MIG_CHAIN_LHR               ONLINE

TS_TESTBLOCKLHR                ONLINE

 

8 rows selected.

 

SYS@lhrdb>  SELECT FILE#,LAST_CHANGE# FROM  V$DATAFILE;

 

     FILE# LAST_CHANGE#

---------- ------------

         1

         2

         3

         4      9028165

         5

         6

         7

 

7 rows selected.

 

可以看到除了USERS表空間的結束SCN不為空,其他數據文件的結束SCN為空。

將數據庫至於MOUNT狀態,由於該狀態下所有的數據文件都不可寫,故MOUNT狀態下所有的數據文件都具有結束SCN

SYS@lhrdb> startup mount

ORACLE instance started.

 

Total System Global Area 1720328192 bytes

Fixed Size                  2247072 bytes

Variable Size             452986464 bytes

Database Buffers         1258291200 bytes

Redo Buffers                6803456 bytes

Database mounted.

SYS@lhrdb> SELECT FILE#,LAST_CHANGE# FROM  V$DATAFILE;

 

     FILE# LAST_CHANGE#

---------- ------------

         1      9048847

         2      9048847

         3      9048847

         4      9028165

         5      9048847

         6      9048847

         7      9048847

 

7 rows selected.

 

SYS@lhrdb> alter tablespace users read write;

 

Tablespace altered.

 

SYS@lhrdb> SELECT FILE#,LAST_CHANGE# FROM  V$DATAFILE;

 

     FILE# LAST_CHANGE#

---------- ------------

         1

         2

         3

         4

         5

         6

         7

 

7 rows selected.

 

SYS@lhrdb> startup force mount

ORACLE instance started.

 

Total System Global Area 1720328192 bytes

Fixed Size                  2247072 bytes

Variable Size             452986464 bytes

Database Buffers         1258291200 bytes

Redo Buffers                6803456 bytes

Database mounted.

SYS@lhrdb> SELECT FILE#,LAST_CHANGE# FROM  V$DATAFILE;

 

     FILE# LAST_CHANGE#

---------- ------------

         1

         2

         3

         4

         5

         6

         7

 

7 rows selected.

 

3.4.3  HIGH AND LOW SCN

ORACLEREDO LOG會順序紀錄數據庫的各個變化。一組REDO LOG文件寫滿后,會自動切換到下一組REDO LOG文件。則上一組REDO LOGHIGH SCN就是下一組REDO LOGLOW SCN。在CURRENT LOGHIGH SCN為無窮大。

在視圖V$LOG_HISTORY中,SEQUENCE#代表REDO LOG的序列號,FIRST_CHANGE#表示當前REDO LOGLOW SCN,列NEXT_CHANGE#表示當前REDO LOGHIGH SCN

可通過查詢V$LOG_HISTORY查看 LOW SCN和 HIGH SCN

SYS@lhrdb> set pagesize 9999

SYS@lhrdb> SELECT RECID,SEQUENCE#,FIRST_CHANGE#,NEXT_CHANGE# FROM V$LOG_HISTORY WHERE ROWNUM<=6;

     RECID  SEQUENCE# FIRST_CHANGE# NEXT_CHANGE#

---------- ---------- ------------- ------------

       272        272       7486197      7510243

       273        273       7510243      7527538

       274        274       7527538      7539409

       275        275       7539409      7556740

       276        276       7556740      7572195

       277        277       7572195      7581847

6 rows selected.

 

 

查看CURRNET REDO LOG中的HIGH SCN

SYS@lhrdb> COL MEMBER FORMAT A50

SYS@lhrdb> SELECT VF.MEMBER,V.STATUS,V.FIRST_CHANGE# FROM VLOGFILEVF,VLOGFILEVF,VLOG V

  2     WHERE VF.GROUP#=V.GROUP#

  3     AND V.STATUS='CURRENT';

 

MEMBER                                             STATUS           FIRST_CHANGE#

-------------------------------------------------- ---------------- -------------

+DATA/lhrdb/onlinelog/group_4.798.923841413        CURRENT                9069089

+DATA/lhrdb/onlinelog/group_4.797.923841415        CURRENT                9069089

 

SYS@lhrdb> ALTER SYSTEM DUMP LOGFILE '+DATA/lhrdb/onlinelog/group_4.797.923841415';

 

System altered.

 

SYS@lhrdb> oradebug setmypid

Statement processed.

SYS@lhrdb> oradebug tracefile_name

/oracle/app/oracle/diag/rdbms/lhrdb/lhrdb/trace/lhrdb_ora_8388948.trc

查看轉儲文件的內容:

DUMP OF REDO FROM FILE '+DATA/lhrdb/onlinelog/group_4.797.923841415'

Opcodes *.*

RBAs: 0x000000.00000000.0000 thru 0xffffffff.ffffffff.ffff

SCNs: scn: 0x0000.00000000 thru scn: 0xffff.ffffffff

Times: creation thru eternity

FILE HEADER:

        Compatibility Vsn = 186647552=0xb200400

        Db ID=959319562=0x392e0e0a, Db Name='LHRDB'

        Activation ID=959339270=0x392e5b06

        Control Seq=96545=0x17921, File size=204800=0x32000

        File Number=4, Blksiz=512, File Type=2 LOG

descrip:"Thread 0001, Seq# 0000001090, SCN 0x0000008a6221-0xffffffffffff"

thread: 1 nab: 0xffffffff seq: 0x00000442 hws: 0x2 eot: 1 dis: 0

resetlogs count: 0x36a23c8c scn: 0x0000.000e20dc (925916)

prev resetlogs count: 0x3155bebd scn: 0x0000.00000001 (1)

Low  scn: 0x0000.008a6221 (9069089) 10/11/2016 16:46:41

Next scn: 0xffff.ffffffff 01/01/1988 00:00:00

Enabled scn: 0x0000.000e20dc (925916) 07/07/2016 19:39:56

Thread closed scn: 0x0000.008a6221 (9069089) 10/11/2016 16:46:41

Disk cksum: 0xc14c Calc cksum: 0xc14c

Terminal recovery stop scn: 0x0000.00000000

Terminal recovery  01/01/1988 00:00:00

Most recent redo scn: 0x0000.00000000

Largest LWN: 0 blocks

End-of-redo stream : No

Unprotected mode

Miscellaneous flags: 0x800000

Thread internal enable indicator: thr: 0, seq: 0 scn: 0x0000.00000000

Zero blocks: 0

Format ID is 1

redo log key is 47e6cd1abd3a43fd864d2b94ae9a8128

redo log key flag is 5

Enabled redo threads: 1

 

當前最新的數據庫scn值可通過如下命令查看:

SYS@lhrdb> select dbms_flashback.get_system_change_number from dual;

GET_SYSTEM_CHANGE_NUMBER

------------------------

                 9069555

如果需要進行實例恢復,則需要恢復的記錄為90690899069555redo log中的記錄。

3.5  SCN號於數據庫的啟動、關閉

Scn號與Oracle數據庫恢復過程有着密切的關系,只有很好地理解了這層關系,才能深刻地理解恢復的原理CKPT進程在checkpoint發生時,將當時的SCN號寫入數據文件頭和控制文件,同時通知DBWR進程將數據塊寫到數據文件。

CKPT進程也會在控制文件中記錄RBA(redo block address),以標志Recovery需要從日志中哪個地方開始。

 

1.在數據庫的啟動過程中,當System Checkpoint SCN=Datafile Checkpoint SCN=Start SCN的時候,Oracle數據庫是可以正常啟動的,而不需要做任何的MEDIA RECOVERY。而如果三者當中有一個不同的話,則需要做MEDIA RECOVERYOracle在啟動過程中首先檢查是否需要MEDIA RECOVERY,然后再檢查是否需要INSTANCE RECOVERY

2.那什么時候需要做INSTANCE RECOVERY呢?其實在正常OPEN數據庫的時候,Oracle會將記錄在控制文件中的每一個數據文件頭的End SCN都設置為#FFFFFF(NULL),那么如果數據庫進行了正常關閉比如(shutdown or shutdown immediate)這個時候,系統會執行一個檢查點,這個檢查點會將控制文件中記錄的各個數據文件頭的End SCN更新為當前online數據文件的各個數據文件頭的Start SCN,也就是End SCN=Start SCN,如果再次啟動數據庫的時候發現二者相等,則直接打開數據庫,並再次將End SCN設置為#FFFFFF(NULL),那么如果數據庫是異常關閉,那么CHECKPOINT就不會執行,因此再次打開數據庫的時候End SCN<>Start SCN這個時候就需要做實例恢復。如果數據庫異常關閉的話,則END SCN號將為NULL.則需要做instance recovery

3.5.1  為什么需要System checkpoint SCN號與Datafile Checkpoint SCN

為什么ORACLE會在控制文件中記錄System checkpoint SCN號的同時,還需要為每個數據文件記錄Datafile Checkpoint SCN號?

原因有二:

1.對只讀表空間,其數據文件的Datafile Checkpoint SCNStart SCNEND SCN號均相同。這三個SCN在表空間處於只讀期間都將被凍結。

2.如果控制文件不是當前的控制文件,則System checkpoint會小於Start SCNEND SCN號。記錄這些SCN號,可以區分控制文件是否是當前的控制文件。

SYS@lhrdb> alter tablespace users read only;

 

Tablespace altered.

 

SYS@lhrdb> SELECT A.FILE#,

  2         A.NAME,

  3         (SELECT CHECKPOINT_CHANGE# FROM V$DATABASE) SYSTEM_CKPT_SCN,

  4         A.CHECKPOINT_CHANGE# DF_CKPT_SCN,

  5         A.LAST_CHANGE# END_SCN,

  6         B.CHECKPOINT_CHANGE# START_SCN,

  7         B.RECOVER,

  8         A.STATUS

  9    FROM V$DATAFILEA A,V$DATAFILE_HEADER B

10   WHERE A.FILE# = B.FILE#;

 

     FILE# NAME                                                         SYSTEM_CKPT_SCN DF_CKPT_SCN    END_SCN  START_SCN REC STATUS

---------- ------------------------------------------------------------ --------------- ----------- ---------- ---------- --- ----------

         1 +DATA/lhrdb/datafile/system.347.916601927                            9225394     9225394               9225394 NO  SYSTEM

         2 +DATA/lhrdb/datafile/sysaux.340.916601927                            9225394     9225394               9225394 NO  ONLINE

         3 +DATA/lhrdb/datafile/undotbs1.353.916601927                          9225394     9225394               9225394 NO  ONLINE

         4 +DATA/lhrdb/datafile/users.445.916601927                             9225394     9229175    9229175    9229175 NO  ONLINE

         5 +DATA/lhrdb/datafile/example.416.916602001                           9225394     9225394               9225394 NO  ONLINE

         6 +DATA/lhrdb/datafile/ts_mig_chain_lhr.471.919677645                  9225394     9225394               9225394 NO  ONLINE

         7 /oracle/app/oracle/oradata/lhrdb/testblocklhr01.dbf                  9225394     9225394               9225394 NO  ONLINE

 

7 rows selected.

 

 

3.5.2  recover database using backup controlfile

當有一個Start SCN號超過了System Checkpoint SCN號時,則說明控制文件不是當前的控制文件,因此在做recover時需要采用using backup controlfile。這是為什么需要記錄SystemCheckpoint SCN的原因之一。

這里需要一提的是,當重建控制文件的時候,System Checkpoint SCN0Datafile Checkpoint SCN的數據來自於Start SCN。根據上述的描述,此時需要采用using backup controlfilerecovery.

3.6  查看系統當前SCN

Oracle數據庫提供了兩種直接查看系統當前SCN的方法,一個是V$DATABASE中的CURRENT_SCN列,另外一個就是通過DBMS_FLASHBACK.GET_SYSTEM_CHANGE_NUMBER得到。

SYS@ORACNSL1> COL SCN1 FOR 9999999999999

SYS@ORACNSL1> COL SCN2 FOR 9999999999999

SYS@ORACNSL1> COL SCN3 FOR 9999999999999

SYS@ORACNSL1> SELECT CURRENT_SCN SCN1,DBMS_FLASHBACK.GET_SYSTEM_CHANGE_NUMBER SCN2,TIMESTAMP_TO_SCN(SYSDATE) SCN3 FROM V$DATABASE;

          SCN1           SCN2       SCN3

-------------- -------------- ----------

    1495460388     1495460388 1495460387

 

 

一般情況下,SCN1SCN2的結果一致,但在系統比較繁忙的時候可能SCN2SCN1稍微大一點,比如大1

oracle 9i中要麻煩些,V$DATABASE視圖中沒有CURRENT_SCN這列,只有通過查詢X$KTUXE視圖來得到。

SYS@lhrdb> SELECT MAX(KTUXESCNW*POWER(2,32)+KTUXESCNB) SCN FROM X$KTUXE;

       SCN

----------

   8764198

 

3.7  SCN與時間的相互轉換(SCN_TO_TIMESTAMPTIMESTAMP_TO_SCN

Oracle 10g提供了兩個新函數對於SCN和時間戳進行相互轉換,這兩個函數是SCN_TO_TIMESTAMPTIMESTAMP_TO_SCN,通過對SCN和時間戳進行轉換,Oracle極大地方便了很多備份和恢復過程。

一個SCN值總是發生在某一個特定的時刻的,只不過由於粒度的不一樣,通常會存在多個SCN對應同一個時間戳。Oracle中提供了兩個函數以供我們進行SCN和時間的互換:

l SCN_TO_TIMESTAMP(scn_number) SCN轉換成時間戳。

l TIMESTAMP_TO_SCN(timestamp) 將時間戳轉換成SCN

 

通過這兩個函數,最終OracleSCN和時間的關系建立起來,在Oracle 10g之前,是沒有辦法通過函數轉換得到SCN和時間的對應關系的,一般可以通過logmnr分析日志獲得。但是這種轉換要依賴於數據庫內部的數據記錄(SMON_SCN_TIME),對於久遠的SCN則不能轉換,請看以下舉例:

SYS@lhrdb>  SELECT MIN(FIRST_CHANGE#) SCN,DBMS_FLASHBACK.GET_SYSTEM_CHANGE_NUMBER FROM V$ARCHIVED_LOG;

 

       SCN GET_SYSTEM_CHANGE_NUMBER

---------- ------------------------

   7527538                  8763206

 

SYS@lhrdb> SELECT SCN_TO_TIMESTAMP(7527538) SCN FROM DUAL;

select scn_to_timestamp(7527538) scn 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@lhrdb> select min(scn) from smon_scn_time;

 

  MIN(SCN)

----------

   8622517

 

SYS@lhrdb>  select scn_to_timestamp(8622517) timestamp from dual;

 

TIMESTAMP

---------------------------------------------------------------------------

08-OCT-16 04.30.26.000000000 AM

 

SYS@lhrdb>  select scn_to_timestamp(8622516) timestamp from dual;

select scn_to_timestamp(8622516) timestamp 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

 

 

 

從上面的例子可以看出Oracle能夠轉換的最小SCN也就是SMON_SCN_TIME.scn的最小值。

 

SYS@lhrdb> SELECT SCN_TO_TIMESTAMP(8763206) SCN FROM DUAL;

 

SCN

---------------------------------------------------------------------------

10-OCT-16 05.22.40.000000000 PM

 

SYS@lhrdb> SELECT TIMESTAMP_TO_SCN(TO_TIMESTAMP('10-OCT-16 05.22.40.000000000 PM','DD-Mon-RR HH:MI:SS.FF AM')) SCN FROM DUAL;

 

       SCN

----------

   8763206

 

SYS@lhrdb> SELECT TIMESTAMP_TO_SCN(TO_TIMESTAMP('2016-10-10 17:22:40','YYYY-MM-DD HH24:MI:SS')) SCN FROM DUAL;

 

       SCN

----------

   8763206

 

SYS@lhrdb> SELECT TO_CHAR(SCN_TO_TIMESTAMP(8763206), 'YYYY-MM-DD HH24:MI:SS') CHR_DATE,TIMESTAMP_TO_SCN(SCN_TO_TIMESTAMP(8763206)) DT FROM DUAL;

 

CHR_DATE                    DT

------------------- ----------

2016-10-10 17:22:40    8763206

 

對於時間到SCN的轉換,Oracle只能定位到3秒以內,3秒內的時間都被轉換成同一個SCN

SYS@lhrdb> SELECT TIMESTAMP_TO_SCN(TO_TIMESTAMP('2016-10-10 17:22:40','YYYY-MM-DD HH24:MI:SS')) SCN FROM DUAL;

 

       SCN

----------

   8763206

 

SYS@lhrdb> SELECT TIMESTAMP_TO_SCN(TO_TIMESTAMP('2016-10-10 17:22:41','YYYY-MM-DD HH24:MI:SS')) SCN FROM DUAL;

 

       SCN

----------

   8763206

 

SYS@lhrdb> SELECT TIMESTAMP_TO_SCN(TO_TIMESTAMP('2016-10-10 17:22:42','YYYY-MM-DD HH24:MI:SS')) SCN FROM DUAL;

 

       SCN

----------

   8763206

 

SYS@lhrdb> SELECT TIMESTAMP_TO_SCN(TO_TIMESTAMP('2016-10-10 17:22:43','YYYY-MM-DD HH24:MI:SS')) SCN FROM DUAL;

 

       SCN

----------

   8763213

 

SYS@lhrdb> SELECT TIMESTAMP_TO_SCN(TO_TIMESTAMP('2016-10-10 17:22:39','YYYY-MM-DD HH24:MI:SS')) SCN FROM DUAL;

 

       SCN

----------

   8763205

 

3.7.1  SMON_SCN_TIME

SELECT * FROM DBA_TABLES D WHERE D.TABLE_NAME = 'SMON_SCN_TIME';

wpsDE76.tmp_thumb  

Oracle 在內部都是使用scn,即使你指定的是as of timestamporacle 也會將其轉換成scn,系統時間標記與scn 之間存在一張表,即SYS下的SMON_SCN_TIME

SYS@lhrdb> set linesize 80

SYS@lhrdb> 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

 

每隔5分鍾,系統產生一次系統時間標記與scn的匹配並存入sys.smon_scn_time 表,該表中記錄了最近1440個系統時間標記與scn的匹配記錄,由於該表只維護了最近的1440條記錄,因此如果使用as of timestamp的方式則只能flashback最近5天內的數據(假設系統是在持續不斷運行並無中斷或關機重啟之類操作的話)。

查看SCN 和 timestamp 之間的對應關系:

SELECT SCN, TO_CHAR(TIME_DP, 'YYYY-MM-DD HH24:MI:SS') TIME_DP

  FROM SYS.SMON_SCN_TIME T

 ORDER BY T.SCN DESC;

wpsDE86.tmp_thumb 

有關表SMON_SCN_TIME的更多內容可以參考我的BLOGhttp://blog.itpub.net/26736162/viewspace-2126291/David大神寫的,非常全面,我就不畫蛇添足了。

 

3.8  實例恢復(INSTANCE RECOVERY)和介質恢復(MEDIA RECOVERY

REDO LOGOracle為確保已經提交的事務不會丟失而建立的一個機制。實際上REDO LOG的存在是為兩種場景准備的,一種我們稱之為實例恢復(INSTANCE RECOVERY),一種我們稱之為介質恢復(MEDIA RECOVERY)。

REDO LOG的數據是按照THREAD來組織的,對於單實例系統來說,只有一個THREAD,對於RAC系統來說,可能存在多個THREAD,每個數據庫實例擁有一組獨立的REDO LOG文件,擁有獨立的LOG BUFFER,某個實例的變化會被獨立的記錄到一個THREADREDO LOG文件中。

 

3.8.1  實例恢復

對於單實例的系統,實例恢復一般是在數據庫實例異常故障后數據庫重啟時進行,當數據庫執行了SHUTDOWN ABORT或者由於操作系統、主機等原因宕機重啟后,在執行ALTER DATABASE OPEN的時候,就會自動做實例恢復。而在RAC環境中,如果某個實例宕機了,那么剩下的實例將會替宕掉的實例做實例恢復。除非是所有的實例都宕機了,這樣的話,第一個執行ALTER DATABASE OPEN的實例將會做實例恢復。這也是RAC環境中,REDO LOG是實例私有的組件,但是REDO LOG文件必須存放在共享存儲上的原因。

一、 RAC中的實例恢復

一個單實例數據庫或者RAC數據庫所有實例失敗之后,第一個打開數據庫的實例會自動執行實例恢復。這種形式的實例恢復稱為Crash恢復。一個RAC數據庫的一部分但不是所有實例失敗后,在RAC中幸存的實例自動執行失敗實例的恢復稱為實例恢復。一般而言,在崩潰或關機退出之后第一個打開數據庫的實例將自動執行崩潰恢復。

根據Crash恢復和實例恢復的不同,由幸存實例或者第一個重啟的實例讀取失敗實例生成的聯機Redo日志和UNDO表空間數據,使用這些信息確保只有已提交的事務被寫到數據庫中,回滾在失敗時候活動的事務,並釋放事務使用的資源。

[ZFZHLHRDB1:oracle]:/oracle>crsctl stat res -t

--------------------------------------------------------------------------------

NAME           TARGET  STATE        SERVER                   STATE_DETAILS      

--------------------------------------------------------------------------------

Local Resources

--------------------------------------------------------------------------------

ora.DATA.dg

               ONLINE  ONLINE       zfzhlhrdb1                                  

               ONLINE  ONLINE       zfzhlhrdb2                                  

ora.LISTENER.lsnr

               ONLINE  ONLINE       zfzhlhrdb1                                  

               ONLINE  ONLINE       zfzhlhrdb2                                  

ora.LISTENER_LHRDG.lsnr

               ONLINE  ONLINE       zfzhlhrdb1                                  

               ONLINE  ONLINE       zfzhlhrdb2                                  

ora.asm

               ONLINE  ONLINE       zfzhlhrdb1               Started            

               ONLINE  ONLINE       zfzhlhrdb2               Started            

ora.gsd

               OFFLINE OFFLINE      zfzhlhrdb1                                  

               OFFLINE OFFLINE      zfzhlhrdb2                                  

ora.net1.network

               ONLINE  ONLINE       zfzhlhrdb1                                  

               ONLINE  ONLINE       zfzhlhrdb2                                  

ora.ons

               ONLINE  ONLINE       zfzhlhrdb1                                  

               ONLINE  ONLINE       zfzhlhrdb2                                  

ora.registry.acfs

               ONLINE  ONLINE       zfzhlhrdb1                                  

               ONLINE  ONLINE       zfzhlhrdb2                                  

--------------------------------------------------------------------------------

Cluster Resources

--------------------------------------------------------------------------------

ora.LISTENER_SCAN1.lsnr

      1        ONLINE  ONLINE       zfzhlhrdb1                                  

ora.cvu

      1        ONLINE  ONLINE       zfzhlhrdb1                                  

ora.lhrdb.db

      1        ONLINE  ONLINE       zfzhlhrdb1               Open               

ora.oc4j

      1        ONLINE  ONLINE       zfzhlhrdb1                                  

ora.raclhr.db

      1        ONLINE  ONLINE       zfzhlhrdb2               Open               

      2        ONLINE  ONLINE       zfzhlhrdb1               Open               

ora.scan1.vip

      1        ONLINE  ONLINE       zfzhlhrdb1                                  

ora.zfzhlhrdb1.vip

      1        ONLINE  ONLINE       zfzhlhrdb1                                  

ora.zfzhlhrdb2.vip

      1        ONLINE  ONLINE       zfzhlhrdb2                                  

[ZFZHLHRDB1:oracle]:/oracle>srvctl stop instance -d raclhr -i raclhr1 -o abort

[ZFZHLHRDB1:oracle]:/oracle>srvctl status db -d raclhr

Instance raclhr1 is not running on node zfzhlhrdb1

Instance raclhr2 is running on node zfzhlhrdb2

abort掉實例1后:

實例一的告警日志:

Thu Oct 13 15:51:30 2016

Shutting down instance (abort)

License high water mark = 60

USER (ospid: 4194780): terminating the instance

Instance terminated by USER, pid = 4194780

Thu Oct 13 15:51:32 2016

Instance shutdown complete

實例二的告警日志:

Thu Oct 13 15:51:31 2016

Reconfiguration started (old inc 4, new inc 6)

List of instances:

2 (myinst: 2)

Global Resource Directory frozen

* dead instance detected - domain 0 invalid = TRUE

Communication channels reestablished

Master broadcasted resource hash value bitmaps

Non-local Process blocks cleaned out

Thu Oct 13 15:51:31 2016

LMS 0: 0 GCS shadows cancelled, 0 closed, 0 Xw survived

Thu Oct 13 15:51:31 2016

LMS 1: 0 GCS shadows cancelled, 0 closed, 0 Xw survived

Set master node info

Submitted all remote-enqueue requests

Dwn-cvts replayed, VALBLKs dubious

All grantable enqueues granted

Post SMON to start 1st pass IR

Thu Oct 13 15:51:31 2016

Instance recovery: looking for dead threads

Submitted all GCS remote-cache requests

Post SMON to start 1st pass IR

Fix write in gcs resources

Reconfiguration complete

Beginning instance recovery of 1 threads

parallel recovery started with 7 processes

Started redo scan

Completed redo scan

read 18 KB redo, 14 data blocks need recovery

Started redo application at

Thread 1: logseq 235, block 68352

Recovery of Online Redo Log: Thread 1 Group 1 Seq 235 Reading mem 0

  Mem# 0: +DATA/raclhr/onlinelog/group_1.362.916601361

  Mem# 1: +DATA/raclhr/onlinelog/group_1.361.916601361

Completed redo application of 0.01MB

Completed instance recovery at

Thread 1: logseq 235, block 68389, scn 9725527

14 data blocks read, 14 data blocks written, 18 redo k-bytes read

Thu Oct 13 15:51:33 2016

minact-scn: Inst 2 is now the master inc#:6 mmon proc-id:25100420 status:0x7

minact-scn status: grec-scn:0x0000.00000000 gmin-scn:0x0000.009417d9 gcalc-scn:0x0000.009417e3

minact-scn: master found reconf/inst-rec before recscn scan old-inc#:6 new-inc#:6

Thread 1 advanced to log sequence 236 (thread recovery)

Redo thread 1 internally disabled at seq 236 (SMON)

Thu Oct 13 15:51:34 2016

Thread 2 advanced to log sequence 265 (LGWR switch)

  Current log# 4 seq# 265 mem# 0: +DATA/raclhr/onlinelog/group_4.349.916601715

  Current log# 4 seq# 265 mem# 1: +DATA/raclhr/onlinelog/group_4.348.916601715

Thu Oct 13 15:51:35 2016

Archived Log entry 493 added for thread 1 sequence 235 ID 0x441b1480 dest 1:

Thu Oct 13 15:51:35 2016

ARC0: Archiving disabled thread 1 sequence 236

Archived Log entry 494 added for thread 1 sequence 236 ID 0x441b1480 dest 1:

Thu Oct 13 15:51:35 2016

Archived Log entry 495 added for thread 2 sequence 264 ID 0x441b1480 dest 1:

minact-scn: master continuing after IR

 

3.8.2  介質恢復

介質恢復是基於物理備份恢復數據,Oracle數據庫出現介質故障時恢復的重要保障。介質恢復包括塊恢復、數據文件恢復、表空間恢復和整個數據庫的恢復。介質恢復主要是針對錯誤類型中的介質失敗,如果是少量的塊失敗,那么可以使用介質恢復中的塊恢復來快速修復;但如果是其它情況的丟失,那么需要根據具體情況,可使用數據文件恢復、表空間恢復甚至全庫恢復,可以參考如下的表格:

 

 

錯誤分類

恢復解決方案

介質失敗

如果是少量的塊損壞,使用塊介質恢復;如果是大量的塊、數據文件、表空間的損壞,可能需要對損壞的數據文件或者表空間執行完全恢復;如果是歸檔REDO日志文件或者聯機REDO日志文件的丟失,那么只需要不完全恢復方式。

邏輯損壞

如果是程序員錯誤導致出現的問題,可通過補丁應用修復問題。對於無法修復的問題,也可采用介質恢復手段來恢復數據。

用戶錯誤

根據不同用戶錯誤,選擇不同的FLASHBACK技術恢復,使用FLASHBACK技術恢復用戶錯誤是首選方案。如果FLASHBACK不能很好的恢復數據再考慮使用介質恢復或者表空間時間點恢復。

Oracle數據庫的介質恢復實際上包含了兩個過程:數據庫還原RESTORE與數據庫恢復RECOVER

數據庫還原RESTORE是指利用備份的數據庫文件來替換已經損壞的數據庫文件或者將其恢復到一個新的位置。RMAN在進行還原操作時,會利用恢復目錄有建立恢復目錄的話就使用目標數據庫的控制文件來獲取備份信息,並從中選擇最合適的備份進行修復操作。選擇備份時有兩個原則1、選擇距離恢復目錄時刻最近;2、優先選擇鏡像復制,其次才是備份集

數據庫恢復RECOVER是指數據文件的介質恢復,即為修復后的數據文件應用聯機或歸檔日志,從而將修復的數據庫文件更新到當前時刻或指定時刻下的狀態。在執行恢復數據庫時,需要使用RECOVER命令。

還原是將某個時間點數據文件的拷貝再拷貝回去,還原后的數據庫處於不一致性的狀態,或不是最新的狀態,還需要執行恢復操作。恢復就是使用歸檔REDO日志文件和聯機REDO日志文件將不一致的數據庫應用到一致性狀態。

需要注意的是,還原只是建立在數據庫備份的基礎版本上,例如,如果數據庫備份包括0級備份和很多1級備份,還原只是應用0級備份,恢復過程會根據情況自動應用1級備份或REDO日志將數據庫恢復到一致性的狀態。

數據庫的恢復過程根據恢復數據的程度又分為完全恢復(Complete Recovery)和不完全恢復Incomplete Recovery

完全恢復是一種沒有數據丟失的恢復方式,能夠恢復到最新的聯機REDO日志中已提交的數據。在傳統恢復方式中,因介質失敗破壞了數據文件之后,可以在數據庫、表空間和數據文件上執行完全介質恢復。

不完全恢復是一種與完全恢復相反的恢復方式,是一種丟失數據的恢復方式,也稱為數據庫基於時間點恢復Point-in-Time Recovery,是將整個數據庫恢復到之前的某個時間點、日志序列號或者SCN號。通常情況下,若FLASHBACK DATABASE沒有啟用或者變得無效,可以執行不完全恢復撤銷一個用戶錯誤。不完全恢復不一定在原有的數據庫環境執行,可以在測試環境下執行不完全恢復,將找回的數據再重新導入生產庫中。不完全恢復根據備份情況恢復到與指定時間、日志序列號和SCN具有一致性的數據,之后的數據都將丟失。執行不完全恢復一方面是因為歸檔REDO日志、聯機REDO日志的丟失不得不執行不完全恢復,另一方面可能是因為在某個時刻錯誤地操作了數據,過了一段時間之后才發現問題,而其它的恢復手段都無法恢復數據,這時也不得不使用不完全恢復來找回數據。執行不完全恢復必須從備份中還原所有的數據文件,備份文件必須是要恢復的時間點之前創建的。當恢復完成,使用RESTLOGS選項打開數據庫,將重新初始化聯機Redo日志,創建一個新的日志序列號流,日志序列號從1開始,RESETLOGS之后的SCN還是在遞增。

如果是完全恢復,那么數據庫就是最新的一致性狀態;如果是不完全恢復,那么數據庫是非最新的一致性狀態。對於非歸檔模式的數據庫來說,不能執行不完全恢復。

不完全恢復的選項如下表所示

不完全恢復方式

RMAN選項

用戶管理備份選項

恢復到某個時間點

UNTIL TIME

UNTIL TIME

恢復到某個日志序列號

UNTIL SUQUENCE

UNTIL CANCEL

恢復到某個SCN

UNTIL SCN

UNTIL CHANGE


不完全恢復的幾種類型如下表所示(注意:下圖是小麥苗即將出版的書上的一個表格,現在提前分享給大家

wpsDE87.tmp_thumb 

綜上所述,恢復的分類大致可以如下圖所示的分類注意:下圖也是小麥苗即將出版的書上的一個表格,現在提前分享給大家


 

3.8.3  實例恢復和介質恢復的區別注意:下圖也是小麥苗即將出版的書上的一個表格,現在提前分享給大家

 

 



DBA入門之認識Oracle SCN(System Change Number)

1. SCN的定義

SCN(System Change Number),也就是通常所說的系統改變號,是數據庫中非常重要的一個數據結構。

SCN用以標識數據庫在某個確切時刻提交的版本。在事務提交時,它被賦予一個唯一的標識事務的SCN。SCN同時被作為Oracle數據庫的內部時鍾機制,可被看做邏輯時鍾,每個數據庫都有一個全局的SCN生成器。

作為數據庫內部的邏輯時鍾,數據庫事務依SCN而排序,Oracle也依據SCN來實現一致性讀(Read Consistency)等重要數據庫功能。另外對於分布式事務(Distributed Transactions),SCN也極為重要,這里不做更多介紹。

SCN在數據庫中是唯一的,並隨時間而增加,但是可能並不連貫。除非重建數據庫,SCN的值永遠不會被重置為0.

一直以來,對於SCN有很多爭議,很多人認為SCN是指System Commit Number,而通常SCN在提交時才變化,所以很多時候,這兩個名詞經常在文檔中反復出現。即使在Oracle的官方文檔中,SCN也常以System Change/Commit Number兩種形式出現。

到底是哪個詞其實不是很重要,重要的是需要知道SCN是Oracle內部的時鍾機制,Oracle通過SCN來維護數據庫的一致性,並通過SCN實施Oracle至關重要的恢復機制。

SCN在數據庫中是無處不在,常見的事務表、控制文件、數據文件頭、日志文件、數據塊頭等都記錄有SCN值。

冠以不同前綴,SCN也有了不同的名稱,如檢查點SCN(Checkpint SCN)、Resetlogs SCN等。

 

2.SCN的獲取方式

可以通過如下幾種方式獲得數據庫的當前或近似SCN。

(1) 從Oracle 9i開始。

可以使用dbms_flashback.get_system_change_number來獲得:

SQL> select dbms_flashback.get_system_change_number from dual;

GET_SYSTEM_CHANGE_NUMBER

------------------------

888266

(2) Oracle 9i前。

可以通過查詢x$ktuxe獲得系統最接近當前值的SCN:

X$ktuxe的含義是[k]ernel [T]ransaction [U]ndo Transa[x]tion [E]ntry(table)

SQL>select max(ktuxecnw*power(2,32)+ktuxescnb) from x$ktuxe;

MAX(KTUXESCNW*POWER(2,32)+KTUXESCNB)

------------------------

28848232

 

3.SCN的進一步說明

系統當前SCN並不是在任何的數據庫操作時都會改變,SCN通常在事務提交或回滾時改變。在控制文件、數據文件頭、數據庫、日志文件頭、日志文件change vector中都有SCN,但其作用各不相同。

(1) 數據文件頭中包含了該數據文件的Checkpoint SCN,表示該數據文件最近一次執行檢查點操作時的SCN

從控制文件的dump文件中,可以得到一下內容:

DATA FILE #1:

(name #7) /opt/ora10g/oradata/ORCL/system01.dbf

creation size=0 block size=8192 status=0xe head=7 tail=7 dup=1

tablespace 0, index=1 krfil=1 prev_file=0

unrecoverable scn: 0x0000.00000000 01/01/1988 00:00:00

Checkpoint cnt:106 scn: 0x0000.000d845f 11/14/2011 15:24:50

Stop scn: 0xffff.ffffffff 11/14/2011 14:31:00

Creation Checkpointed at scn: 0x0000.00000009 06/30/2005 19:10:11

……

對於每一個數據文件都包含一個這樣的條目,記錄該文件的檢查點SCN的值以及檢查點發生的時間,這里的Checkpint SCN、Stop SCN以及Checkpoint CNT都是非常重要的數據結構,我們將會在下面檢查點部分詳細介紹。

同樣可以通過命令轉儲數據文件頭,觀察其具體信息及檢查點記錄等,從跟蹤文件中摘取system表空間的記錄作為參考:

***************************************************************************

DATA FILE RECORDS

***************************************************************************

(size = 428, compat size = 428, section max = 100, section in-use = 4,

last-recid= 53, old-recno = 0, last-recno = 0)

(extent = 1, blkno = 11, numrecs = 100)

DATA FILE #1:

(name #7) /opt/ora10g/oradata/ORCL/system01.dbf

creation size=0 block size=8192 status=0xe head=7 tail=7 dup=1

tablespace 0, index=1 krfil=1 prev_file=0

unrecoverable scn: 0x0000.00000000 01/01/1988 00:00:00

Checkpoint cnt:106 scn: 0x0000.000d845f 11/14/2011 15:24:50

Stop scn: 0xffff.ffffffff 11/14/2011 14:31:00

Creation Checkpointed at scn: 0x0000.00000009 06/30/2005 19:10:11

thread:0 rba:(0x0.0.0)

enabled threads: 00000000 00000000 00000000 00000000 00000000 00000000

00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000

Offline scn: 0x0000.0006ce7a prev_range: 0

Online Checkpointed at scn: 0x0000.0006ce7b 11/10/2011 22:40:23

thread:1 rba:(0x1.2.0)

enabled threads: 01000000 00000000 00000000 00000000 00000000 00000000

Hot Backup end marker scn: 0x0000.00000000

aux_file is NOT DEFINED

(2) 日志文件頭包含了Low SCN 和Next SCN。

Low SCN和 Next SCN這兩個SCN表示該日志文件包含介於Low SCN到Next SCN的重做信息,對於Current的日志文件(當前正在被使用的Redo Logfile),其最終SCN不可知,所以Next SCN被置為無窮大,也就是ffffffff。

來看一下日志文件的情況:

SQL> select * from v$log;

GROUP# THREAD# SEQUENCE# BYTES MEMBERS ARC STATUS FIRST_CHANGE# FIRST_TIM

---------- ---------- ---------- ---------- ---------- --- ----------------------------- ---------

1 1 35 52428800 1 NO CURRENT 881890 14-NOV-11

2 1 33 52428800 1 YES INACTIVE 836815 12-NOV-11

3 1 34 52428800 1 YES INACTIVE 858362 12-NOV-11

SQL> select dbms_flashback.get_system_change_number from dual;

GET_SYSTEM_CHANGE_NUMBER

------------------------

889346

SQL> alter system switch logfile;

System altered.

SQL> select * from v$log;

GROUP# THREAD# SEQUENCE# BYTES MEMBERS ARC STATUS FIRST_CHANGE# FIRST_TIM

---------- ---------- ---------- ---------- ---------- --- ----------------------------- ---------

1 1 35 52428800 1 YES ACTIVE 881890 14-NOV-11

2 1 36 52428800 1 NO CURRENT 889353 14-NOV-11

3 1 34 52428800 1 YES INACTIVE 858362 12-NOV-11

可以看到,SCN 889346顯然位於Log Group#為1的日志文件中,該日志文件包含了SCN自881890 至889353 的Redo信息。Oracle在進行恢復時,就需要根據低SCN和高SCN來確定需要的恢復信息位於哪一個日志或歸檔文件中。

如果通過控制文件轉儲,可以在控制文件中找到關於日志文件的信息:

SQL> alter session set events 'immediate trace name redohdr level 10';

Session altered.

 

LOG FILE #1:

(name #3) /opt/ora10g/oradata/ORCL/redo01.log

Thread 1 redo log links: forward: 2 backward: 0

siz: 0x19000 seq: 0x00000026 hws: 0x1 bsz: 512 nab: 0xffffffff flg: 0x8 dup: 1

Archive links: fwrd: 0 back: 0 Prev scn: 0x0000.000de15c

Low scn: 0x0000.000def9a 11/16/2011 16:06:06

Next scn: 0xffff.ffffffff 01/01/1988 00:00:00

LOG FILE #2:

(name #2) /opt/ora10g/oradata/ORCL/redo02.log

Thread 1 redo log links: forward: 3 backward: 1

siz: 0x19000 seq: 0x00000024 hws: 0x4 bsz: 512 nab: 0x5c6 flg: 0x1 dup: 1

Archive links: fwrd: 0 back: 0 Prev scn: 0x0000.000d74e2

Low scn: 0x0000.000d9209 11/14/2011 16:57:08

Next scn: 0x0000.000de15c 11/16/2011 15:01:07

LOG FILE #3:

(name #1) /opt/ora10g/oradata/ORCL/redo03.log

Thread 1 redo log links: forward: 0 backward: 2

siz: 0x19000 seq: 0x00000025 hws: 0x3 bsz: 512 nab: 0x37e3 flg: 0x1 dup: 1

Archive links: fwrd: 0 back: 0 Prev scn: 0x0000.000d9209

Low scn: 0x0000.000de15c 11/16/2011 15:01:07

Next scn: 0x0000.000def9a 11/16/2011 16:06:06

可以注意到,Log File 1是當前的日志文件,該文件擁有的Next SCN是無窮大。

同樣,可以通過直接dump日志文件的方式來進行轉儲;

SQL> select * from v$logfile;

GROUP# STATUS TYPE MEMBER

---------- ------- ---------------------------------------------------------------------------

3 ONLINE /opt/ora10g/oradata/ORCL/redo03.log

2 ONLINE /opt/ora10g/oradata/ORCL/redo02.log

1 ONLINE /opt/ora10g/oradata/ORCL/redo01.log

SQL> alter system dump logfile '/opt/ora10g/oradata/ORCL/redo01.log';

System altered.

DUMP OF REDO FROM FILE '/opt/ora10g/oradata/ORCL/redo01.log'

Opcodes *.*

RBAs: 0x000000.00000000.0000 thru 0xffffffff.ffffffff.ffff

SCNs: scn: 0x0000.00000000 thru scn: 0xffff.ffffffff

Times: creation thru eternity

FILE HEADER:

Compatibility Vsn = 169869568=0xa200100

Db ID=1294662348=0x4d2afacc, Db Name='ORCL'

Activation ID=1294635980=0x4d2a93cc

Control Seq=953=0x3b9, File size=102400=0x19000

File Number=1, Blksiz=512, File Type=2 LOG

descrip:"Thread 0001, Seq# 0000000038, SCN 0x0000000def9a-0xffffffffffff"

thread: 1 nab: 0xffffffff seq: 0x00000026 hws: 0x1 eot: 1 dis: 0

resetlogs count: 0x2db5af57 scn: 0x0000.0006ce7b (446075)

resetlogs terminal rcv count: 0x0 scn: 0x0000.00000000

prev resetlogs count: 0x2184ef74 scn: 0x0000.00000001 (1)

prev resetlogs terminal rcv count: 0x0 scn: 0x0000.00000000

Low scn: 0x0000.000def9a (913306) 11/16/2011 16:06:06

Next scn: 0xffff.ffffffff 01/01/1988 00:00:00

Enabled scn: 0x0000.0006ce7b (446075) 11/10/2011 22:40:23

Thread closed scn: 0x0000.000def9a (913306) 11/16/2011 16:06:06

Disk cksum: 0x5987 Calc cksum: 0x5987

Terminal recovery stop scn: 0x0000.00000000

Terminal recovery 01/01/1988 00:00:00

Most recent redo scn: 0x0000.00000000

Largest LWN: 0 blocks

End-of-redo stream : No

Unprotected mode

Miscellaneous flags: 0x0

這里不打算詳細介紹具體命令的用戶及更進一步的內容,有興趣的朋友可以由此開始進一步的探索。



使用Oradebug修改Oracle SCN  

Oracle SCN對於數據庫運行、維護而言是至關重要的因素。在啟動從mountopen過程中,主要是各種文件的SCN進行比較的行為。通常情況下,我們是不需要介入到Oracle SCN的取值和設置,甚至錯誤的干預可能會引起嚴重運行事故。

 

在之前的文章中,筆者介紹過使用隱含參數和跟蹤事件來推動Oracle SCN前進的方法。但是,在11.2.0.2之后的版本中,Oracle關閉了這個通道,這種方法不在有效。在高版本情況下,我們是可以通過oradebug工具對SCN進行修改。

 

注意:這種方法比較危險,請不要在投產環境下進行測試。

 

1、實驗環境說明

 

筆者使用Oracle 11g進行測試,版本為11.2.0.4。對應操作系統是Linux 6.5 64bit版本。

 

 

SQL> select * from v$version;

 

BANNER

--------------------------------------------------------------------------------

Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production

PL/SQL Release 11.2.0.4.0 - Production

CORE    11.2.0.4.0      Production

TNS for Linux: Version 11.2.0.4.0 - Production

NLSRTL Version 11.2.0.4.0 – Production

 

 

我們先聊聊OracleSCN。在數據庫內部,SCN是一個單向遞增的數字編號,控制文件、數據文件、在線Redo日志、歸檔日志和備份集合中,都包括這個數字編號。在內部文件中,SCN是通過BaseWrap兩個部分進行保存。BaseSCN編號的基礎位,是通過32位二進制位進行保存。一旦超過這32位長度,系統會自動在Wrap進位。也就是說,Wrap表示的超過4G個數的進位次數。

 

使用Oracle oradebug修改SCN,可以在兩個場景下進行,就是Oracle啟動Open狀態和Mount狀態。下面分別進行說明。

 

2Open狀態下SCN修改

 

Open狀態,系統的SCN是在不斷的向前推動,即使對外沒有事務操作,系統內部SCN編號也在不斷的前進。我們先將數據庫進入open狀態。

 

 

SQL> alter database open;

Database altered.

 

SQL> select CHECKPOINT_CHANGE#, current_scn from v$database;

 

CHECKPOINT_CHANGE# CURRENT_SCN

------------------ -----------

           1753982     1754355

 

SQL> select dbms_flashback.get_system_change_number from dual;

 

GET_SYSTEM_CHANGE_NUMBER

------------------------

                 1754364

 

 

此時,從系統中提取出的SCN編號約為1754364,顯然沒有超過wrap的進位4G,變化為16進制如下:

 

 

SQL> select to_char(1754364, 'XXXXXXXX') from dual;

 

TO_CHAR(1754364,'XXXXXXXX')

---------------------------

   1AC4FC

 

 

使用oradebug查看內存中SCN對應的變量。

 

 

SQL> oradebug setmypid

Statement processed.

SQL> oradebug dumpvar sga kcsgscn_                      

kcslf kcsgscn_ [06001AE70, 06001AEA0) = 001AC52A 00000000 00000000 00000000 00000065 00000000 00000000 00000000 00000000 00000000 6001AB50 00000000

 

 

其中,0x001AC52A近似SCNBase部分。注意:Linux系統是Little位的操作系統,Base在前,Wrap在后。

 

 

SQL> select to_number('1AC52A','xxxxxx') from dual;

 

TO_NUMBER('1AC52A','XXXXXX')

----------------------------

                     1754410

 

 

下面計划將Base修改為1800000,查看16進制取值。

 

 

SQL> select to_char(1800000, 'XXXXXXXX') from dual;

 

TO_CHAR(1800000,'XXXXXXXX')

---------------------------

   1B7740

 

 

使用poke命令將計算好的值寫入進去。

 

 

SQL> oradebug poke 0x06001AE70 4 0x001B7740

BEFORE: [06001AE70, 06001AE74) = 001AC66F

AFTER:  [06001AE70, 06001AE74) = 001B7740

SQL> oradebug DUMPvar SGA kcsgscn_

kcslf kcsgscn_ [06001AE70, 06001AEA0) = 001B7745 00000000 00000000 00000000 00000164 00000000 00000000 00000000 00000000 00000000 6001AB50 00000000

SQL>

 

 

poke命令中,第一位參數是對應寫入的內存位數,第二位參數是寫入長度,第三位參數是寫入取值。默認寫入取值是10進制,我們在這里指定寫入16進制。

 

每一個取值段,用816進制對應,對應到數字位數是4位。此時查看Oracle情況。

 

 

SQL> select CHECKPOINT_CHANGE#, current_scn from v$database;

 

CHECKPOINT_CHANGE# CURRENT_SCN

------------------ -----------

           1753982     1800400

 

SQL> select dbms_flashback.get_system_change_number from dual;

 

GET_SYSTEM_CHANGE_NUMBER

------------------------

                 1800402

 

 

SQL> select file#, checkpoint_change# from v$datafile;

 

     FILE# CHECKPOINT_CHANGE#

---------- ------------------

         1            1753982

         2            1753982

         3            1753982

         4            1753982

         5            1753982

         6            1753982

         7            1753982

 

7 rows selected

 

SQL> select file#, checkpoint_change# from v$datafile_header;

 

     FILE# CHECKPOINT_CHANGE#

---------- ------------------

         1            1753982

         2            1753982

         3            1753982

         4            1753982

         5            1753982

         6            1753982

         7            1753982

 

7 rows selected

 

 

從上面看,內存和控制文件中新的取值已經寫入進去了。但是各個文件的頭塊和檢查點還沒有反應過來。此時可以使用checkpoint強制寫入。

 

 

SQL> alter system checkpoint;

System altered.

 

SQL> select file#, checkpoint_change# from v$datafile;

 

     FILE# CHECKPOINT_CHANGE#

---------- ------------------

         1            1800422

         2            1800422

         3            1800422

         4            1800422

         5            1800422

         6            1800422

         7            1800422

 

7 rows selected

 

SQL> select file#, checkpoint_change# from v$datafile_header;

 

     FILE# CHECKPOINT_CHANGE#

---------- ------------------

         1            1800422

         2            1800422

         3            1800422

         4            1800422

         5            1800422

         6            1800422

         7            1800422

 

7 rows selected

 

SQL> select CHECKPOINT_CHANGE#, current_scn from v$database;

 

CHECKPOINT_CHANGE# CURRENT_SCN

------------------ -----------

           1800422     1800433

 

 

此時,關閉重啟系統也不會有問題。篇幅原因,不進行具體展示。那么,很多時候SCN錯誤是會影響到開啟數據庫的,我們可能都不能進入open狀態。從mount狀態下我們怎么修改SCN編號。

 

3Mount狀態修改SCN編號

 

我們測試進入mount狀態。

 

 

SQL> startup mount

ORACLE instance started.

 

Total System Global Area 3540881408 bytes

Fixed Size                  2258320 bytes

Variable Size             855640688 bytes

Database Buffers         2667577344 bytes

Redo Buffers               15405056 bytes

Database mounted.

 

 

此時,oradebug命令導出內存取值。

 

 

SQL> oradebug setmypid

Statement processed.

SQL> oradebug DUMPvar SGA kcsgscn_

kcslf kcsgscn_ [06001AE70, 06001AEA0) = 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 6001AB50 00000000

 

 

注意:在mount狀態下,內存中的SCN取值都是0,包括basewrap兩部分。我們這次修改wrap01。這個過程中,我們需要寫入basewrap兩個部分,如果我們只寫入了wrap部分,base部分保持0,那么系統運行的時候,會從base0開始。

 

此時,需要查看一下當前文件里面SCN是多少。

 

 

SQL> select file#, checkpoint_change# from v$datafile;

 

     FILE# CHECKPOINT_CHANGE#

---------- ------------------

         1            1800920

         2            1800920

         3            1800920

         4            1800920

         5            1800920

         6            1800920

         7            1800920

 

7 rows selected

 

SQL> select file#, checkpoint_change# from v$datafile_header;

 

     FILE# CHECKPOINT_CHANGE#

---------- ------------------

         1            1800920

         2            1800920

         3            1800920

         4            1800920

         5            1800920

         6            1800920

         7            1800920

 

7 rows selected

 

SQL> select CHECKPOINT_CHANGE#, current_scn from v$database;

 

CHECKPOINT_CHANGE# CURRENT_SCN

------------------ -----------

           1800920           0

 

 

計算1800920對應到16進制取值為:0x001B7AD8。下面分別寫入basewrap取值。

 

 

SQL> oradebug DUMPvar SGA kcsgscn_

kcslf kcsgscn_ [06001AE70, 06001AEA0) = 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 6001AB50 00000000

SQL> oradebug poke 0x06001AE70 4 0x001B7AD8

BEFORE: [06001AE70, 06001AE74) = 00000000

AFTER:  [06001AE70, 06001AE74) = 001B7AD8

SQL> oradebug poke 0x06001AE74 4 0x00000001

BEFORE: [06001AE74, 06001AE78) = 00000000

AFTER:  [06001AE74, 06001AE78) = 00000001

SQL> oradebug DUMPvar SGA kcsgscn_

kcslf kcsgscn_ [06001AE70, 06001AEA0) = 001B7AD8 00000001 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 6001AB50 00000000

 

 

啟動數據庫。

 

 

SQL> alter database open;

Database altered.

 

SQL> select CHECKPOINT_CHANGE#, current_scn from v$database;

 

CHECKPOINT_CHANGE# CURRENT_SCN

------------------ -----------

        4296768217  4296768485

 

SQL> select file#, checkpoint_change# from v$datafile_header;

 

     FILE# CHECKPOINT_CHANGE#

---------- ------------------

         1         4296768217

         2         4296768217

         3         4296768217

         4         4296768217

         5         4296768217

         6         4296768217

         7         4296768217

 

7 rows selected

 

SQL> select file#, checkpoint_change# from v$datafile;

 

     FILE# CHECKPOINT_CHANGE#

---------- ------------------

         1         4296768217

         2         4296768217

         3         4296768217

         4         4296768217

         5         4296768217

         6         4296768217

         7         4296768217

 

7 rows selected

 

 

顯然在open的時候,寫入的checkpoint在所有文件中。寫入的wrap頭也比較清晰。

 

 

SQL> select 4296768217/(4*1024*1024*1024) from dual;

 

4296768217/(4*1024*1024*1024)

-----------------------------

              1.0004193095956

 

SQL> oradebug DUMPvar SGA kcsgscn_

kcslf kcsgscn_ [06001AE70, 06001AEA0) = 001B7C1D 00000001 00000000 00000000 00000047 00000000 00000000 00000000 00000000 00000000 6001AB50 00000000

 

 

4、結論

 

使用oradebug直接修改內存SCN,是我們在故障修復時候非常快捷的方法。不過,快捷建立在對內部機制清晰理解的前提之下。所以,無論何種場景進行修復,有備份、可恢復是我們工作的基本前提。

 



Oracle系統表 smon_scn_time 的說明

一.SMON_SCN_TIME 表結構說明

 

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;

 



  由oradebug poke推進scn理解scn base及scn wrap系列一  

背景

   在v$transaction會看到scn,其中又分為scn base及scn wrap,這到底怎么回事呢?而且很多ORA報錯與SCN有關,如果多了解一些SCN相關的知識,也便於我們
分析解決問題。   


結論

1,oradebug poke可以推進SCN,分為在數據庫OPEN及MOUNT皆可以
oradebug setmypid


oradebug DUMPvar SGA kcsgscn_


oradebug poke 0x060012658 4 1000


2,關於kcsgscn_變量我是在BAIDU上面查的,而關於SCN到底是對應內存是哪塊區域,我是采用多次運行oradebug DUMPvar SGA kcsgscn_,看哪些內存的值在變化,基本就是哪塊


3,oradebug poke 0x060012658 4 1000 就是推進SCN的命令,具體含義如下:
  oradebug  poke 內存地址  長度  要修改的內容 ,注意這個要修改的內容必須是十進制,如果是16進制會報上述的錯(這里我采用了反向對比思維),且這里長度是前4個字節


4,如果是在OPEN狀態下推進SCN,oradebug DUMPvar SGA kcsgscn_是有值的,而在MOUNT因為數據庫沒有打開,所在是空的,全是0,那么如何調整SCN,可以基於每個文件頭的BLOCK 1的數據結構kscnbas及kscnwrp進行調整
   這個數據結構對應select file#,name,checkpoint_change# from v$datafile;
  BBED> map
 File: /home/ora10g/asia/asia/users01.dbf (0)
 Block: 1                                     Dba:0x00000000
------------------------------------------------------------
 Data File Header


 struct kcvfh, 676 bytes                    @0       


 ub4 tailchk                                @8188    




BBED> p kcvfh
   struct kcvfhckp, 36 bytes                @484     
      struct kcvcpscn, 8 bytes              @484     
         ub4 kscnbas                        @484      0x028f5c58  --scn base  
         ub2 kscnwrp                        @488      0x0000      --scn wrap




5,select current_scn from v$database,這個SCN是一直在變化,可以叫作內存SCN


6,scn是由scn base及scn wrap構成的,當scn base達到一定程度,scn wrap則會遞增,一般情況下scn wrap是0,不會變化


7,scn base及scn wrap也是數據塊中的數據結構,可見scn base是4個字節,而scn wrap是2個字節
  也就是說scn base要用4個字節用完,scn wrap就會遞增
  依理推理,4個字節為 power(2,32),也就是達到這個數據時,scn base就會歸0,scn wrap遞增1


8,基於  select file#,name,checkpoint_change# from v$datafile;和數據結構的scn base及scn wrap可知scn計算公式為


scn=scn wrap * power(2,32)+scn base


9,進一步引申,也可以計算出為scn最大值,因為scn base及scn wrap是由4個字節及4個字節構成的,而這些字節表示的數據范圍是有限的
 


10,如果過小調整scn遠小於checkpoint_change#,會引發ora-600 2662,當然解決也很容易,基於checkpoint_change#調大scn即可
   否則2662會引發數據庫強制關閉


測試


SQL> select * from v$version where rownum=1;


BANNER
----------------------------------------------------------------
Oracle Database 10g Enterprise Edition Release 10.2.0.5.0 - 64bi


---可見事務也有scn base及scn wrap的概念
SQL> desc v$transaction;
 Name              Null?    Type
 ----------------- -------- ------------
 ADDR                       RAW(8)
 XIDUSN                     NUMBER
 XIDSLOT                    NUMBER
 XIDSQN                     NUMBER
 UBAFIL                     NUMBER
 UBABLK                     NUMBER
 UBASQN                     NUMBER
 UBAREC                     NUMBER
 STATUS                     VARCHAR2(16)
 START_TIME                 VARCHAR2(20)
 START_SCNB                 NUMBER  --scn base
 START_SCNW                 NUMBER  --scn wrap
 START_UEXT                 NUMBER
 START_UBAFIL               NUMBER
 START_UBABLK               NUMBER
 START_UBASQN               NUMBER
 START_UBAREC               NUMBER
 SES_ADDR                   RAW(8)
 FLAG                       NUMBER
 SPACE                      VARCHAR2(3)
 RECURSIVE                  VARCHAR2(3)
 NOUNDO                     VARCHAR2(3)
 PTX                        VARCHAR2(3)
 NAME                       VARCHAR2(256
                            )
 PRV_XIDUSN                 NUMBER
 PRV_XIDSLT                 NUMBER
 PRV_XIDSQN                 NUMBER
 PTX_XIDUSN                 NUMBER
 PTX_XIDSLT                 NUMBER
 PTX_XIDSQN                 NUMBER
 DSCN-B                     NUMBER --scn base
 DSCN-W                     NUMBER  --scn wrap
 USED_UBLK                  NUMBER
 USED_UREC                  NUMBER
 LOG_IO                     NUMBER
 PHY_IO                     NUMBER
 CR_GET                     NUMBER
 CR_CHANGE                  NUMBER
 START_DATE                 DATE
 DSCN_BASE                  NUMBER --scn base
 DSCN_WRAP                  NUMBER --scn wrap
 START_SCN                  NUMBER
 DEPENDENT_SCN              NUMBER
 XID                        RAW(8)
 PRV_XID                    RAW(8)
 PTX_XID                    RAW(8)




---普通數據塊也有scn base及scn wrap的概念,且scn base為4個字節,scn wrap為2個字節
BBED> map
 File: /home/ora10g/asia/asia/users01.dbf (0)
 Block: 12                                    Dba:0x00000000
------------------------------------------------------------
 KTB Data Block (Table/Cluster)


 struct kcbh, 20 bytes                      @0       


 struct ktbbh, 72 bytes                     @20      


 struct kdbh, 14 bytes                      @100     


 struct kdbt[1], 4 bytes                    @114     


 sb2 kdbr[32]                               @118     


 ub1 freespace[7814]                        @182     


 ub1 rowdata[192]                           @7996    


 ub4 tailchk                                @8188    




BBED> p kcbh
struct kcbh, 20 bytes                       @0       
   ub1 type_kcbh                            @0        0x06
   ub1 frmt_kcbh                            @1        0xa2
   ub1 spare1_kcbh                          @2        0x00
   ub1 spare2_kcbh                          @3        0x00
   ub4 rdba_kcbh                            @4        0x0100000c
   ub4 bas_kcbh                             @8        0x00048e91  --scn base
   ub2 wrp_kcbh                             @12       0x0000  --scn wrap
   ub1 seq_kcbh                             @14       0x02
   ub1 flg_kcbh                             @15       0x06 (KCBHFDLC, KCBHFCKV)
   ub2 chkval_kcbh                          @16       0x7e45
   ub2 spare3_kcbh                          @18       0x0000


BBED> 


---數據文件頭也有scn base及scn wrap的概念
BBED> map
 File: /home/ora10g/asia/asia/users01.dbf (0)
 Block: 1                                     Dba:0x00000000
------------------------------------------------------------
 Data File Header


 struct kcvfh, 676 bytes                    @0       


 ub4 tailchk                                @8188    




BBED> p kcvfh
struct kcvfh, 676 bytes                     @0       
   struct kcvfhbfh, 20 bytes                @0       
      ub1 type_kcbh                         @0        0x0b
      ub1 frmt_kcbh                         @1        0xa2
      ub1 spare1_kcbh                       @2        0x00
      ub1 spare2_kcbh                       @3        0x00
      ub4 rdba_kcbh                         @4        0x01000001
      ub4 bas_kcbh                          @8        0x00000000
      ub2 wrp_kcbh                          @12       0x0000




從上述我們發現基本scn wrap全是0,那么何時scn會變成非0呢,我想到了推進SCN,然后對比DUMP數據塊,可以了其原理了




SQL> select current_scn,checkpoint_change# from v$database;


CURRENT_SCN CHECKPOINT_CHANGE#
----------- ------------------
     311981             296387




SQL> alter session set events 'immediate trace name adjust_scn level 1';


Session altered.


SQL> select current_scn,checkpoint_change# from v$database;


CURRENT_SCN CHECKPOINT_CHANGE#
----------- ------------------
     311996             296387




可見上述推進SCN太慢了
SQL> select 311996-311981 from dual;


311996-311981
-------------
           15          




---且ALERT會報權限不足的錯誤信息
Mon Nov 30 23:46:36 EST 2015
Errors in file /home/ora10g/admin/asia/udump/asia_ora_23849.trc:
ORA-01031: insufficient privileges


---上述推進SCN方法太慢,我們嘗試另一種快速推進SCN的方法,不過要重啟庫到MOUNT狀態
SQL> shutdown immediate
Database closed.
Database dismounted.
ORACLE instance shut down.
SQL> startup mount
ORACLE instance started.


Total System Global Area  901775360 bytes
Fixed Size                  2100424 bytes
Variable Size             226493240 bytes
Database Buffers          666894336 bytes
Redo Buffers                6287360 bytes
Database mounted.


---可見MOUNT狀態下CURRENT_SCN為0,其它SCN列皆有值
SQL> select current_scn,checkpoint_change# from v$database;


CURRENT_SCN CHECKPOINT_CHANGE#
----------- ------------------
          0             312204






SQL> select file#,name,checkpoint_change# from v$datafile;


     FILE# NAME                                               CHECKPOINT_CHANGE#
---------- -------------------------------------------------- ------------------
         1 /home/ora10g/asia/asia/system01.dbf                            312204
         2 /home/ora10g/asia/asia/undotbs01.dbf                           312204
         3 /home/ora10g/asia/asia/sysaux01.dbf                            312204
         4 /home/ora10g/asia/asia/users01.dbf                             312204


SQL> select file#,checkpoint_change# from v$datafile_header;


     FILE# CHECKPOINT_CHANGE#
---------- ------------------
         1             312204
         2             312204
         3             312204
         4             312204




SQL> select to_char('312204','xxxxxxx') from dual;


TO_CHAR(
--------
   4c38c


---bbed查看數據文件的SCN,可知是4c38c


   struct kcvfhckp, 36 bytes                @484     
      struct kcvcpscn, 8 bytes              @484     
         ub4 kscnbas                        @484      0x0004c38c
         ub2 kscnwrp                        @488      0x0000


---用10015事件推進SCN發現沒有變化,可見在MOUNT狀態下不生效推進SCN
SQL> alter session set events '10015 trace name adjust_scn level 1';


Session altered.


SQL> select current_scn,checkpoint_change# from v$database;


CURRENT_SCN CHECKPOINT_CHANGE#
----------- ------------------
          0             312204


打開數據庫看看有無生效,也是沒有效果
SQL> alter database open;


Database altered.   




SQL> select current_scn,checkpoint_change# from v$database;


CURRENT_SCN CHECKPOINT_CHANGE#
----------- ------------------
     312409             312207


SQL> select file#,name,checkpoint_change# from v$datafile;


     FILE# NAME                                               CHECKPOINT_CHANGE#
---------- -------------------------------------------------- ------------------
         1 /home/ora10g/asia/asia/system01.dbf                            312207
         2 /home/ora10g/asia/asia/undotbs01.dbf                           312207
         3 /home/ora10g/asia/asia/sysaux01.dbf                            312207
         4 /home/ora10g/asia/asia/users01.dbf                             312207






---換另一種方法,用ORADEBUG POKE推進SCN
SQL> shutdown immediate
Database closed.
Database dismounted.
ORACLE instance shut down.
SQL> startup mount
ORACLE instance started.


Total System Global Area  901775360 bytes
Fixed Size                  2100424 bytes
Variable Size             226493240 bytes
Database Buffers          666894336 bytes
Redo Buffers                6287360 bytes
Database mounted.


SQL> oradebug setmypid
Statement processed.
SQL> oradebug DUMPvar SGA kcsgscn_
kcslf kcsgscn_ [060012658, 060012688) = 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 60012338 00000000
SQL> 


SQL> select file#,name,checkpoint_change# from v$datafile;


     FILE# NAME                                               CHECKPOINT_CHANGE#
---------- -------------------------------------------------- ------------------
         1 /home/ora10g/asia/asia/system01.dbf                            312714
         2 /home/ora10g/asia/asia/undotbs01.dbf                           312714
         3 /home/ora10g/asia/asia/sysaux01.dbf                            312714
         4 /home/ora10g/asia/asia/users01.dbf                             312714


SQL> select to_char('312714','xxxxxx') from dual;


TO_CHAR
-------
  4c58a




  SQL> oradebug poke 0x060012658 8 0x0004c58a
BEFORE: [060012658, 060012660) = 00000000 00000000
AFTER:  [060012658, 060012660) = 0004C58A 00000000
SQL> oradebug DUMPvar SGA kcsgscn
kcslf kcsgscn_ [060012658, 060012688) = 0004C58A 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 60012338 00000000
SQL> 




SQL> alter database open;


Database altered.




SQL> select file#,name,checkpoint_change# from v$datafile;


     FILE# NAME                                               CHECKPOINT_CHANGE#
---------- -------------------------------------------------- ------------------
         1 /home/ora10g/asia/asia/system01.dbf                            312717
         2 /home/ora10g/asia/asia/undotbs01.dbf                           312717
         3 /home/ora10g/asia/asia/sysaux01.dbf                            312717
         4 /home/ora10g/asia/asia/users01.dbf                             312717


好像沒起作用
SQL> select current_scn,checkpoint_change# from v$database;


CURRENT_SCN CHECKPOINT_CHANGE#
----------- ------------------
     312891             312717


---換個思路,試試在數據庫打開時推進SCN
SQL> select file#,name,checkpoint_change# from v$datafile;


     FILE# NAME                                               CHECKPOINT_CHANGE#
---------- -------------------------------------------------- ------------------
         1 /home/ora10g/asia/asia/system01.dbf                            313429
         2 /home/ora10g/asia/asia/undotbs01.dbf                           313429
         3 /home/ora10g/asia/asia/sysaux01.dbf                            313429
         4 /home/ora10g/asia/asia/users01.dbf                             313429


SQL> select current_scn,checkpoint_change# from v$database;


CURRENT_SCN CHECKPOINT_CHANGE#
----------- ------------------
     313917             313429


SQL> select to_char('313917','xxxxxxxxxx') from dual;


TO_CHAR('31
-----------
      4ca3d


---經間隔多次運行如下ORADEBUG命令,我分析CURRENT_SCN就是內存中的第1部分(因為就這部分信息在變化,其它信息是固定的)
SQL> oradebug setmypid
Statement processed.
SQL> oradebug DUMPvar SGA kcsgscn_
kcslf kcsgscn_ [060012658, 060012688) = 0004CAD4 00000000 00000000 00000000 00000113 00000000 00000000 00000000 00000000 00000000 60012338 00000000
SQL> 
SQL> 
SQL> 
SQL> oradebug DUMPvar SGA kcsgscn_
kcslf kcsgscn_ [060012658, 060012688) = 0004CAD6 00000000 00000000 00000000 00000114 00000000 00000000 00000000 00000000 00000000 60012338 00000000
SQL> 
SQL> 
SQL> oradebug DUMPvar SGA kcsgscn_
kcslf kcsgscn_ [060012658, 060012688) = 0004CAD7 00000000 00000000 00000000 00000115 00000000 00000000 00000000 00000000 00000000 60012338 00000000
SQL>       


---所以我們只要改第1部分信息的內容即可
SQL> oradebug poke 0x060012658 4 FFFFA3523
ORA-01858: a non-numeric character was found where a numeric was expected
SQL> 


可見oradeug poke 的含義是oradebug  poke 內存地址  長度  要修改的內容 ,注意這個要修改的內容必須是十進制,如果是16進制會報上述的錯(這里我采用了反向對比思維),且這里長度是前4個字節
SQL> oradebug poke 0x060012658 4 1000
BEFORE: [060012658, 06001265C) = 0004CB41
AFTER:  [060012658, 06001265C) = 000003E8
SQL> select to_number('3E8','xxxxxxxxx') from dual;


TO_NUMBER('3E8','XXXXXXXXX')
----------------------------
                        1000


---而且上述由於把SCN改得過小,小於數據文件及控制文件的SCN,會報ORA-600 的2662錯誤,處理很簡單,快速基於checkpoint_change#把SCN變大即可,否則過會數據庫就會DOWN機
SQL> select current_scn,checkpoint_change# from v$database;
select current_scn,checkpoint_change# from v$database
                                           *
ERROR at line 1:
ORA-00600: internal error code, arguments: [2662], [0], [71], [0], [333548],
[0], [], []


---基於上述分析,因為原來SCN是313917,我們加到19999999999


SQL> oradebug setmypid
Statement processed.
SQL> select power(2,32) from dual;


POWER(2,32)
-----------
 4294967296


如果把SCN調整為上述的值,馬上ALAERT會報錯
SQL> oradebug DUMPvar SGA kcsgscn_
kcslf kcsgscn_ [060012658, 060012688) = 000565AE 00000000 00000000 00000000 00000075 00000000 00000000 00000000 00000000 00000000 60012338 00000000
SQL> oradebug poke 0x060012658 4 4294967296
BEFORE: [060012658, 06001265C) = 000565B3
AFTER:  [060012658, 06001265C) = 00000000


Tue Dec 01 01:27:33 EST 2015
Errors in file /home/ora10g/admin/asia/bdump/asia_cjq0_27711.trc:
ORA-00604: error occurred at recursive SQL level 1
ORA-08176: consistent read failure; rollback data not available


--所以可見SCN也不能隨意去調太大,ORACLE內部肯定有個控制算法的,否則會把庫搞DOWN掉
SQL> oradebug poke 0x060012658 4 42949670
BEFORE: [060012658, 06001265C) = 00000003
AFTER:  [060012658, 06001265C) = 028F5C26






SQL> alter system checkpoint;


System altered.


SQL> alter system checkpoint;


System altered.


SQL> select file#,name,checkpoint_change# from v$datafile;


     FILE# NAME                                               CHECKPOINT_CHANGE#
---------- -------------------------------------------------- ------------------
         1 /home/ora10g/asia/asia/system01.dbf                          42949720
         2 /home/ora10g/asia/asia/undotbs01.dbf                         42949720
         3 /home/ora10g/asia/asia/sysaux01.dbf                          42949720
         4 /home/ora10g/asia/asia/users01.dbf                           42949720


---可見SCN已經調整為指定的SCN了
SQL> select current_scn,checkpoint_change# from v$database;


CURRENT_SCN CHECKPOINT_CHANGE#
----------- ------------------
   42949724           42949720






---換個思路繼糿研究SCN BASE及SCN WRAP,如果我一直增加SCN BASE,SCN WRAP會有變化呢,我理解肯定是SCN BASE大到一定程度,SCN WRAP就會有變化
BBED> map
 File: /home/ora10g/asia/asia/users01.dbf (0)
 Block: 1                                     Dba:0x00000000
------------------------------------------------------------
 Data File Header


 struct kcvfh, 676 bytes                    @0       


 ub4 tailchk                                @8188    




BBED> p kcvfh
   struct kcvfhckp, 36 bytes                @484     
      struct kcvcpscn, 8 bytes              @484     
         ub4 kscnbas                        @484      0x028f5c58  --scn base
         ub2 kscnwrp                        @488      0x0000






SQL> select to_number('&x','xxxxxxxx') from dual;
Enter value for x: 28f5c58
old   1: select to_number('&x','xxxxxxxx') from dual
new   1: select to_number('28f5c58','xxxxxxxx') from dual


TO_NUMBER('28F5C58','XXXXXXXX')
-------------------------------
                       42949720




BBED> set offset 484
        OFFSET          484


BBED> dump count 5
 File: /home/ora10g/asia/asia/users01.dbf (0)
 Block: 1                Offsets:  484 to  488           Dba:0x00000000
------------------------------------------------------------------------
 585c8f02 00 


 <32 bytes="" per="" line="">


 SQL> select power(2,31) from dual;


POWER(2,31)
-----------
 2147483648


 SQL> select to_char('2147483648','xxxxxxxxx') from dual;


TO_CHAR('2
----------
  80000000


BBED> modify /x 00000080
Warning: contents of previous BIFILE will be lost. Proceed? (Y/N) Y
 File: /home/ora10g/asia/asia/users01.dbf (0)
 Block: 1                Offsets:  484 to  488           Dba:0x00000000
------------------------------------------------------------------------
 00000080 00 


 <32 bytes="" per="" line="">




--還要調整tailchk
可以看到tailchk校驗由ub4 bas_kcbh的低4位+ub1 type_kcbh+ub1 seq_kcbh


BBED> p tailchk
ub4 tailchk                                 @8188     0x00000b01


      ub4 bas_kcbh                          @8        0x00000000


      ub1 type_kcbh                         @0        0x0b


      ub1 seq_kcbh                          @14       0x01




BBED> sum apply
Check value for File 0, Block 1:
current = 0x2dac, required = 0x2dac


   ---調整后   
   struct kcvfhckp, 36 bytes                @484     
      struct kcvcpscn, 8 bytes              @484     
         ub4 kscnbas                        @484      0x80000000
         ub2 kscnwrp                        @488      0x0000




BBED> p tailchk
ub4 tailchk                                 @8188     0x00000b01




SQL> conn scott/system
Connected.
SQL> create table t_modafter(a int);


Table created.


SQL> insert into t_modafter values(1);


1 row created.


SQL> commit;


Commit complete.




SQL> conn /as sysdba
Connected.
SQL> alter system checkpoint;


System altered.


SQL> alter system flush buffer_cache;


System altered.


---調整scn base到最大值-1
SQL> select power(2,32)-1 from dual;


POWER(2,32)-1
-------------
   4294967295


SQL> select to_char('4294967295','xxxxxxxxxx') from dual;


TO_CHAR('42
-----------
   ffffffff


---報錯可以分2步進行,即先2個字節進行,然后再把余下的2個字節修改完
BBED> modify /x ffffffff
BBED-00209: invalid number (ffffffff)


BBED> modify /x ffff
Warning: contents of previous BIFILE will be lost. Proceed? (Y/N) Y
 File: /home/ora10g/asia/asia/users01.dbf (0)
 Block: 1                Offsets:  484 to  488           Dba:0x00000000
------------------------------------------------------------------------
 ffff0080 00 


 <32 bytes="" per="" line="">




 BBED> set offset 486
        OFFSET          486


BBED> dump
 File: /home/ora10g/asia/asia/users01.dbf (0)
 Block: 1                Offsets:  486 to  488           Dba:0x00000000
------------------------------------------------------------------------
 008000 


 <32 bytes="" per="" line="">


BBED> modify /x ffff
 File: /home/ora10g/asia/asia/users01.dbf (0)
 Block: 1                Offsets:  486 to  488           Dba:0x00000000
------------------------------------------------------------------------
 ffff00 


 <32 bytes="" per="" line="">




BBED> dump
 File: /home/ora10g/asia/asia/users01.dbf (0)
 Block: 1                Offsets:  484 to  486           Dba:0x00000000
------------------------------------------------------------------------
 ffffff 


 <32 bytes="" per="" line="">


BBED> p kcvfh
   struct kcvfhckp, 36 bytes                @484     
      struct kcvcpscn, 8 bytes              @484     
         ub4 kscnbas                        @484      0xffffffff  scn_base已經調整為 power(2,32)-1 ,其中32代表4個字節,每個字節byte即8bit,所以就是32個bit,可以表示的數據即power(2,32)
         ub2 kscnwrp                        @488      0x0000


SQL> alter system flush buffer_cache;


System altered.


SQL> alter system checkpoint;
System altered.


BBED> p kcvfh


   struct kcvfhckp, 36 bytes                @484     
      struct kcvcpscn, 8 bytes              @484     
         ub4 kscnbas                        @484      0x00000002
         ub2 kscnwrp                        @488      0x0001  ---看到沒,SCN WRAP有值了,哈哈說明,SCN BASE大到一定程度,它就有值了




SQL> select file#,name,checkpoint_change# from v$datafile;


     FILE# NAME                                               CHECKPOINT_CHANGE#
---------- -------------------------------------------------- ------------------
         1 /home/ora10g/asia/asia/system01.dbf                        4294967298
         2 /home/ora10g/asia/asia/undotbs01.dbf                       4294967298
         3 /home/ora10g/asia/asia/sysaux01.dbf                        4294967298
         4 /home/ora10g/asia/asia/users01.dbf                         4294967298   




可見scn=scn wrap * power(2,32)+scn base
SQL> select 1*4294967296+2 from dual;


1*4294967296+2
--------------
    4294967298


也就是說scn wrap有值時,scn又開始從0開始計數,由此可見ORACLE設計的精妙所在,再深入一些,也可以知道SCN最大值是什么,哈哈








About Me

...............................................................................................................................

● 本文作者:小麥苗,只專注於數據庫的技術,更注重技術的運用

● 本文在itpub(http://blog.itpub.net/26736162)、博客園(http://www.cnblogs.com/lhrbest)和個人微信公眾號(xiaomaimiaolhr)上有同步更新

● 本文itpub地址:http://blog.itpub.net/26736162/viewspace-2126407/

● 本文博客園地址:http://www.cnblogs.com/lhrbest/p/5961987.html

● 本文pdf版及小麥苗雲盤地址:http://blog.itpub.net/26736162/viewspace-1624453/

● 數據庫筆試面試題庫及解答:http://blog.itpub.net/26736162/viewspace-2134706/

● QQ群:230161599     微信群:私聊

● 聯系我請加QQ好友(646634621),注明添加緣由

● 於 2017-07-01 09:00 ~ 2017-07-31 22:00 在魔都完成

● 文章內容來源於小麥苗的學習筆記,部分整理自網絡,若有侵權或不當之處還請諒解

● 版權所有,歡迎分享本文,轉載請保留出處

...............................................................................................................................

拿起手機使用微信客戶端掃描下邊的左邊圖片來關注小麥苗的微信公眾號:xiaomaimiaolhr,掃描右邊的二維碼加入小麥苗的QQ群,學習最實用的數據庫技術。


DBA筆試面試講解
歡迎與我聯系



免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM