checkpoint触发的条件
1)手工触发
当手工发出alter system checkpoint 等命令时触发(实际上alter system flush buffer chache 也会触发)
一般我们在进行重大操作的时,可以手工触发检查点,然后多切换几次redo logfile,再去shutdown.这样可以保证数据库的脏块尽可能的都完全写入到disk中,同时也能保证实例open时,能尽可能快的打开。
2) redo switch
从8i之后版本,redo切换已经视为增量检查点了
oracle是日志写优先原则,在进行日志切换时,即将写next redo时,lgwr进程会post信息给dbwr进程,去写buffer cache中的脏块。如果归档的话,同时还会post给arch进程。
3)对象检查点
这主要是指DDL操作,比如我们drop 某个表或truncate某个表。当ddl发生后,会触发dbwn进程将buffer cache 中该对象相关的所有脏块都写入到disk中。我们知道dbwn进行写脏块,是通过扫描dbwn的LRU链表,如果我们的
cache buffer很大,那么这个扫描链表的操作会很长。
案例drop user 时间很长,减少buffer 的大小。
通常有2个等待事件:
enq:RO -fast object reuse
enq:KO-fast object checkpoint
4)并行查询触发检查点
出现direct path read.直接路劲读是绕过buffer cache的。当绕过buffer cache后,直接从文件中读取某个块,而可能改块正好在buffer cache中北修改,这个时候可能出现数据库块版本不一致的情况。为了防止这样的情况,所以oracle
在这是引入检查点,就是object级别的检查点,去保障数据块版本的一致性。
5)3s check机制
1. full chekcpoint的一些基础知识
我们汉子道检查点其实是一个数据库事件,它存在的目的其实有2个:
1)建立数据的一致性
2)保证数据库尽可能快的恢复
full chekcpoint检查点的分类以及检查点的触发机制:
主要有如下几种触发机制:
--手工触发
--日志切换
--object 检查点
--并行查询
--3s check机制
检查点触发后会post信息给dbwn进程去写dirty block.那么dbwn进程写脏块的条件有哪些?
1)oracle shadow 进程扫描cache buffer链表超过25%,会触发,同时如果扫描达到40%后,仍然没有空闲buffer可用,
那么会post信息给dbwn去将buffer cache中的脏块写入到disk中。这2个机制是通过如下参数来控制的:
SQL> show parameter dirty
NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
_db_large_dirty_queue integer 25
SQL> show parameter db_block_max
NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
_db_block_max_cr_dba integer 6
_db_block_max_scan_pct integer 40
这里dbwn进程写脏块的顺序是怎么样的?根据chekcpoint queue来进行的,根据checkpoint queue将脏块按照seq进行顺序的写入到disk中。
SQL> alter system checkpoint;
System altered.
SQL> select file#,checkpoint_change# from v$datafile order by 1;
FILE# CHECKPOINT_CHANGE#
---------- ------------------
1 7867966
2 7867966
4 7867966
5 7867966
6 7867966
SQL> select file#,checkpoint_change# from v$datafile_header order by 1;
FILE# CHECKPOINT_CHANGE#
---------- ------------------
1 7867966
2 7867966
4 7867966
5 7867966
6 7867966
SQL> select rtckp_rba_seq||'.'||rtckp_rba_bno||'.'|| rtckp_rba_bof "RBA",rtckp_scn from x$kccrt;
RBA RTCKP_SCN
---------------------------------------- ----------------
323.2661.16 7867966
查看alert此时的日志
Beginning global checkpoint up to RBA [0x143.a65.10], SCN: 7867966
Completed checkpoint up to RBA [0x143.a65.10], SCN: 7867966
0x143.a65.10转换成十进制是323.2661.16
BBED> set file 5 block 1
FILE# 5
BLOCK# 1
BBED> p kcvfhckp
struct kcvfhckp, 36 bytes @484
struct kcvcpscn, 8 bytes @484
ub4 kscnbas @484 0x00780e3e
ub2 kscnwrp @488 0x0000
ub4 kcvcptim @492 0x3b33782c
ub2 kcvcpthr @496 0x0001
union u, 12 bytes @500
struct kcvcprba, 12 bytes @500
ub4 kcrbaseq @500 0x00000143
ub4 kcrbabno @504 0x00000a65
ub2 kcrbabof @508 0x0010
ub1 kcvcpetb[0] @512 0x02
ub1 kcvcpetb[1] @513 0x00
ub1 kcvcpetb[2] @514 0x00
ub1 kcvcpetb[3] @515 0x00
ub1 kcvcpetb[4] @516 0x00
ub1 kcvcpetb[5] @517 0x00
ub1 kcvcpetb[6] @518 0x00
ub1 kcvcpetb[7] @519 0x00
---------------
占用12个字节
struct kcvcprba, 12 bytes @500
ub4 kcrbaseq @500 0x00000143 ------redo的seq的值
ub4 kcrbabno @504 0x00000a65
ub2 kcrbabof @508 0x0010
1)什么是增量检查点
我们知道oracle引入检查点机制的目的,是尽可能的降低实例恢复的时间,然后由于以前的版本只有full checkpoint,而每次触发full checkpoint都必须让dbwn进程将
cache buffer的所有脏块写入到disk中。对于一个大型OLTP系统而言,将所有脏块写入到disk中,会产生巨大的IO消耗,而且一旦此时数据库crash,那么实例恢复的时间会
相当的漫长。
故oracle引入增量检查点,这样让dbwn写脏块的频率变的更高一些,不仅可以缓解io压力,同时也能降低实例恢复的时间。oracle8i开始引入增量检查点。
2) 增量检查点相关的参数
log_checkpoint_interval 设定两次checkpoint之间重做日志块数量,当重做日志块数量达到设定值的时候将触发checkpoint.
log_checkpoint_timeout 设定两次checkpoint之间的间隔时间,当超时增量checkpoint将被触发。 ORACLE建议不用这个参数来控制,因为事务大小不是按时间等量分布的。单位是秒。
fast_start_io_target 因为log_checkpoint_interval主要看的是重做日志块的数量,并不能反映buffer cache中脏数据块的修改,因此oracle又引入了这个参数来实现当脏块达到一定数量
的时候触发checkpoint,不过此参数实际上控制的是恢复时所需IO的数量。
从9i,oracle引入了新的参数来代替上面的几个参数:
fast_start_mttr_target
关于该参数,一旦你设置之后,上面的几个参数的值就是通过这个参数来计算的。
SQL> select tt.TARGET_MTTR,tt.ESTIMATED_MTTR,tt.CKPT_BLOCK_WRITES,tt.CKPT_BLOCK_WRITES from v$instance_recovery tt ;
TARGET_MTTR ESTIMATED_MTTR CKPT_BLOCK_WRITES CKPT_BLOCK_WRITES
----------- -------------- ----------------- -----------------
0 7 1300 1300
从10g开始,oracle引入了增量检查点的自动调节机制:
SQL> show parameter checkpoint
NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
_disable_incremental_checkpoints boolean FALSE --决定是否启动增量检查点。
_disable_selftune_checkpointing boolean FALSE 决定是否启动增量检查点自动调节。
_gc_global_checkpoint_scn boolean TRUE
_kdli_checkpoint_flush boolean FALSE
_log_checkpoint_recovery_check integer 0
_selftune_checkpoint_write_pct integer 3 是一个百分比
_selftune_checkpointing_lag integer 300 默认值300s
log_checkpoint_interval integer 0
log_checkpoint_timeout integer 1800
log_checkpoints_to_alert boolean TRUE
3)增量检查点的实质
增量检查点不会更新datafile header,仅仅是更新controlfile。记住redo switch也是会触发增量检查点的。但是redo switch所触发增量检查点,并不是真正的增量检查点,
因为它会更新controlfile和datafile header。
通过实验观察一下:
++++++++++session1
SQL> col "RBA" for a30;
SQL> select rtckp_rba_seq||'.'||rtckp_rba_bno||'.'|| rtckp_rba_bof "RBA",rtckp_scn from x$kccrt;
RBA RTCKP_SCN
------------------------------ ----------------
325.2.16 7931250
SQL> oradebug setmypid
Statement processed.
SQL> alter session set events 'immediate trace name controlf level 3';
Session altered.
SQL> oradebug tracefile_name
/u01/app/oracle/diag/rdbms/orcl/orcl/trace/orcl_ora_12817.trc
此时观察一个datafie header 的checkpoint信息:
BBED> p kcvfhckp
struct kcvfhckp, 36 bytes @484
struct kcvcpscn, 8 bytes @484
ub4 kscnbas @484 0x00790572
ub2 kscnwrp @488 0x0000
ub4 kcvcptim @492 0x3b3476a5
ub2 kcvcpthr @496 0x0001
union u, 12 bytes @500
struct kcvcprba, 12 bytes @500
ub4 kcrbaseq @500 0x00000145
ub4 kcrbabno @504 0x00000002
ub2 kcrbabof @508 0x0010
ub1 kcvcpetb[0] @512 0x02
ub1 kcvcpetb[1] @513 0x00
ub1 kcvcpetb[2] @514 0x00
ub1 kcvcpetb[3] @515 0x00
ub1 kcvcpetb[4] @516 0x00
ub1 kcvcpetb[5] @517 0x00
ub1 kcvcpetb[6] @518 0x00
ub1 kcvcpetb[7] @519 0x00
++++++++session2
进行大量的dml操作
SQL> delete from tt where rownum<200;
199 rows deleted.
SQL> commit;
Commit complete.
SQL> delete from tt where rownum<10000;
9999 rows deleted.
SQL> commit;
Commit complete.
SQL> insert into tt values(22);
1 row created.
SQL> commit;
Commit complete.
----------session3
SQL> oradebug setmypid
Statement processed.
SQL> alter session set events 'immediate trace name controlf level 3';
Session altered.
SQL> oradebug tracefile_name
/u01/app/oracle/diag/rdbms/orcl/orcl/trace/orcl_ora_12893.trc
此时再次观察datafile checkpint信息:
BBED> p kcvfhckp
struct kcvfhckp, 36 bytes @484
struct kcvcpscn, 8 bytes @484
ub4 kscnbas @484 0x00790572
ub2 kscnwrp @488 0x0000
ub4 kcvcptim @492 0x3b3476a5
ub2 kcvcpthr @496 0x0001
union u, 12 bytes @500
struct kcvcprba, 12 bytes @500
ub4 kcrbaseq @500 0x00000145
ub4 kcrbabno @504 0x00000002
ub2 kcrbabof @508 0x0010
ub1 kcvcpetb[0] @512 0x02
ub1 kcvcpetb[1] @513 0x00
ub1 kcvcpetb[2] @514 0x00
ub1 kcvcpetb[3] @515 0x00
ub1 kcvcpetb[4] @516 0x00
ub1 kcvcpetb[5] @517 0x00
ub1 kcvcpetb[6] @518 0x00
ub1 kcvcpetb[7] @519 0x00
之前的:
DATA FILE #5:
name #5: /u01/app/oracle/oradata/orcl/tbs_unvdata01.dbf
creation size=0 block size=8192 status=0xe head=5 tail=5 dup=1
tablespace 6, index=4 krfil=5 prev_file=0
unrecoverable scn: 0x0000.00000000 01/01/1988 00:00:00
Checkpoint cnt:187 scn: 0x0000.00790572 11/27/2018 10:59:49
Stop scn: 0xffff.ffffffff 11/22/2018 10:03:22
Creation Checkpointed at scn: 0x0000.004f62b1 10/16/2018 17:49:00
thread:0 rba:(0x0.0.0)
之后的:
DATA FILE #5:
name #5: /u01/app/oracle/oradata/orcl/tbs_unvdata01.dbf
creation size=0 block size=8192 status=0xe head=5 tail=5 dup=1
tablespace 6, index=4 krfil=5 prev_file=0
unrecoverable scn: 0x0000.00000000 01/01/1988 00:00:00
Checkpoint cnt:187 scn: 0x0000.00790572 11/27/2018 10:59:49
Stop scn: 0xffff.ffffffff 11/22/2018 10:03:22
Creation Checkpointed at scn: 0x0000.004f62b1 10/16/2018 17:49:00
thread:0 rba:(0x0.0.0)
orcl_ora_12817.trc
***************************************************************************
CHECKPOINT PROGRESS RECORDS
***************************************************************************
(size = 8180, compat size = 8180, section max = 11, section in-use = 0,
last-recid= 0, old-recno = 0, last-recno = 0)
(extent = 1, blkno = 2, numrecs = 11)
THREAD #1 - status:0x2 flags:0x0 dirty:50
low cache rba:(0x145.1051.0) on disk rba:(0x145.10c4.0)
on disk scn: 0x0000.00790b6e 11/27/2018 11:22:53
resetlogs scn: 0x0000.000e2006 09/14/2018 11:30:48
heartbeat: 993285236 mount id: 1521006257
orcl_ora_12893.trc
***************************************************************************
CHECKPOINT PROGRESS RECORDS
***************************************************************************
(size = 8180, compat size = 8180, section max = 11, section in-use = 0,
last-recid= 0, old-recno = 0, last-recno = 0)
(extent = 1, blkno = 2, numrecs = 11)
THREAD #1 - status:0x2 flags:0x0 dirty:213
low cache rba:(0x145.10c4.0) on disk rba:(0x145.25bd.0)
on disk scn: 0x0000.00790c4c 11/27/2018 11:27:53
resetlogs scn: 0x0000.000e2006 09/14/2018 11:30:48
heartbeat: 993285346 mount id: 1521006257
从上面可以得出一下结论:
1)增量检查点仅仅更新controlfile,不会更新datafile header中的checkpoint的信息。
2)增量检查点会仅仅是controlfile中的checkpoint progress records记录中的如下信息:
low cache rba ,on disk rba ,on disk scn不会去更新controlfile中datafile对应的checkpoint scn等信息。
alter system switch logfile;
更新了checkpoint rba信息,同时datafile header的checkpoint scn信息也更新了。
实际上,检查点队列就是一个列表,而这个列表上包含一系列的buffer cache中的脏块,当然这些脏块的顺序是最早被修改的脏块放在前面,稍后修改的脏块在后面,
总之是根据time来排序的。
checkpoint queue是一个列表,每个checkpointqueue的一个位置我们称职为postion,当然这个postion就是通过rba来表示的。所以你可以理解为:
checkpoint queue就是一些脏块对应的buffer header列表,每个buffer header里面还包含了rba信息,只是这些rba是有一定顺序的。
每个rba都对应buffer cache中的一个脏块,而脏块这里也是分时间前后的,所以对应的checkpoint queue 上的checkpoint rba也是分先后的。
1)这里补充一点,dbwn进程要写脏块,那么久需要扫描LRU链表,在扫描之前需要先获得 cache buffer lru chains这个latch。
还有,dbwn进行在修改buffer cache中的数据之前,需要获得一个free buffer。cache buffer是被划分成多个buffer pool,然后,每个buffer pool里面的free buffer 是通过hash bucket
来管理的。当然,bucket的个数,是通过oracle隐含参数来控制:
SQL> show parameter db_block_hash
NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
_db_block_hash_buckets integer 65536
_db_block_hash_latches integer 2048
2) buffer header dump
SQL> oradebug setmypid
Statement processed.
SQL> alter session set events ' immediate trace name buffers level 1';
Session altered.
SQL> oradebug close_trace
Statement processed.
SQL> oradebug tracefile_name
/u01/app/oracle/diag/rdbms/orcl/orcl/trace/orcl_ora_14141.trc
Dump of buffer cache at level 1 for tsn=2147483647 rdba=0
BH (0x647ea7f0) file#: 2 rdba: 0x00813c80 (2/81024) class: 8 ba: 0x6461c000
set: 20 pool: 3 bsz: 8192 bsi: 0 sflg: 1 pwc: 0,0
dbwrid: 0 obj: 6592 objn: 6592 tsn: 1 afn: 2 hint: f
hash: [0x710f89b0,0x710f89b0] lru: [0x67bf1420,0x6d3e33e0]
lru-flags: hot_buffer
ckptq: [NULL] fileq: [NULL] objq: [0x6b3e2b80,0x612d6988] objaq: [0x6afe6748,0x612d6978]
st: XCURRENT md: NULL fpin: 'ktspfwh10: ktspscan_bmb' tch: 0
flags: block_written_once redo_since_read
LRBA: [0x0.0.0] LSCN: [0x0.0] HSCN: [0xffff.ffffffff] HSUB: [3]
BH (0x6cfd7e90) file#: 2 rdba: 0x00821a9c (2/137884) class: 1 ba: 0x6cc34000
set: 17 pool: 3 bsz: 8192 bsi: 0 sflg: 1 pwc: 0,0
dbwrid: 0 obj: 87239 objn: 87239 tsn: 1 afn: 2 hint: f
hash: [0x710f8a00,0x710f8a00] lru: [0x6cfd7d10,0x6c3e7958]
lru-flags: hot_buffer
ckptq: [NULL] fileq: [NULL] objq: [0x61299158,0x61299158] objaq: [0x61299148,0x61299148]
st: XCURRENT md: NULL fpin: 'ktspbwh1: ktspfsrch' tch: 1
flags: block_written_once redo_since_read
LRBA: [0x0.0.0] LSCN: [0x0.0] HSCN: [0xffff.ffffffff] HSUB: [1]