暂无图片
暂无图片
4
暂无图片
暂无图片
暂无图片

Oracle DBCACHE和CKPT

白鳝的洞穴 2020-11-24
4029

DB CACHE是Oracle十分重要的数据结构。老白刚刚开始学习ORACLE数据库的时候,有个前辈指导老白,看oracle性能好不好,检查下DB CACHE的命中率就行了,保证DB CACHE的命中率在90%以上,确保不低于85%,你的系统性能就不会有太大的问题了。后来在很多项目中验证过,发现这一招还真的挺灵的。不过那时候是90年代初,应用软件还比较简单,并发量还不大。确实如果确保大部分数据是在CACHE中获得的,并且通过DB CACHE命中率发现一些有问题的SQL,并进行优化,效果也挺好的。于是凭着这手绝活,老白在圈子里渐渐有了优化高手的名号。

随着计算机技术的发展,海量内存的使用,现在绝大多数系统的DB CACHE命中率都已经高达99%以上了。很多初学者对DB CACHE为何有如此高的命中率十分疑惑,实际上,这和Oracle DB CACHE巧妙的数据结构和卓越的算法是分不开的。今天我们来探究一下DB CACHE里的一些重要的数据结构和算法。

DB CACHE的算法是基于一系列链的,DB CACHE中有很多重要的链,这些链或者和DB CACHE的分配、换出、刷新优化,或者和DB BLOCK的查找有关。下面我们先来了解这些链的基本情况,然后我们来探讨一下这些链在各种DB CACHE活动中所起的作用。

LRU list 和LRU-AUX list

 LRU list也叫replacement list,这就是大家常说的LRU链,用于DB CACHE的老化淘汰和CACHE块的重用。DB CACHE的算法中,数据库启动之初,空闲的CACHE都是在LRU链上的。前台进程需要分配DB CACHE的时候,从LRU链的冷端开始扫描,查找可用的CACHE。找到CACHE后,根据要读入的数据块的RDBA,通过HASH算法找到一个HASH 链的BUCKET,将这个数据块头上的HASH链相关指针链接到HASH链上。
LRU-AUX链是LRU链的一个子链。从LRU-AUX头开始的BLOCK是被确认为CLEAR的,其来源包括DBWR已经写回文件的数据块和UNPIN的干净块。前台进程查找空闲BUFFER的时候,就是首先在LRU-AUX中查找,因为从这里找到的BUFFER一般都是可用的。LRU-AUX存储的是刚刚被回写数据,并且已经释放的DB CACHE,其主要作用是批量将一个可用链表链入LRU LIST,从而减少对LRU LIST链表的性能影响。

LRU-W list (write list)

    LRU-W list就是我们常说的脏数据链,对于LRU-W链,也存在一个AUX链LRUW-AUX。引入AUX链的目的是为了提高LRU-W的效率,支持异步DBWR作业。在这个链没有引入以前,当一个DBWR作业没有完成前,是无法进行下一个DBWR作业的。引入AUX后,AUX链存放的是当前DBWR正在写入的数据,LRU-W就腾出来处理下一个DBWR作业了。前台进程在查找空闲CACHE的时候,如果扫描到了一个脏块,就会主动将脏块移到LRU-W LIST上,从而避免这个脏块被多次无效的扫描到。Oracle这种将一些脏活累活分散到某个前台会话中的做法,是一种十分有效的提高性能的方法,十分值得我们数据库开发厂家学习。

LRU-XO list (reuse object list)

LRU-XO list也被称为重用对象链,这个链主要是为了对TRUNCATE,DROP等操作的对象相关的BUFFER进行CHECKPOINT操作。当reuse object cross instance call事件发生的时候,CKPT会将这个对象的脏数据块放入LRU-XO链,然后由DBWR将这些数据块写盘。当CKPT发现这个链已经空的时候,本次CHECKPOINT操作结束。

LRU-XR list (reuse range list)

  和LRU-XO链类似,XO是针对某个SEGMENT的,而LRU-XR主要针对表空间这类对象。LRU-XR list也被称为Reuse range链,当reuse range cross instance call事件发生的时候,CKPT搜索这些BUFFER,把脏数据块放入LRU-XR链,然后由DBWR将这些数据写盘。当CKPT发现这个链已经空的时候,本次CHECKPOINT结束。如果我们要将某个表空间OFFLINE或者将某个表空间设置为READ ONLY的时候,这个时候就会产生ruse range cross instance call事件,因为要安全的完成这些操作,必须要将表空间上的脏数据全部写入磁盘。

  

上面我们介绍了一些LRU链,下面我们再来看看BUFFER HEAD的数据结构,看看这些链是如何使用的。

struct kcbbh { * 10201 struct kcbbh */

  kgglk                kcbbhha; *  hash chain buffer is on  */

  ktsn                 kcbbhtsn; *  tablespace number  */

  krdba                kcbbhrdba; *  relative DBA  */

  ub4                  kcbbhflg; *  flags: all changes require hash latch  */

  kobjd                kcbbhobj; *  Object # (disk )for block (if known)  */

  kobjn                kcbbhobjn; *  dictionary object # (if known)  */

  BitMask for "struct kcbbh.kcbbhobjn"

   KCBBHFBD        BIT 0x00000001 //  Buffer Dirty 

   KCBBHREU        BIT 0x00000002 //  buffer has been reused 

   KCBBHFMS        BIT 0x00000004 //  modification started, no new writes 

   KCBBHFPB        BIT 0x00000008 //  private buffer 

   KCBBHFTD        BIT 0x00000010 //  temporary data, no redo for changes 

   KCBBHFBW        BIT 0x00000020 //  being written, cannot modify 

   KCBBHFFG        BIT 0x00000040 //  foreground waiting for buffer 

   KCBBHFCP        BIT 0x00000080 //  clone of a private buffer 

   KCBBHFIM        BIT 0x00000100 //  pinned for IMU, do not write 

   KCBBHFUL        BIT 0x00000200 //  unlink from lock element and make cr 

   KCBBHFDG        BIT 0x00000400 //  down grade lock 

   KCBBHFCW        BIT 0x00000800 //  a clone copy is being written 

   KCBBHFCR        BIT 0x00001000 //  reading from disk into KCBBHCR buffer 

   KCBBHFGC        BIT 0x00002000 //  has been gotten in current mode 

   KCBBHFST        BIT 0x00004000 //  stale, unused CR buf made from current 

   KCBBHFDP        BIT 0x00008000 //  deferred ping 

   KCBBHFDA        BIT 0x00010000 //  direct Access to buffer contents 

   KCBBHFVB        BIT 0x00020000 //  buffer being evicted for cache shrink 

   KCBBHFPW        BIT 0x00040000 //  prewarmed buffer 

   KCBBHFSQ        BIT 0x00080000 //  sequential scan only flag 

   KCBBHFBP        BIT 0x00100000 //  Buffer was Prefetched 

   KCBBHFFW        BIT 0x00200000 //  buffer has been written once 

   KCBBHFFB        BIT 0x00400000 //  buffer is logically flushed 

   KCBBHFTP        BIT 0x01000000 //  dma transfer in progress 

   KCBBHFRG        BIT 0x02000000 //  Redo Generated since block read 

   KCBBHFWC        BIT 0x04000000 //  Write has been Completed 

   KCBBHFSI        BIT 0x08000000 //  block transferred from another instance 

   KCBBHFDB        BIT 0x20000000 //  buffer is directly from a foreign DB 

   KCBBHFAW        BIT 0x40000000 //  flush after writing 


  b1                   kcbbhst; /*  state of the buffer  */

  BitMask for "struct kcbbh.kcbbhst"

   KCBBHFREE       BIT 0 //  buffer free 

   KCBBHEXLCUR     BIT 1 //  buffer current (and is DFS locked X) 

   KCBBHSHRCUR     BIT 2 //  buffer current (and is DFS locked S) 

   KCBBHCR         BIT 3 //  buffer consistant read 

   KCBBHREADING    BIT 4 //  being read 

   KCBBHMRECOVERY  BIT 5 //  media recovery 

   KCBBHIRECOVERY  BIT 6 //  crash or instance recovery 

   KCBBHWRITING    BIT 7 //  write clone 

   KCBBHPI         BIT 8 //  past image 

   KCBBHMEMORY     BIT 9 //  allocated memory buffer 

   KCBBHMWRITING   BIT 10 //  media recovery write clone 

   KCBBHDONATED    BIT 11 //  donated to another memory component 


  b1                   kcbbhmd; /*  mode owned in (KCBMNULL, KCBMSHR, KCBMEXCL)  */

  ub2                  kcbbhcla; /*  block class  */

  ub2                  kcbbhafn; /*  absolute file number  */

  b1                   kcbbhccnt; /*  number of changes to buffer in single kcbchg()  */

  b1                   kcbbhcst; /*  change state for recovery if failure during kcbchg()  */

  BitMask for "struct kcbbh.kcbbhcst"

   KCBBHCNUL       BIT 0 //  No change in progress. KCBBHFMS should be off 

   KCBBHCNAY       BIT 1 //  changes not active yet: redo may have been written 

   KCBBHCACT       BIT 2 //  changes active:  buffer contents unpredictable 

   KCBBHCRCV       BIT 3 //  changes recovering: block recovery in progress 

   KCBBHCCMP       BIT 4 //  changes complete: buffer cleanup still needed 


  ub2                  kcbbhssid; /*  simulation set id  */

  ub1                  kcbbhsflg; /*  rac flags  */

  BitMask for "struct kcbbh.kcbbhsflg"

   KCBBHFMW        BIT 0x01 //  multiple waiters when gc lock acquired 

   KCBBHFAK        BIT 0x02 //  locked with an affinity lock 

   KCBBHFPA        BIT 0x04 //  PI buffer has been aged once 

   KCBBHFSP        BIT 0x08 //  recovery suspect resolution in progress 

   KCBBHFRE        BIT 0x10 //  renounce in progress 

   KCBBHFSU        BIT 0x20 //  write suspect resolution in progress 


  ub1                  kcbbhcqid; /*  which ckpt queue in working set buffer is  */

  kgglk                kcbbhckql; /*  link for checkpoint queue  */

  kgglk                kcbbhfql; /*  link for per-file checkpoint queue  */

  ptr_t                kcbbhba; /*  buffer base address (set when mapped)  */

  kscn                 kcbbhdscn; /*  incremental Transactional DSCN  */

  kgglk                kcbbhus; /*  list of users  */

  kgglk                kcbbhwa; /*  list of waiters  */

  kgglk                kcbbhrpl; /*  link for maintaining position on replacement chain  */

  b1                   kcbbhfoq; /*  TRUE iff the buffer is on a write list  */

  b1                   kcbbhlpf; /*  LRU latch protected flags  */

  BitMask for "struct kcbbh.kcbbhlpf"

   KCBBHLDF        BIT 0x01 //  LRU Dump Flag used in debug print routine 

   KCBBHLMT        BIT 0x02 //  moved to tail of lru (for extended stats) 

   KCBBHLAL        BIT 0x04 //  on auxiliary list 

   KCBBHLHB        BIT 0x08 //  hot buffer - not in cold portion of lru 

   KCBBHOAX        BIT 0x10 //  buffer in auxiliary object queue 

   KCBBHOWR        BIT 0x20 //  buffer in write object queue 


  ub2                  kcbbhtch; /*  touch count  */

  ub4                  kcbbhtim; /*  time of last touch count increment  */

  union kcbbh.UNK_10526973 kcbbhu;

  void *               kcbbhxcb; /*  pointer to transaction state object  */

  kcocv *              kcbbhlcv; /*  pointer to last chg in a series of chg's  */

  struct kcbwds *      kcbbhds; /*  system set descriptor  */

  krfgda               kcbbhgda; /*  flashback generation disk address  */

  kgglk                kcbbhoq; /*  object queue the buffer is on  */

  struct kcbbh.UNK_10526983 kcbbhsh; /*  all fields that are needed in shared mode  */

  kcbtrcbuf            kcbbhhashtrc; /*  trace of events under hash latch  */

}


以前也经常有人问我CKPT的相关操作,我在这方面也研究较少,主要是Oracle这方面的文档实在是太少了。虽然从TOM和STEVE那里可以获得一些资料,但是都比较支离破碎,因此针对CKPT操作的一些细节问题,我也只能通过上面的数据结构做一个推测,这个推测一定准确,不过大体上可以反映出CKPT算法的一些最为基本的概念。

首先,我们来看看CHECKPOINT QUEUE。CHECKPOINT QUEUE是通过LOW RBA排序的一个链表,当某个BLOCK发生变化的时候,会将该BLOCK按照LOW RBA地址链入相关的CHECKPOINT QUEUE,这些链表包括标准CKPT QUEUE(老白在这里用了“标准”两个字,实际上这不是Oracle 内部的术语,这部分内容公布的很少,因此老白用“标准”两字来将其区别于RANGE和OBJECT两个CKPT QUEUE)、XO CKPT QUEUE(OBJECT CKPT,每个对象一个)和XR CKPT QUEUE(RANGE CKPT,术语称为PER-FILE CKPT QUEUE,每个数据文件一个)。

在做普通的CHECKPOINT操作的时候,CKPT进程找到CKPT链的头部,将CKPT QUEUE交给DBWR,由DBWR组织CHECKPOINT DBWR批处理,DBWR进程开始写入操作,由于CKPT QUEUE是按照LOW RBA的顺序排序的,因此在做CHECKPOINT DBWR批处理的时候,是按照RBA的顺序写入脏数据的。当DBWR完成写操作后,CKPT进程更高控制文件和相关的文件头的SCN数据,记录本次CKPT操作的结果。

由于CKPT QUEUE上的BUFFER有可能在LRU链上,也有可能在LRU-W链上,在组织DBWR批处理的时候,LRU链上的BUFFER是否要摘下放入LRU-W,这些算法目前CHECKPOINT 写入的时候,这些BLOCK不从LRU LIST上移走,写完后,从CKPTQ里清除,这和普通的LRUW中的块被写入数据库是不同的。

TRUNCATE,DROP之类的操作发生的时候,也会发生CHECKPOINT,这类的CHECKPOINT被称为是REUSE OBJECT CHECKPOINT,发生这个操作的时候的具体操作目前很少有资料说明。老白猜测当REUSE OBJECT CHECKPOINT发生时,CKPT进程将kcbbhoq指向的OBJECT CHECKPOINT链上的脏块链入LRU-XO,交给DBWR处理。DBWR组织写批处理,进行写入操作。只有当所有的LRU-XO上的块全部被写入后,DDL操作才能完成。这种算法也造成了TRUNCATE一个大对象可能会很慢(如果这个对象很多块是脏块的话)。kcbbhoq字段是一个对象的DB CACHE链。这条链的存在对于REUSED OBJECT CROSS INSTANCE CALL的性能有很大的帮助。

当表空间设置READ ONLY或者OFFLINE的时候,会触发REUSE RANGE的CHECKPOINT,其原理和REUSE OBJECT的CHECKPOINT类似。通过在BUFFER HEAD中的kcbbhfql将每个数据文件的脏块串成一条链。这样,当REUSE RANGE CHECKPOINT发生时,CKPT将这条链链入LRU-XR,然后交给DBWR处理。


最后修改时间:2020-12-08 12:26:16
文章转载自白鳝的洞穴,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论