SCN基礎

壹頁書發表於2014-10-14

SCN是什麼

在《Concepts》中是描述SCN的:

system change number (SCN) is a logical, internal timestamp 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.

怎麼理解這個“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都會增加。也許你會想為什麼不直接記錄事務提交時候的時間戳呢?這裡面主要是涉及了兩個問題,一個是時間戳記錄的精度有限,再一個就是在分散式系統中記錄時間戳會存在系統時鐘同步的問題,詳細的討論可以檢視。

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


SCN檢視與轉換

檢視系統當前的SCN

Oracle資料庫提供了兩種直接檢視系統當前SCN的方法,一個是V$DATABASE中的CURRENT_SCN列,另外一個就是透過dbms_flashback.get_system_change_number得到。

1
2
3
4
5
6
SQL> col scn for 9999999999999
SQL> SELECT current_scn scn FROM v$database;
 
           SCN
--------------
 7046242302279
1
2
3
4
5
6
SQL> col scn for 9999999999999
SQL> SELECT DBMS_FLASHBACK.GET_SYSTEM_CHANGE_NUMBER scn FROM DUAL;
 
           SCN
--------------
 7046242302616

如果你好奇心足夠的話也許會執行下面的語句,然後發現一個“驚訝”的結果:

1
2
3
4
5
6
7
8
SQL> col scn2 for 9999999999999
SQL> col scn for 9999999999999
SQL> SELECT current_scn scn,
DBMS_FLASHBACK.GET_SYSTEM_CHANGE_NUMBER scn2
FROM v$database;
           SCN           SCN2
-------------- --------------
 7046253210061  7046253210063

不過請不要驚訝,這個很正常,畢竟語句的執行時需要時間的,雖然很短,不過還是能發生很多的事情。

SCN與時間的相互轉換

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

SCN_TO_TIMESTAMP(scn_number) 將SCN轉換成時間戳。 TIMESTAMP_TO_SCN(timestamp) 將時間戳轉換成SCN。

下面就舉幾個例子來說明:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
-- 將SCN轉換成時間戳
SQL> SELECT SCN_TO_TIMESTAMP(7046253210061) timestamp FROM DUAL;
 
TIMESTAMP
---------------------------------------------------------------------------
30-MAR-10 10.53.04.000000000 AM
 
-- 將時間戳轉換成SCN
SQL> SELECT TIMESTAMP_TO_SCN(TO_TIMESTAMP('30-MAR-10 10.53.04.000000000 AM',
'DD-Mon-RR HH:MI:SS.FF AM')) SCN FROM DUAL;
 
           SCN
--------------
 7046253197273

很明顯的能看到同樣的時間戳,轉換出來的SCN就是不一樣,其根本原因就是粒度問題了。


ORA_ROWSCN偽列

從10g開始,Oracle提供了一個名為ORA_ROWSCN的偽列來讓我們更近距離的接觸SCN這個東西,利用這個偽列能很清楚的觀察提交(Commit)操作對於表中SCN的影響。

我們先來建立以下測試的資料表和資料(例子延伸自《Oracle9i & 10g程式設計藝術》一書),下面的例子進行兩次,兩次唯一的不同在於建表時引數不一樣,我們透過這個來觀察SCN記錄的一些行為。

試驗一:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
-- 建立表
CREATE TABLE t ( x INT );
 
-- 插入資料
BEGIN
    FOR i IN 1 .. 5
        LOOP
            INSERT INTO t VALUES ( i );
                        COMMIT;
        END LOOP;
    END;
/
-- 檢視結果
SQL> SELECT x, ORA_ROWSCN scn,
  2  DBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID) BLOCKNO
  3  FROM t ORDER BY 2;
 
         X            SCN    BLOCKNO
---------- -------------- ----------
         1  7046267387297      31002
         2  7046267387297      31002
         3  7046267387297      31002
         4  7046267387297      31002
         5  7046267387297      31002

試驗二:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
-- 建立表
CREATE TABLE t ( x INT ) ROWDEPENDENCIES;
 
-- 插入資料
BEGIN
    FOR i in 1 .. 5
        LOOP
            INSERT INTO t VALUES ( i );
                        COMMIT;
        END LOOP;
    END;
/
-- 檢視結果
SQL> SELECT x, ORA_ROWSCN scn,
  2  DBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID) blockno
  3  FROM t ORDER BY 2;
 
         X            SCN    BLOCKNO
---------- -------------- ----------
         1  7046267390044      31002
         2  7046267390046      31002
         3  7046267390047      31002
         4  7046267390048      31002
         5  7046267390050      31002

試驗一中每行資料的SCN資料都是一樣的,如果根據我們現在對SCN的理解的話每次提交之後SCN應該變化才對的,那問題出在哪裡呢?問題就出在預設情況下Oracle資料庫記錄SCN是以資料庫為單位記錄的,因為在資料庫讀取資料的時候都是以資料塊單位,而不是以行為單位的。

要想達到按行記錄SCN就必須在建立表的時候使用引數,ROWDEPENDENCIES用於開啟一個資料表的行級的追蹤,在行級維護SCN記錄,使得我們能清楚的看到每次提交操作對於SCN的影響。試驗二就是使用表的ROWDEPENDENCIES特性之後的結果。

ROWDEPENDENCIES有個重要的作用是用來實現樂觀鎖定(Optimistic Locking),這個在《Oracle9i & 10g程式設計藝術》一書中有詳細的描述。


關於SCN分類

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

下面再列舉一些常見的SCN分類:

  • 系統檢查點SCN (System Checkpoint SCN)
  • 檔案檢查點SCN (Datafile Checkpoint SCN)
  • 開始SCN (Start SCN)
  • 結束SCN (Stop SCN)

關於這些不同的SCN的定義環境和作用會在後續備份恢復相關文章中詳細說明。


SCN的作用

SCN描述的是資料一致性的狀態,自然的它就會在各種涉及資料一致性的場合中起到重要作用的,下面列舉的就是其中的一部分:

  • 讀資料的一致性
  • 資料庫恢復
  • Flashback
  • Stream
  • 等等其他的

說這個的原因就是想說SCN在Oracle中的應用無處不在,理解SCN是理解資料庫許多其他功能工作原理的基礎。


延伸閱讀



轉載自:


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/29254281/viewspace-1298018/,如需轉載,請註明出處,否則將追究法律責任。

相關文章