揭示檢查點的祕密
檢查點總結
oracle 8以前都是完全檢查點,每次觸發,則記錄當前資料庫SCN號,並將記憶體裡所有截至到該SCN號的髒資料塊都重新整理到資料檔案裡。從而同步資料檔案。
隨著記憶體越來越便宜,以及控制例項恢復的需要,完全檢查點已經不適合實際情況了。於是從oracle 8開始,oracle引入了增量檢查點,通過增量檢查點來減少例項恢復的時間。為此,oracle引入了checkpoint queue,按照資料塊第一次被修改的先後順序,將髒資料塊掛到該佇列上。同時還在該佇列上記錄了每個髒資料塊第一次被修改時產生的redo entry的地址,這叫LRBA。
增量檢查點的啟動時機由以下引數控制:
·fast_start_mttr_target:應用從CKPT position到最後一個redo entry之間所有redo entry所花的時間。也就是例項前滾所花費的時間。
·LOG_CHECKPOINT_INTERVAL:如果自從上一次檢查點啟動以來所累積的日誌塊個數達到該引數,則觸發增量檢查點,從而觸發DBWn寫髒塊。
·LOG_CHECKPOINT_TIMEOUT:兩次檢查點啟動的時間間隔。實際也就是控制髒塊在記憶體裡待多長時間的引數。
·90%*(SUM(log_size) – MAX(log_size)):如果產生的redo塊的量達到該值,則啟動增量檢查點。
只要滿足上面條件中的任何一個,就會啟動增量檢查點。增量檢查點一旦啟動,則會記錄當前CKPT SCN。
然後通知DBWn程式去寫checkpoint queue上所掛載的髒塊,至於寫到哪個髒塊為止,則不超過到當前CKPT SCN。
DBWn程式是批量寫髒塊的,髒塊個數不到一定程度,DBWn不會真的去寫。而每次寫多少個髒塊的個數則由一個隱藏引數控制。
每隔3秒鐘(這叫heartbeat,心跳),“增量檢查點”也還會啟動一次,只不過這時增量檢查點啟動只是檢視一下checkpoint queue,將該佇列上的第一個髒塊所對應的redo block的地址寫入控制檔案,也就是將CKPT Position寫入控制檔案,並不會觸發DBWn程式寫髒塊。所以是打引號的增量檢查點。
有關檢查點更詳細的資訊,google、baidu等都可以搜到,這裡不再贅述。
在10g版本中,完全檢查點也存在,其觸發時機:
1、發出命令:alter system checkpoint;
2、正常關閉資料庫。
有關檢查點(包括完全檢查點和增量檢查點)的檢視主要有兩個:
1、v$instance_recovery。其中主要的欄位包括:
·actual_redo_blks:最近一次檢查點所對應的要寫入的髒塊所對應的redo block到寫入了日誌檔案的最後一個redo block之間的redo blocks數量;
·target_redo_blks:所有檢查點條件中最小的條件所導致的在記憶體裡的redo blocks數量;
·log_file_size_redo_blks:其欄位值為90%*(SUM(log_size) – MAX(log_size))的計算結果。
·log_chkpt_timeout_redo_blks:由log_checkpoint_timeout引數所得到的redo blocks數量。
·target_mttr:由fast_start_mttr_target引數所計算出來的例項恢復所需要的時間。
·estimated_mttr:根據當前最後一次檢查點與日誌尾所差的redo blocks數量估算出來的例項恢復所需要的時間。
2、X$KCCCP。該記憶體表的命名含義為:
[K]ernel [C]ache [C]ontrolfile management [c]heckpoint [p]rogress。
其中主要的欄位包括:
·CPLRBA_SEQ:最後一次增量檢查點對應LRBA的第一部分--日誌序列號;
·CPLRBA_BNO:最後一次增量檢查點對應LRBA的第二部分--日誌塊數;
·CPLRBA_BOF:最後一次增量檢查點對應LRBA的第三部分--日誌偏移量;
·CPODR_SEQ:已寫入日誌檔案的最後一個RBA的第一部分--日誌序列號;
·CPODR_BNO:已寫入日誌檔案的最後一個RBA的第二部分--日誌塊數;
·CPODR_BOF:已寫入日誌檔案的最後一個RBA的第二部分--日誌偏移量;
·CPHBT:每三秒更新一次,並寫入控制檔案的heartbeat部分。表示這時的SCN號。
換句話所,當進行例項恢復時,需要應用的redo entry從CPLRBA_*到CPODR_*為止。
一、完全檢查點
SQL> select CPLRBA_SEQ as cur_seq#,
2 CPLRBA_BNO as cur_blk#,
3 CPODR_SEQ as stop_seq#,
4 CPODR_BNO as stop_blk#
5 from x$kcccp
6 where CPODR_SEQ>0;
CUR_SEQ# CUR_BLK# STOP_SEQ# STOP_BLK#
---------- ---------- ---------- ----------
37 97550 37 97778
SQL> select count(*) from v$bh where dirty='Y';
COUNT(*)
----------
63
SQL> alter system checkpoint;
系統已更改。
SQL> select count(*) from v$bh where dirty='Y';
COUNT(*)
----------
0
很明顯,發出該命令以後,記憶體裡所有髒塊都被寫入了資料檔案,於是記憶體裡就沒有髒塊了。
開啟跟蹤檔案,可以看到:
Beginning global checkpoint up to RBA [0x25.17df2.10], SCN: 662364
Completed checkpoint up to RBA [0x25.17df2.10], SCN: 662364
SQL> select to_number('25','xx') from dual;
TO_NUMBER('25','XX')
--------------------
37
SQL> select to_number('17df2','xxxxxxxx') from dual;
TO_NUMBER('17DF2','XXXXXXXX')
-----------------------------
97778
將其與x$kcccp的查詢結果比較一下,也可以看到,在完全檢查點中,截至寫入資料檔案的髒塊所對應的redo entry對應到STOP_SEQ#和STOP_BLK#所指明的redo entry為止。
二、增量檢查點
測試增量檢查點,主要通過v$instance_recovery檢視。
我們通常不會去修改log_checkpoint和fast_start引數,那些引數的預設值都設定的很大,所以還沒到那些引數所指定的上限的時候,90%這個條件就生效了。因為增量檢查點在任何一個條件滿足就會被觸發。
按照前面的公式:90%*(SUM(log_size) – MAX(log_size)),我們來計算日誌量是多大。
SQL> select 0.90*(sum(bytes)/1024/1024-max(bytes/1024/1024)) from v$log;
0.90*(SUM(BYTES)/1024/1024-MAX(BYTES/1024/1024))
------------------------------------------------
180
可以看到,只要日誌量達到180M,就會發生增量檢查點。然後來驗證:
SQL> select actual_redo_blks,
2 target_redo_blks,
3 LOG_FILE_SIZE_REDO_BLKS as "90%_blks",
4 LOG_CHKPT_TIMEOUT_REDO_BLKS as timeout_blks,
5 target_mttr,
6 estimated_mttr
7 from v$instance_recovery;
ACTUAL_REDO_BLKS TARGET_REDO_BLKS 90%_blks TIMEOUT_BLKS TARGET_MTTR ESTIMATED_MTTR
---------------- ---------------- ---------- ------------ ----------- --------------
89 368640 368640 0 27
這裡368640表示redo block的個數,至於每個redo block多大,則通常為500 bytes。也可以通過下面的sql來驗證:
SQL> select distinct lebsz as redo_block_size from x$kccle where lebsz>0;
REDO_BLOCK_SIZE
---------------
512
於是,我們得到:368640*512/1024/1024=180M。很明顯,與前面的公式吻合。
同時,我們看到當前記憶體裡的髒塊所對應的redo block有89個。而其他控制增量檢查點的引數都保持預設值:
SQL> show parameter log_checkpoint
NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
log_checkpoint_interval integer 0
log_checkpoint_timeout integer 1800
log_checkpoints_to_alert boolean TRUE
SQL> show parameter fast_start
NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
fast_start_io_target integer 0
fast_start_mttr_target integer 0
fast_start_parallel_rollback string LOW
假設當前所在的session為sess #1。然後再啟動一個session,假設其session為sess #2。發出大量的DML語句。
SQL> connect hr/hr
已連線。
SQL> create table test as select * from dba_objects;
表已建立。
回到sess #1,檢視v$instance_recovery:
SQL> select actual_redo_blks,
2 target_redo_blks,
3 LOG_FILE_SIZE_REDO_BLKS as "90%_blks",
4 LOG_CHKPT_TIMEOUT_REDO_BLKS as timeout_blks,
5 target_mttr,
6 estimated_mttr
7 from v$instance_recovery;
ACTUAL_REDO_BLKS TARGET_REDO_BLKS 90%_blks TIMEOUT_BLKS TARGET_MTTR ESTIMATED_MTTR
---------------- ---------------- ---------- ------------ ----------- --------------
308 368640 368640 0 22
可以看到,只產生了大約300多個redo block。於是回到sess #2,不斷的做insert+delete:
SQL> insert into test select * from test;
已建立50320行。
SQL> commit;
提交完成。
SQL> delete test;
已刪除100640行。
SQL> commit;
提交完成。
大概做3、4次左右,回到sess #1,檢視v$instance_recovery。
SQL> select actual_redo_blks,
2 target_redo_blks,
3 LOG_FILE_SIZE_REDO_BLKS as "90%_blks",
4 LOG_CHKPT_TIMEOUT_REDO_BLKS as timeout_blks,
5 target_mttr,
6 estimated_mttr
7 from v$instance_recovery;
ACTUAL_REDO_BLKS TARGET_REDO_BLKS 90%_blks TIMEOUT_BLKS TARGET_MTTR ESTIMATED_MTTR
---------------- ---------------- ---------- ------------ ----------- --------------
341604 368640 368640 0 105
這時記憶體裡的髒資料塊所對應的redo block已經接近上限了。於是再次回到sess #2裡做DML,結束以後回到sess #1檢視。
SQL> select actual_redo_blks,
2 target_redo_blks,
3 LOG_FILE_SIZE_REDO_BLKS as "90%_blks",
4 LOG_CHKPT_TIMEOUT_REDO_BLKS as timeout_blks,
5 target_mttr,
6 estimated_mttr
7 from v$instance_recovery;
ACTUAL_REDO_BLKS TARGET_REDO_BLKS 90%_blks TIMEOUT_BLKS TARGET_MTTR ESTIMATED_MTTR
---------------- ---------------- ---------- ------------ ----------- --------------
378157 368640 368640 0 184
已經超過上限,於是觸發增量檢查點。這時可以去檢視alert log:
Sun Nov 23 12:47:47 2008
Beginning log switch checkpoint up to RBA [0x26.2.10], SCN: 667801
Thread 1 advanced to log sequence 38
Current log# 6 seq# 38 mem# 0: C:\ORACLE\PRODUCT\10.2.0\ORADATA\ORCL\REDO06.LOG
Sun Nov 23 12:48:47 2008
Beginning log switch checkpoint up to RBA [0x27.2.10], SCN: 677714
Thread 1 advanced to log sequence 39
Current log# 4 seq# 39 mem# 0: C:\ORACLE\PRODUCT\10.2.0\ORADATA\ORCL\REDO04.LOG
很明顯,可以看到觸發了2次增量檢查點,第一次增量檢查點要寫到[0x26.2.10]為止,第二次要寫到[0x27.2.10]為止。同時這兩次增量檢查點都還沒有完成,因為在checkpoint queue上,截至到該RBA的redo entry所對應的髒塊還沒有被寫入資料檔案。增量檢查點只是通知DBWn寫到這個位置並不等DBWn寫完就返回了。這裡的26對應到十進位制就是:2*16+6=38,也就是寫到序列號為38為止。而27則對應到39號日誌檔案。
SQL> select CPLRBA_SEQ as cur_seq#,
2 CPLRBA_BNO as cur_blk#,
3 CPODR_SEQ as stop_seq#,
4 CPODR_BNO as stop_blk#
5 from x$kcccp
6 where CPODR_SEQ>0;
CUR_SEQ# CUR_BLK# STOP_SEQ# STOP_BLK#
---------- ---------- ---------- ----------
37 108095 39 85497
SQL> select group#,sequence#,status from v$log;
GROUP# SEQUENCE# STATUS
---------- ---------- ----------------
4 39 CURRENT
5 37 ACTIVE
6 38 ACTIVE
可以看到37、38這兩個日誌所對應的髒塊還沒有被寫入資料檔案,所以其狀態為active。
SQL> select actual_redo_blks,
2 target_redo_blks,
3 LOG_FILE_SIZE_REDO_BLKS as "90%_blks",
4 LOG_CHKPT_TIMEOUT_REDO_BLKS as timeout_blks,
5 target_mttr,
6 estimated_mttr
7 from v$instance_recovery;
ACTUAL_REDO_BLKS TARGET_REDO_BLKS 90%_blks TIMEOUT_BLKS TARGET_MTTR ESTIMATED_MTTR
---------------- ---------------- ---------- ------------ ----------- --------------
368599 368640 368640 0 161
同時也發現,記憶體裡的髒塊所對應的redo block個數從378157下降到了368599,也就是隻減少了很少的redo block,換句花說,這時DBWn程式只寫了很少的幾個髒塊。因為寫的髒塊個數只需要滿足不觸發增量檢查點即可,這裡的條件也就是記憶體裡的髒塊所對應的redo block不要超過368640即可。
然後再次的在sess #2裡做DML。然後回到sess #1。
SQL> select CPLRBA_SEQ as cur_seq#,
2 CPLRBA_BNO as cur_blk#,
3 CPODR_SEQ as stop_seq#,
4 CPODR_BNO as stop_blk#
5 from x$kcccp
6 where CPODR_SEQ>0;
CUR_SEQ# CUR_BLK# STOP_SEQ# STOP_BLK#
---------- ---------- ---------- ----------
38 22297 39 195257
可以看到發生變化了,checkpoint position從37號日誌向前推進到了38號日誌。也就是說,完成了一次檢查點。
馬上去看alert log,發現下面這一段:
Thread 1 advanced to log sequence 39
Current log# 4 seq# 39 mem# 0: C:\ORACLE\PRODUCT\10.2.0\ORADATA\ORCL\REDO04.LOG
Sun Nov 23 13:00:56 2008
Completed checkpoint up to RBA [0x26.2.10], SCN: 667801
Sun Nov 23 13:01:57 2008
Beginning log switch checkpoint up to RBA [0x28.2.10], SCN: 685552
Thread 1 advanced to log sequence 40
Current log# 5 seq# 40 mem# 0: C:\ORACLE\PRODUCT\10.2.0\ORADATA\ORCL\REDO05.LOG
很明顯,第一次增量檢查點結束了,也就是說,前面active的37號日誌檔案裡的redo entry所對應的髒塊已經被
寫入了資料檔案,其狀態肯定變為inactive。同時第二次增量檢查點還沒有結束,同時又啟動了第三次增量檢查點。
SQL> select group#,sequence#,status from v$log;
GROUP# SEQUENCE# STATUS
---------- ---------- ----------------
4 39 CURRENT
5 37 INACTIVE
6 38 ACTIVE
SQL> select CPLRBA_SEQ as cur_seq#,
2 CPLRBA_BNO as cur_blk#,
3 CPODR_SEQ as stop_seq#,
4 CPODR_BNO as stop_blk#
5 from x$kcccp
6 where CPODR_SEQ>0;
CUR_SEQ# CUR_BLK# STOP_SEQ# STOP_BLK#
---------- ---------- ---------- ----------
38 22297 39 195257
整個過程是很容易理解的。這裡可以很容易得出結論:通常所說的logfile switch 觸發檢查點,實際上就是觸發增量檢查點而不是完全檢查點,並標記要寫到哪個髒塊為止。同時不等DBWn寫完這些髒塊就返回。當DBWn寫完所標記的髒塊以後,該增量檢查點結束。
然後來修改log_checkpoint_timeout引數,從而調整增量檢查點的頻率。該參數列示髒資料塊留在記憶體裡的時間長度,一旦超過該時間,就會觸發增量檢查點,從而確定要寫到的redo entry,從而確定了要寫到的髒塊地址,然後觸發DBWn程式寫髒塊。將該引數設定為60秒。
SQL> alter system set log_checkpoint_timeout=60;
系統已更改。
SQL> select actual_redo_blks,
2 target_redo_blks,
3 LOG_FILE_SIZE_REDO_BLKS as "90%_blks",
4 LOG_CHKPT_TIMEOUT_REDO_BLKS as timeout_blks,
5 target_mttr,
6 estimated_mttr
7 from v$instance_recovery;
ACTUAL_REDO_BLKS TARGET_REDO_BLKS 90%_blks TIMEOUT_BLKS TARGET_MTTR ESTIMATED_MTTR
---------------- ---------------- ---------- ------------ ----------- --------------
6 40 368640 40 0 23
可以看到,修改為60秒以後,TARGET_REDO_BLKS為40,表示記憶體裡只能容納40個redo block所保護的髒資料塊。然後在sess #2裡進行DML以後,回到sess #1裡檢視相關檢視。
SQL> select actual_redo_blks,
2 target_redo_blks,
3 LOG_FILE_SIZE_REDO_BLKS as "90%_blks",
4 LOG_CHKPT_TIMEOUT_REDO_BLKS as timeout_blks,
5 target_mttr,
6 estimated_mttr
7 from v$instance_recovery;
ACTUAL_REDO_BLKS TARGET_REDO_BLKS 90%_blks TIMEOUT_BLKS TARGET_MTTR ESTIMATED_MTTR
---------------- ---------------- ---------- ------------ ----------- --------------
22791 22791 368640 22791 0 25
等待1分鐘左右,再次查詢該檢視,會發現其結果為:
SQL> select actual_redo_blks,
2 target_redo_blks,
3 LOG_FILE_SIZE_REDO_BLKS as "90%_blks",
4 LOG_CHKPT_TIMEOUT_REDO_BLKS as timeout_blks,
5 target_mttr,
6 estimated_mttr
7 from v$instance_recovery;
ACTUAL_REDO_BLKS TARGET_REDO_BLKS 90%_blks TIMEOUT_BLKS TARGET_MTTR ESTIMATED_MTTR
---------------- ---------------- ---------- ------------ ----------- --------------
73 75 368640 75 0 22
很明顯,1分鐘以後,大部分髒塊被增量檢查點觸發DBWn寫入資料檔案。
然後來測試fast_start_mttr_target引數。
SQL> alter system set fast_start_mttr_target=40;
系統已更改。
SQL> show parameter log_checkpoint
NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
log_checkpoint_interval integer 0
log_checkpoint_timeout integer 0
log_checkpoints_to_alert boolean TRUE
SQL> show parameter fast_start
NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
fast_start_io_target integer 0
fast_start_mttr_target integer 40
fast_start_parallel_rollback string LOW
設定完fast_start_mttr_target=40以後,立刻檢視相關檢視:
SQL> select actual_redo_blks,
2 target_redo_blks,
3 LOG_FILE_SIZE_REDO_BLKS as "90%_blks",
4 LOG_CHKPT_TIMEOUT_REDO_BLKS as timeout_blks,
5 target_mttr,
6 estimated_mttr
7 from v$instance_recovery;
ACTUAL_REDO_BLKS TARGET_REDO_BLKS 90%_blks TIMEOUT_BLKS TARGET_MTTR ESTIMATED_MTTR
---------------- ---------------- ---------- ------------ ----------- --------------
104 368640 368640 40 22
可以看到,TARGET_MTTR就是我們設定的40秒,而ESTIMATED_MTTR則表示由於當前記憶體裡髒塊很少,因此如果當前例項崩潰,則只需要22秒就能完成例項的恢復。
在sess #2裡進行DML以後,馬上到sess #1裡檢視相關檢視。
SQL> select actual_redo_blks,
2 target_redo_blks,
3 LOG_FILE_SIZE_REDO_BLKS as "90%_blks",
4 LOG_CHKPT_TIMEOUT_REDO_BLKS as timeout_blks,
5 target_mttr,
6 estimated_mttr
7 from v$instance_recovery;
ACTUAL_REDO_BLKS TARGET_REDO_BLKS 90%_blks TIMEOUT_BLKS TARGET_MTTR ESTIMATED_MTTR
---------------- ---------------- ---------- ------------ ----------- --------------
67141 368640 368640 40 42
可以看到這時sess #2產生了67141個redo block,這將觸發增量檢查點。然後我們間隔很短的時間,比如30秒以後再次查詢該檢視。
SQL> select actual_redo_blks,
2 target_redo_blks,
3 LOG_FILE_SIZE_REDO_BLKS as "90%_blks",
4 LOG_CHKPT_TIMEOUT_REDO_BLKS as timeout_blks,
5 target_mttr,
6 estimated_mttr
7 from v$instance_recovery;
ACTUAL_REDO_BLKS TARGET_REDO_BLKS 90%_blks TIMEOUT_BLKS TARGET_MTTR ESTIMATED_MTTR
---------------- ---------------- ---------- ------------ ----------- --------------
132 368640 368640 40 42
會發現,由於我們設定了40秒的例項恢復時間,因此馬上就完成了增量檢查點,減少了記憶體裡髒資料塊的個數。
oracle 8以前都是完全檢查點,每次觸發,則記錄當前資料庫SCN號,並將記憶體裡所有截至到該SCN號的髒資料塊都重新整理到資料檔案裡。從而同步資料檔案。
隨著記憶體越來越便宜,以及控制例項恢復的需要,完全檢查點已經不適合實際情況了。於是從oracle 8開始,oracle引入了增量檢查點,通過增量檢查點來減少例項恢復的時間。為此,oracle引入了checkpoint queue,按照資料塊第一次被修改的先後順序,將髒資料塊掛到該佇列上。同時還在該佇列上記錄了每個髒資料塊第一次被修改時產生的redo entry的地址,這叫LRBA。
增量檢查點的啟動時機由以下引數控制:
·fast_start_mttr_target:應用從CKPT position到最後一個redo entry之間所有redo entry所花的時間。也就是例項前滾所花費的時間。
·LOG_CHECKPOINT_INTERVAL:如果自從上一次檢查點啟動以來所累積的日誌塊個數達到該引數,則觸發增量檢查點,從而觸發DBWn寫髒塊。
·LOG_CHECKPOINT_TIMEOUT:兩次檢查點啟動的時間間隔。實際也就是控制髒塊在記憶體裡待多長時間的引數。
·90%*(SUM(log_size) – MAX(log_size)):如果產生的redo塊的量達到該值,則啟動增量檢查點。
只要滿足上面條件中的任何一個,就會啟動增量檢查點。增量檢查點一旦啟動,則會記錄當前CKPT SCN。
然後通知DBWn程式去寫checkpoint queue上所掛載的髒塊,至於寫到哪個髒塊為止,則不超過到當前CKPT SCN。
DBWn程式是批量寫髒塊的,髒塊個數不到一定程度,DBWn不會真的去寫。而每次寫多少個髒塊的個數則由一個隱藏引數控制。
每隔3秒鐘(這叫heartbeat,心跳),“增量檢查點”也還會啟動一次,只不過這時增量檢查點啟動只是檢視一下checkpoint queue,將該佇列上的第一個髒塊所對應的redo block的地址寫入控制檔案,也就是將CKPT Position寫入控制檔案,並不會觸發DBWn程式寫髒塊。所以是打引號的增量檢查點。
有關檢查點更詳細的資訊,google、baidu等都可以搜到,這裡不再贅述。
在10g版本中,完全檢查點也存在,其觸發時機:
1、發出命令:alter system checkpoint;
2、正常關閉資料庫。
有關檢查點(包括完全檢查點和增量檢查點)的檢視主要有兩個:
1、v$instance_recovery。其中主要的欄位包括:
·actual_redo_blks:最近一次檢查點所對應的要寫入的髒塊所對應的redo block到寫入了日誌檔案的最後一個redo block之間的redo blocks數量;
·target_redo_blks:所有檢查點條件中最小的條件所導致的在記憶體裡的redo blocks數量;
·log_file_size_redo_blks:其欄位值為90%*(SUM(log_size) – MAX(log_size))的計算結果。
·log_chkpt_timeout_redo_blks:由log_checkpoint_timeout引數所得到的redo blocks數量。
·target_mttr:由fast_start_mttr_target引數所計算出來的例項恢復所需要的時間。
·estimated_mttr:根據當前最後一次檢查點與日誌尾所差的redo blocks數量估算出來的例項恢復所需要的時間。
2、X$KCCCP。該記憶體表的命名含義為:
[K]ernel [C]ache [C]ontrolfile management [c]heckpoint [p]rogress。
其中主要的欄位包括:
·CPLRBA_SEQ:最後一次增量檢查點對應LRBA的第一部分--日誌序列號;
·CPLRBA_BNO:最後一次增量檢查點對應LRBA的第二部分--日誌塊數;
·CPLRBA_BOF:最後一次增量檢查點對應LRBA的第三部分--日誌偏移量;
·CPODR_SEQ:已寫入日誌檔案的最後一個RBA的第一部分--日誌序列號;
·CPODR_BNO:已寫入日誌檔案的最後一個RBA的第二部分--日誌塊數;
·CPODR_BOF:已寫入日誌檔案的最後一個RBA的第二部分--日誌偏移量;
·CPHBT:每三秒更新一次,並寫入控制檔案的heartbeat部分。表示這時的SCN號。
換句話所,當進行例項恢復時,需要應用的redo entry從CPLRBA_*到CPODR_*為止。
一、完全檢查點
SQL> select CPLRBA_SEQ as cur_seq#,
2 CPLRBA_BNO as cur_blk#,
3 CPODR_SEQ as stop_seq#,
4 CPODR_BNO as stop_blk#
5 from x$kcccp
6 where CPODR_SEQ>0;
CUR_SEQ# CUR_BLK# STOP_SEQ# STOP_BLK#
---------- ---------- ---------- ----------
37 97550 37 97778
SQL> select count(*) from v$bh where dirty='Y';
COUNT(*)
----------
63
SQL> alter system checkpoint;
系統已更改。
SQL> select count(*) from v$bh where dirty='Y';
COUNT(*)
----------
0
很明顯,發出該命令以後,記憶體裡所有髒塊都被寫入了資料檔案,於是記憶體裡就沒有髒塊了。
開啟跟蹤檔案,可以看到:
Beginning global checkpoint up to RBA [0x25.17df2.10], SCN: 662364
Completed checkpoint up to RBA [0x25.17df2.10], SCN: 662364
SQL> select to_number('25','xx') from dual;
TO_NUMBER('25','XX')
--------------------
37
SQL> select to_number('17df2','xxxxxxxx') from dual;
TO_NUMBER('17DF2','XXXXXXXX')
-----------------------------
97778
將其與x$kcccp的查詢結果比較一下,也可以看到,在完全檢查點中,截至寫入資料檔案的髒塊所對應的redo entry對應到STOP_SEQ#和STOP_BLK#所指明的redo entry為止。
二、增量檢查點
測試增量檢查點,主要通過v$instance_recovery檢視。
我們通常不會去修改log_checkpoint和fast_start引數,那些引數的預設值都設定的很大,所以還沒到那些引數所指定的上限的時候,90%這個條件就生效了。因為增量檢查點在任何一個條件滿足就會被觸發。
按照前面的公式:90%*(SUM(log_size) – MAX(log_size)),我們來計算日誌量是多大。
SQL> select 0.90*(sum(bytes)/1024/1024-max(bytes/1024/1024)) from v$log;
0.90*(SUM(BYTES)/1024/1024-MAX(BYTES/1024/1024))
------------------------------------------------
180
可以看到,只要日誌量達到180M,就會發生增量檢查點。然後來驗證:
SQL> select actual_redo_blks,
2 target_redo_blks,
3 LOG_FILE_SIZE_REDO_BLKS as "90%_blks",
4 LOG_CHKPT_TIMEOUT_REDO_BLKS as timeout_blks,
5 target_mttr,
6 estimated_mttr
7 from v$instance_recovery;
ACTUAL_REDO_BLKS TARGET_REDO_BLKS 90%_blks TIMEOUT_BLKS TARGET_MTTR ESTIMATED_MTTR
---------------- ---------------- ---------- ------------ ----------- --------------
89 368640 368640 0 27
這裡368640表示redo block的個數,至於每個redo block多大,則通常為500 bytes。也可以通過下面的sql來驗證:
SQL> select distinct lebsz as redo_block_size from x$kccle where lebsz>0;
REDO_BLOCK_SIZE
---------------
512
於是,我們得到:368640*512/1024/1024=180M。很明顯,與前面的公式吻合。
同時,我們看到當前記憶體裡的髒塊所對應的redo block有89個。而其他控制增量檢查點的引數都保持預設值:
SQL> show parameter log_checkpoint
NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
log_checkpoint_interval integer 0
log_checkpoint_timeout integer 1800
log_checkpoints_to_alert boolean TRUE
SQL> show parameter fast_start
NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
fast_start_io_target integer 0
fast_start_mttr_target integer 0
fast_start_parallel_rollback string LOW
假設當前所在的session為sess #1。然後再啟動一個session,假設其session為sess #2。發出大量的DML語句。
SQL> connect hr/hr
已連線。
SQL> create table test as select * from dba_objects;
表已建立。
回到sess #1,檢視v$instance_recovery:
SQL> select actual_redo_blks,
2 target_redo_blks,
3 LOG_FILE_SIZE_REDO_BLKS as "90%_blks",
4 LOG_CHKPT_TIMEOUT_REDO_BLKS as timeout_blks,
5 target_mttr,
6 estimated_mttr
7 from v$instance_recovery;
ACTUAL_REDO_BLKS TARGET_REDO_BLKS 90%_blks TIMEOUT_BLKS TARGET_MTTR ESTIMATED_MTTR
---------------- ---------------- ---------- ------------ ----------- --------------
308 368640 368640 0 22
可以看到,只產生了大約300多個redo block。於是回到sess #2,不斷的做insert+delete:
SQL> insert into test select * from test;
已建立50320行。
SQL> commit;
提交完成。
SQL> delete test;
已刪除100640行。
SQL> commit;
提交完成。
大概做3、4次左右,回到sess #1,檢視v$instance_recovery。
SQL> select actual_redo_blks,
2 target_redo_blks,
3 LOG_FILE_SIZE_REDO_BLKS as "90%_blks",
4 LOG_CHKPT_TIMEOUT_REDO_BLKS as timeout_blks,
5 target_mttr,
6 estimated_mttr
7 from v$instance_recovery;
ACTUAL_REDO_BLKS TARGET_REDO_BLKS 90%_blks TIMEOUT_BLKS TARGET_MTTR ESTIMATED_MTTR
---------------- ---------------- ---------- ------------ ----------- --------------
341604 368640 368640 0 105
這時記憶體裡的髒資料塊所對應的redo block已經接近上限了。於是再次回到sess #2裡做DML,結束以後回到sess #1檢視。
SQL> select actual_redo_blks,
2 target_redo_blks,
3 LOG_FILE_SIZE_REDO_BLKS as "90%_blks",
4 LOG_CHKPT_TIMEOUT_REDO_BLKS as timeout_blks,
5 target_mttr,
6 estimated_mttr
7 from v$instance_recovery;
ACTUAL_REDO_BLKS TARGET_REDO_BLKS 90%_blks TIMEOUT_BLKS TARGET_MTTR ESTIMATED_MTTR
---------------- ---------------- ---------- ------------ ----------- --------------
378157 368640 368640 0 184
已經超過上限,於是觸發增量檢查點。這時可以去檢視alert log:
Sun Nov 23 12:47:47 2008
Beginning log switch checkpoint up to RBA [0x26.2.10], SCN: 667801
Thread 1 advanced to log sequence 38
Current log# 6 seq# 38 mem# 0: C:\ORACLE\PRODUCT\10.2.0\ORADATA\ORCL\REDO06.LOG
Sun Nov 23 12:48:47 2008
Beginning log switch checkpoint up to RBA [0x27.2.10], SCN: 677714
Thread 1 advanced to log sequence 39
Current log# 4 seq# 39 mem# 0: C:\ORACLE\PRODUCT\10.2.0\ORADATA\ORCL\REDO04.LOG
很明顯,可以看到觸發了2次增量檢查點,第一次增量檢查點要寫到[0x26.2.10]為止,第二次要寫到[0x27.2.10]為止。同時這兩次增量檢查點都還沒有完成,因為在checkpoint queue上,截至到該RBA的redo entry所對應的髒塊還沒有被寫入資料檔案。增量檢查點只是通知DBWn寫到這個位置並不等DBWn寫完就返回了。這裡的26對應到十進位制就是:2*16+6=38,也就是寫到序列號為38為止。而27則對應到39號日誌檔案。
SQL> select CPLRBA_SEQ as cur_seq#,
2 CPLRBA_BNO as cur_blk#,
3 CPODR_SEQ as stop_seq#,
4 CPODR_BNO as stop_blk#
5 from x$kcccp
6 where CPODR_SEQ>0;
CUR_SEQ# CUR_BLK# STOP_SEQ# STOP_BLK#
---------- ---------- ---------- ----------
37 108095 39 85497
SQL> select group#,sequence#,status from v$log;
GROUP# SEQUENCE# STATUS
---------- ---------- ----------------
4 39 CURRENT
5 37 ACTIVE
6 38 ACTIVE
可以看到37、38這兩個日誌所對應的髒塊還沒有被寫入資料檔案,所以其狀態為active。
SQL> select actual_redo_blks,
2 target_redo_blks,
3 LOG_FILE_SIZE_REDO_BLKS as "90%_blks",
4 LOG_CHKPT_TIMEOUT_REDO_BLKS as timeout_blks,
5 target_mttr,
6 estimated_mttr
7 from v$instance_recovery;
ACTUAL_REDO_BLKS TARGET_REDO_BLKS 90%_blks TIMEOUT_BLKS TARGET_MTTR ESTIMATED_MTTR
---------------- ---------------- ---------- ------------ ----------- --------------
368599 368640 368640 0 161
同時也發現,記憶體裡的髒塊所對應的redo block個數從378157下降到了368599,也就是隻減少了很少的redo block,換句花說,這時DBWn程式只寫了很少的幾個髒塊。因為寫的髒塊個數只需要滿足不觸發增量檢查點即可,這裡的條件也就是記憶體裡的髒塊所對應的redo block不要超過368640即可。
然後再次的在sess #2裡做DML。然後回到sess #1。
SQL> select CPLRBA_SEQ as cur_seq#,
2 CPLRBA_BNO as cur_blk#,
3 CPODR_SEQ as stop_seq#,
4 CPODR_BNO as stop_blk#
5 from x$kcccp
6 where CPODR_SEQ>0;
CUR_SEQ# CUR_BLK# STOP_SEQ# STOP_BLK#
---------- ---------- ---------- ----------
38 22297 39 195257
可以看到發生變化了,checkpoint position從37號日誌向前推進到了38號日誌。也就是說,完成了一次檢查點。
馬上去看alert log,發現下面這一段:
Thread 1 advanced to log sequence 39
Current log# 4 seq# 39 mem# 0: C:\ORACLE\PRODUCT\10.2.0\ORADATA\ORCL\REDO04.LOG
Sun Nov 23 13:00:56 2008
Completed checkpoint up to RBA [0x26.2.10], SCN: 667801
Sun Nov 23 13:01:57 2008
Beginning log switch checkpoint up to RBA [0x28.2.10], SCN: 685552
Thread 1 advanced to log sequence 40
Current log# 5 seq# 40 mem# 0: C:\ORACLE\PRODUCT\10.2.0\ORADATA\ORCL\REDO05.LOG
很明顯,第一次增量檢查點結束了,也就是說,前面active的37號日誌檔案裡的redo entry所對應的髒塊已經被
寫入了資料檔案,其狀態肯定變為inactive。同時第二次增量檢查點還沒有結束,同時又啟動了第三次增量檢查點。
SQL> select group#,sequence#,status from v$log;
GROUP# SEQUENCE# STATUS
---------- ---------- ----------------
4 39 CURRENT
5 37 INACTIVE
6 38 ACTIVE
SQL> select CPLRBA_SEQ as cur_seq#,
2 CPLRBA_BNO as cur_blk#,
3 CPODR_SEQ as stop_seq#,
4 CPODR_BNO as stop_blk#
5 from x$kcccp
6 where CPODR_SEQ>0;
CUR_SEQ# CUR_BLK# STOP_SEQ# STOP_BLK#
---------- ---------- ---------- ----------
38 22297 39 195257
整個過程是很容易理解的。這裡可以很容易得出結論:通常所說的logfile switch 觸發檢查點,實際上就是觸發增量檢查點而不是完全檢查點,並標記要寫到哪個髒塊為止。同時不等DBWn寫完這些髒塊就返回。當DBWn寫完所標記的髒塊以後,該增量檢查點結束。
然後來修改log_checkpoint_timeout引數,從而調整增量檢查點的頻率。該參數列示髒資料塊留在記憶體裡的時間長度,一旦超過該時間,就會觸發增量檢查點,從而確定要寫到的redo entry,從而確定了要寫到的髒塊地址,然後觸發DBWn程式寫髒塊。將該引數設定為60秒。
SQL> alter system set log_checkpoint_timeout=60;
系統已更改。
SQL> select actual_redo_blks,
2 target_redo_blks,
3 LOG_FILE_SIZE_REDO_BLKS as "90%_blks",
4 LOG_CHKPT_TIMEOUT_REDO_BLKS as timeout_blks,
5 target_mttr,
6 estimated_mttr
7 from v$instance_recovery;
ACTUAL_REDO_BLKS TARGET_REDO_BLKS 90%_blks TIMEOUT_BLKS TARGET_MTTR ESTIMATED_MTTR
---------------- ---------------- ---------- ------------ ----------- --------------
6 40 368640 40 0 23
可以看到,修改為60秒以後,TARGET_REDO_BLKS為40,表示記憶體裡只能容納40個redo block所保護的髒資料塊。然後在sess #2裡進行DML以後,回到sess #1裡檢視相關檢視。
SQL> select actual_redo_blks,
2 target_redo_blks,
3 LOG_FILE_SIZE_REDO_BLKS as "90%_blks",
4 LOG_CHKPT_TIMEOUT_REDO_BLKS as timeout_blks,
5 target_mttr,
6 estimated_mttr
7 from v$instance_recovery;
ACTUAL_REDO_BLKS TARGET_REDO_BLKS 90%_blks TIMEOUT_BLKS TARGET_MTTR ESTIMATED_MTTR
---------------- ---------------- ---------- ------------ ----------- --------------
22791 22791 368640 22791 0 25
等待1分鐘左右,再次查詢該檢視,會發現其結果為:
SQL> select actual_redo_blks,
2 target_redo_blks,
3 LOG_FILE_SIZE_REDO_BLKS as "90%_blks",
4 LOG_CHKPT_TIMEOUT_REDO_BLKS as timeout_blks,
5 target_mttr,
6 estimated_mttr
7 from v$instance_recovery;
ACTUAL_REDO_BLKS TARGET_REDO_BLKS 90%_blks TIMEOUT_BLKS TARGET_MTTR ESTIMATED_MTTR
---------------- ---------------- ---------- ------------ ----------- --------------
73 75 368640 75 0 22
很明顯,1分鐘以後,大部分髒塊被增量檢查點觸發DBWn寫入資料檔案。
然後來測試fast_start_mttr_target引數。
SQL> alter system set fast_start_mttr_target=40;
系統已更改。
SQL> show parameter log_checkpoint
NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
log_checkpoint_interval integer 0
log_checkpoint_timeout integer 0
log_checkpoints_to_alert boolean TRUE
SQL> show parameter fast_start
NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
fast_start_io_target integer 0
fast_start_mttr_target integer 40
fast_start_parallel_rollback string LOW
設定完fast_start_mttr_target=40以後,立刻檢視相關檢視:
SQL> select actual_redo_blks,
2 target_redo_blks,
3 LOG_FILE_SIZE_REDO_BLKS as "90%_blks",
4 LOG_CHKPT_TIMEOUT_REDO_BLKS as timeout_blks,
5 target_mttr,
6 estimated_mttr
7 from v$instance_recovery;
ACTUAL_REDO_BLKS TARGET_REDO_BLKS 90%_blks TIMEOUT_BLKS TARGET_MTTR ESTIMATED_MTTR
---------------- ---------------- ---------- ------------ ----------- --------------
104 368640 368640 40 22
可以看到,TARGET_MTTR就是我們設定的40秒,而ESTIMATED_MTTR則表示由於當前記憶體裡髒塊很少,因此如果當前例項崩潰,則只需要22秒就能完成例項的恢復。
在sess #2裡進行DML以後,馬上到sess #1裡檢視相關檢視。
SQL> select actual_redo_blks,
2 target_redo_blks,
3 LOG_FILE_SIZE_REDO_BLKS as "90%_blks",
4 LOG_CHKPT_TIMEOUT_REDO_BLKS as timeout_blks,
5 target_mttr,
6 estimated_mttr
7 from v$instance_recovery;
ACTUAL_REDO_BLKS TARGET_REDO_BLKS 90%_blks TIMEOUT_BLKS TARGET_MTTR ESTIMATED_MTTR
---------------- ---------------- ---------- ------------ ----------- --------------
67141 368640 368640 40 42
可以看到這時sess #2產生了67141個redo block,這將觸發增量檢查點。然後我們間隔很短的時間,比如30秒以後再次查詢該檢視。
SQL> select actual_redo_blks,
2 target_redo_blks,
3 LOG_FILE_SIZE_REDO_BLKS as "90%_blks",
4 LOG_CHKPT_TIMEOUT_REDO_BLKS as timeout_blks,
5 target_mttr,
6 estimated_mttr
7 from v$instance_recovery;
ACTUAL_REDO_BLKS TARGET_REDO_BLKS 90%_blks TIMEOUT_BLKS TARGET_MTTR ESTIMATED_MTTR
---------------- ---------------- ---------- ------------ ----------- --------------
132 368640 368640 40 42
會發現,由於我們設定了40秒的例項恢復時間,因此馬上就完成了增量檢查點,減少了記憶體裡髒資料塊的個數。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/9842/viewspace-501556/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Oracle完全檢查點和增量檢查點詳解Oracle
- 【TUNE_ORACLE】Oracle檢查點(二)檢查點效能Oracle
- PTA 檢查密碼 (15分)密碼
- Eventloop的祕密OOP
- Oracle 檢查點涉及的SCNOracle
- 【TUNE_ORACLE】Oracle檢查點(一)檢查點(Checkpoint)概念介紹Oracle
- SQLServer的檢查點、redo和undoSQLServer
- Science:對爬行動物和兩棲動物衰老和長壽的最大規模揭示了衰老的祕密
- 網頁文字的祕密網頁
- ZooKeeper 會話的祕密會話
- 隱藏在水印的祕密
- 關於NSUserDefaults的祕密
- 隨機森林的祕密隨機森林
- 【TUNE_ORACLE】Oracle檢查點(五)建立並利用Statspack定位檢查點故障Oracle
- Linux 生成複雜密碼並且檢查密碼強度Linux密碼
- 20190110-生成密碼以及簡易密碼強度檢查密碼
- PAT-B 1081 檢查密碼【模擬】密碼
- Redis小祕密Redis
- “==”、“equals()”、“hashcode()”之間的祕密
- 挖掘Chrome Console的小祕密Chrome
- TCP/IP家族的小祕密TCP
- 《流量的祕密》閱讀分析
- Linux基礎命令---檢查密碼檔案pwckLinux密碼
- 【TUNE_ORACLE】Oracle檢查點(三)增量檢查點四個關鍵引數介紹Oracle
- 如何在 Linux 生成複雜密碼並且檢查密碼強度Linux密碼
- Python輕鬆檢視微信撤回訊息,祕密無處可藏Python
- 密碼學專家揭示Telegram Passport中的安全問題密碼學Passport
- MySQL什麼是InnoDB檢查點?MySql
- PG檢查點刷寫髒頁
- TensorFlow——Checkpoint為模型新增檢查點模型
- postgresql10.3 檢查點調整SQL
- postgresql 檢查點調整 checkpoint 轉SQL
- WebGL座標系的小祕密Web
- JavaScript原型與繼承的祕密JavaScript原型繼承
- Flutter和原生之間的祕密Flutter
- OpenJDK的“CRaC檢查點協調恢復” - foojayJDK
- VCS中檢查Cluster中節點的狀態
- 行業看點|一文為你揭祕量子密碼行業密碼