当前台进程发出一个select或者其他DML语句时,oracle会根据sql语句的执行计划找到的数据块,会构造一个名为数据块描述的内存结构,当然这块内存结构不会存在SGA中,而是位于session的PGA中,只要记录的是数据块所在的物理地址,数据块类型,数据块所属对象等信息。当这块内存结构构造完成后,oracle会把数据块请求的锁定模式以及所构造出来的buffer descriptor(数据块描述)传入到搜索数据块的函数中,该函数会根据oracle传入的buffer descriptor所记录的信息,应用一定的hash算法,得到要找的数据块所处的hash bucket,确定了该sql操作的数据块在哪条hash chain上,然后oracle进入该chain,在该hash chain上,对第一个buffer header开始搜索,一直到最后一个buffer header,在搜索过程中,过程如下:
1) 比较buffer header上所记录的数据块的地址,如果不符合,则跳过该buffer header。
2) 跳过状态为CR的buffer header。
3) 如果遇到状态为READING的buffer header,则等待,一直等到该buffer header的状态改变以后再比较所记录的数据块的地址是否符合。
4) 如果发现数据块地址符合的buffer header,则查看该buffer header是否位于正在使用的列表上,如果是,则判断已存在的锁定模式与当前所要求的锁定模式是否兼容,如果是,则返回该buffer header所记录的数据块地址,并将当前进程号放入该buffer header所处的正在使用的列表上。
5) 如果发现锁定模式不兼容,则根据找到的buffer header所指向的数据块的内容,构建一个新的、内容一样的、状态为XCURRENT的复制数据块,并且构造一个状态为CR的buffer header,同时该buffer header指向所新建立的复制数据块。然后,返回该复制数据块的地址,并将当前进程号放入该buffer header所处的正在使用的列表上。
6) 如果比较完整个hash chain以后还没发现所要找的buffer header,则从磁盘上读取数据文件。并将读取到的数据块所对应的buffer header挂到hash chain上。
如上所述就是oracle如何在hash chain中搜索要找的数据块所对应的buffer header过程,可能过程总结比较简单,但原理大致就是这样,具体实现过程就不阐述了。另外如果在hash chain上没有找到所需要的buffer header时,oracle会发出io请求,到磁盘上的数据文件中获取所需要的数据块,这里也就是通常我们所说的物理读,然后将该数据块的内容拷贝一份到buffer cache中的内存数据块里。这里就需要再说明一下,既然要放数据块到buffer cache中,那如果buffer cache满了怎么办,没有满又是如何操作的?假如buffer cache是空的,或者能够放下所需要的数据块,那就直接拿一根空的内存数据块来用即可,如果buffer cache中的内存数据块此时已经全部被用到了,没有空的内存数据块了,这里就要引入前面我们所说过的LRU和LRUW等链表结构了。
LRU链表前面博客也简单提到过,在buffer cache中,LRU链表算经常使用的一种结构,但在详细说明LRU链表和LRUW链表时,还是有必要先了解一下其他几个概念:
1) 脏数据块(dirty buffer):buffer cache中的内存数据块的内容与数据文件中的数据块的内容不一致。
2) 可用数据块(free buffer):buffer cache中的内存数据块为空或者其内容与数据文件中的一致。注意,可用数据块不一定是空的。
3) 钉住的数据块(ping buffer):当前正在更新的内存数据块。
4) 数据库写进程(DBWR):这是一个很底层的数据库后台进程。既然是后台进程,就表示该进程是不能被用户调用的。由oracle内置的一些事件根据需要启动该进程,该进程用来将脏数据块写入磁盘上的数据文件。
看到如上几个概念,应该还是比较熟悉吧,而且也非常容易理解,这对于后面所提到的LRU和LRUW链表还是非常有帮助的。
转载: http://www.savedba.com/oracle-buffer-cache理解之四-buffer-cache的内部管理机制!/