Oracle Buffer Pool内部闩锁机制

本文中根块,枝块,叶块,表块分别是索引根块,索引枝块,索引叶块,数据表块的简称。

此外本文大多数观点来自于大师吕海波《Oracle内核技术揭秘》一书,本博文为个人感想。

首先需要明确4点关于CBC LATCH和BUFFER PIN的知识点:

1. 对于根块和枝块,CBC LATCH都是以S模式获取的,无BUFFER PIN

2. 对于叶块,CBC LATCH是以X模式获取的,BUFFER PIN是以S模式获取的

3. 对于表块,CBC LATCH是以X模式获取的,SELECT语句的BUFFER PIN是以S模式获取的,DML语句的BUFFER PIN是以X模式获取的

4. 以上三点基本正确,但有一个特殊情况,INDEX UNIQUE SCAN的情况下是这样的:

1)对于根块、枝块、叶块,CBC LATCH都是以S模式获取的,且都无BUFFER PIN

2)对于表块,SELECT语句的CBC LATCH是以S模式获取的,无BUFFER PIN;DML语句的CBC LATCH是以X模式获取的,BUFFER PIN是以X模式获取的

现在我们考虑一种最复杂的情况:不走索引唯一扫描但走索引的情况。

此时将CBC LATCH和BUFFER PIN的获取方式进行分类总结:

A 根块和枝块:以S模式获取CBC LATCH-->>读取索引数据-->>释放CBC LATCH

B 叶块:以X模式获取CBC LATCH-->>以S模式获取BUFFER PIN,释放CBC LATCH,读取索引数据-->>以X模式获取CBC LATCH,释放BUFFER PIN-->>释放CBC LATCH

C 表块(SELECT):以X模式获取CBC LATCH-->>以S模式获取BUFFER PIN,释放CBC LATCH,读取数据-->>以X模式获取CBC LATCH,释放BUFFER PIN-->>释放CBC LATCH

D 表块(DML):以X模式获取CBC LATCH-->>以X模式获取BUFFER PIN,释放CBC LATCH,修改数据-->>以X模式获取CBC LATCH,释放BUFFER PIN-->>释放CBC LATCH

那么对于SELECT和DML语句我们就可以使用以上组合来显示出其获取内部锁和闩的过程:

1.SELECT语句的流程是:ABC

2.DML语句的流程是:ABD

现在我们模拟所有情况下的内部闩锁争用:(我们假设最差的情况,SELECT和DML语句都走同样的索引,查同样的数据)

一:SELECT语句的并发,即ABC并发ABC

A阶段全是S模式不会有争用发生,BC阶段获取X模式CBC LATCH的时间极短(只为修改BUFFER PIN的状态),BC阶段的BUFFER PIN是S模式,也不会引发争用。(10G之前会)

因此SELECT并发不会引发BUFFER BUSY WAITS

二:SELECT语句和DML语句的并发,即ABC并发ABD

A阶段全是S模式不会有争用发生,B阶段获取X模式CBC LATCH的时间极短(只为修改BUFFER PIN的状态),也不会发生争用,那么C和D阶段:

如果C在前那么D貌似会发生等待,但其实会进行构造CR块的操作,并在独占CBC LATCH的保护下将当前BUFFER HEADER(简称BH)修改为CR块,克隆出来的块的BH修改为XCUR的当前块,不会发生等待。但是如果构造完CR块完此时又有一个C或D并发过来,由于克隆块是XCUR块上边被加了X模式的BUFFER PIN,那么就会发生等待,这里就是BUFFER BUSY WAITS啦。

如果D在前,那么同样的BUFFER BUSY WAITS出现,所以说只要在D之后并发了C或者D,都会造成BUFFER BUSY WAITS。

之前在此处有些疑问,为何后来的C并发不会发生一致性读呢,后来想想D已经加了X模式的BUFFER PIN,一致性读是需要读取表块的ITL槽信息的,这里C连块的BUFFER PIN都获取不到,谈何一致性读。

真正的一致性读应当指涉及UNDO的操作,因为既然DML发现了BUFFER PIN上的S模式的锁证明这个块正在被读,根本无需一致性读。

三:DML语句的并发

这里就很显然了,ABD的AB阶段不会发生明显争用,D阶段一个会话获取了X模式的BUFFER PIN之后,另一个必然要等待,而且此时如果再来一个SELECT语句,也会被阻塞,按照事务锁的机制,SELECT是不会被DML阻塞的,但是这里并不是事务锁阻塞而是BUFFER PIN的等待。

总结:

我们知道在数据库中无论是读取还是修改一个块都是极其迅速的,因此即便是以上的并发情况下,由于每个块的BUFFER PIN锁持有时间都极短,因此单个块即便发生BUFFER BUSY WAITS时间也基本可以忽略不计。

除非更改大量的块导致多个块发生BUFFER BUSY WAITS等待,因此如果发生了BUFFER BUSY WAITS,只和DML有关,由于DML也会导致索引更新,因此出现BUFFER BUSY WAITS尽量优化DML语句。

而如果发生了CBC LATCH的等待,那就更明显了,一定是并发过多,甚至和DML无关,只要是个SQL并发太多都会导致CBC LATCH的等待,因为表块和叶块都是以独占模式获取的CBC LATCH,解决办法要么是减小并发,要么全部优化为走INDEX UNIQUE SCAN,或者通过修改隐含参数_db_block_hash_latches和_db_block_hash_buckets增大CBC LATCH和HASH BUCKET的数量。

但是需要明确的是:

BUFFER BUSY WAITS和CBC LATCH的等待其本质都是并发量过大引起,并不推荐以上使用更改隐含参数的方式解决CBC LATCH的争用。对于BUFFER PIN的争用DML语句的优化空间也很小,只能尝试创建唯一索引,因此应当考虑从业务角度降低并发。

 

时间: 2024-10-29 19:10:55

Oracle Buffer Pool内部闩锁机制的相关文章

Oracle Share Pool内部管理机制

SHARE POOL利用堆(HEAP)的内存管理方式管理,在物理上由多个内存区(EXTENT)组成,内存区又由多个不同大小的CHUNK组成.而CHUNK又有可重用和空闲之分,并且它们分别有LRU LIST.FREE LIST.RESERVED LIST串联起来. 堆管理 Shared Pool是利用堆内存管理方式管理的(KGH:Kernel Generic Heap).从Oracle 9i开始,可以有多个最高级堆(TOP-LEVLE HEAP),最高级堆可以分成多个副堆,副堆下面还拥有子堆.堆和

MYSQL的InnoDB Buffer Pool内部机制

1. 基本结构:INNODB用least recently used (LRU) 算法来管理他的buffer_pool. buffer_pool在内部被分隔为两个list. a young list 和 a old list. Young list 存储那些高频使用的缓存数据(默认占整个BUFFER的5/8) Old list 存储那些低频使用的数据(默认占整个BUFFER的3/8) 2.使用机制:当一个新块数据被从磁盘缓存到buffer当中,它默认被放在Old list的头部,即midpoin

ORACLE【2】:锁机制及解锁

1. 锁的基本知识 根据要保护的对象不同,oracle的数据锁可以分成以下几类:DML锁,(data locks)数据锁,用于保护数据的完整性:DDL锁(dictionary locks),用于保护数据库内部结构,如表,索引等结构定义:内部锁和闩(internal locks and latcheds),保护数据库内部结构. 我们通常遇到的都是DML锁,DML锁在通常状态下都是用于保证并发情况下的数据完整性.在oracle中,主要包含有TM锁和TX锁,其中TM锁称为表级锁,TX锁称行级锁或事物锁

关于MySQL buffer pool的预读机制

预读机制 两种预读算法 1.线性预读 2.随机预读 对预读的监控 一.预读机制 InnoDB在I/O的优化上有个比较重要的特性为预读,预读请求是一个i/o请求,它会异步地在缓冲池中预先回迁多个页面,预计很快就会需要这些页面,这些请求在一个范围内引入所有页面.InnoDB以64个page为一个extent,那么InnoDB的预读是以page为单位还是以extent? 数据库请求数据的时候,会将读请求交给文件系统,放入请求队列中:相关进程从请求队列中将读请求取出,根据需求到相关数据区(内存.磁盘)读

cache buffer 相关的闩锁等待事件(cache buffers lru chain/cache buffers chain)

cache buffers lru chain原因高负荷的cache吞吐量,效率差的sql语句(全表扫描,或不正确的index range scans)dbwr写出速度太慢,前台进程花费很多时间持有latch查找free buffer. cache buffers lru chain保护buffer的链表在cache中,当增加,移除,移动一个buffer从list时,cblc latch必须被获取.在SMP(对称多处理)的系统上,oracle自动设置LRU latche数量是cpu个数的一半.在

基于Oracle数据库锁机制,解决集群中的并发访问问题

1.需求 应用场景是这样的: 使用Oracle数据保存待办任务,使用状态字段区分任务是否已经被执行.多个Worker线程同时执行任务,执行成功或失败后,修改状态字段的值. 假设数据库表结构如下所示. create table Task( id varchar2(32), name varchar2(32), flag varchar2(1), worker varchar2(32) ); flag 可取的值包括:0-待办,1-已办,-1-失败待重试. 需要避免的问题: 多个Worker同时工作时

oracle buffer cache的基本原理

Buffer cache 的原理 一. 1·)当一个服务器进程需要读数据到buffer cache中时,首先必须判断该数据在buffer 中是否存在,如果存在且可用,则获取该数据,根据lru算法在lru list上移动该block:如果buffer中不存在该数据,则需要从数据文件上获取 2)在读取数据之前,server进程需要扫描lru list 寻找free的buffer,扫描过程中server进程会把发现的所有已经被修改过的buffer移动到checkpoint queue上,这些dirty

mysql-5.7 saving and restore buffer pool state 详解

一.mysql 重启要面临的问题: 由于重启后之前innodb buffer pool中缓存的数据就都没有了,如果这个时候业务SQL来临,mysql就只能是从磁盘中 读取数据到内存:可能要经过数个小时的时间内存中的数据才能是业务频繁要用的.行业中把这个内存从什么都没有 到内存中都是热数据的这个过程叫作预热.可见在预热这个过程中数据库的性能是不怎么好的,对于内存(innodb buffer pool) 越大的库预热的时间就越长 二.解决问题的思路: 说起来这个解决方法也是简单粗暴,方法就是mysq

shared pool 和buffer pool 详解(之二, Cache Buffers LRU Chain、Cache Buffers LRU Chain闩锁竞争与解决)

[深入解析--eygle]学习笔记 1.1.2  Cache BuffersLRU Chain闩锁竞争与解决 当用户进程需要读数据到Buffer Cache时或Cache Buffer根据LRU算法进行管理等,就不可避免的要扫描LRU  List获取可用Buffer或更改Buffer状态,我们知道,Oracle的Buffer Cache是共享内存,可以为众多并发进程并发访问,所以在搜索的过程中必须获取Latch(Latch是Oracle的一种串行锁机制,用于保护共享内存结构),锁定内存结构,防止