Cache buffer latches的形成原因分析

Cache buffer latches 的形成原因分析

当一个数据块被读入 SGA. 这些数据块所在缓冲区的头地址 (buffer headers) 被挂载到链列表上 (LRU, LRUW). 这些连列表被挂载在 hash buckets . Oracle 定义了一些 cache buffer chains latches 来保护这种内存结构的数据一致性读取 . 如下表所示 .

一个进程在对数据块执行 add, remove, search, inspect, read 或者 modify 之前需要首先获得 cache buffers chains latch. 有两条规则跟 oracle 访问数据块时的 cache buffers chains 相关 .

l          每一个 logical read 都会造成一个 latch cpu 时间 .

l          Oracle 必须获得期望的 latch 才能执行下一个步骤 .

 

不够优化的 SQL 语句是导致 cache buffers chains latch 的主要原因。如果 SQL 语句需要访问过多的内存数据块,那么必然会持有 latch 很长时间。找出逻辑读特别大的 sql 语句进行调整。

还有一个原因可能会引起 cache buffers chains latch ,就是热点数据块问题。这是指多个 session 重复访问一个或多个被同一个 child cache buffers chains latch 保护的内存数据块。这主要是应用程序的问题。大多数情况下,单纯增加 child cache buffers chains latches 的个数对提高性能没有作用。这是因为内存数据块是根据数据块地址以及 hash chain 的个数来进行 hash 运算从而得到具体的 hash chain 的,而不是根据 child cache buffers chains latches 的个数。如果数据块的地址以及 hash chain 的个数保持一致,那么热点块仍然很有可能会被 hash 到同一个 child cache buffers chains latch 上。可以通过 v$session_wait p1raw 字段来判断 latch free 等待事件是否是由于出现了热点块。如果 p1raw 保持一致,那么说明 session 在等待同一个 latch 地址,系统存在热点块。当然也可以通过 x$bh tch 来判断是否出现了热点块,该值越高则数据块越热。

对于一些大型的数据库系统来说 , hash chains 可能会较长 , 比如每个 hash chains 上可能会有上百个数据块 . 这也可能是造成性能问题的一个重要原因 .

1, 考虑 10 个相同的查询语句同时开始执行查询同一个 hash latch(L1) 中的第一个数据块 .

A, 在第一个 cpu 时间 , session1 获得 latch L1, 其他 session 获取失败 .

B, 在第二个 cpu 时间 , 假设 sesson1 已经完成 , L1 session2 获得 , 其他 session 获取失败 .

C, ….

D, 在第 n cpu 时间 , n session 获得 latch 成功 , 剩余 10-n session 获取失败 .

E…

F, 在第十个 cpu 时间里 , session10 获得 L1 成功 .

在上述的描述过程中 , session N 的等待时间可以用下面的公式描述 .

WaitTime(n) = (n-1) * 单位 cpu 时间 .

2, 考虑 10 个相同的查询语句同时开始执行查询同一个 hash latch(L1) 中的最后一个数据块 .

A, 在第一个 cpu 时间 , session1 获得 latch L1, 其他 session 获取失败 .

B, 在第二个 cpu 时间 , 假设 sesson1 已经完成 , L1 session2 获得 , 其他 session 获取失败 .

C, ….

D, 在第 n cpu 时间 , n session 获得 latch 成功 , 剩余 10-n session 获取失败 .

E…

F, 在第十个 cpu 时间里 , session10 获得 L1 成功 .

在这里的单位 cpu 时间跟情况 1 下少有不同 . 我们假设遍历一条 chain 的时间为 t1, 则每个 session 的等待时间可以用下述公式描述 .

WaitTime(n) = (n-1) * ( 单位 cpu 时间 +t1)

3, 考虑 10 个相同的查询语句同时开始执行查询同一个 hash latch(L1) 中的最后一个数据块 .

A, 在第一个 cpu 时间 , session1 获得 latch L1, 其他 session 获取失败 .

B, 在第二个 cpu 时间 , session1 由于需要重新获得同一个 latch, 所以也会加入竞争队列 . 我们为了计算方便 , 假设使用一个先进先出的队列处理竞争 , 于是 L1 session2 获得 , 其他 session 获取失败 .

C, ….

D, 在第 n cpu 时间 , n session 获得 latch 成功 , 剩余 9 session 获取失败 .

E…

F, 在第十个 cpu 时间里 , session10 获得 L1 成功 . 其他获取失败

G, 在第十一个 cpu 时间里 , session1 获得 L1 成功 , 其他获取失败 .

我们依然假设每个 latch 的拥有时间均为单位 cpu 时间 t, 则每个 session 等待的时间变为 .

WaitTime(n) =10 * 单位 cpu 时间 + (n-1) * ( 单位 cpu 时间 +t1)

 

测试环境建立

1, 创建一个包含 10 个数据块的表

/* 创建数据表
pctfree 设置为99 主要是为了使每个数据块只有1 条数据
*/

create table jax_t1(
FID
varchar2 ( 10 ),
FName
varchar2 ( 400 ),
Ftype
varchar2 ( 4 )
)
pctfree 99
pctused 1 ;

-- 插入测试数据
insert into jax_t1
select rownum ,rpad( rownum , 400 , '*' ), mod ( rownum , 2 ) from dba_objects where rownum < 11 ;

-- 检查各记录存储的数据块号
select dbms_rowid.rowid_relative_fno( rowid ) fileno,
       dbms_rowid.rowid_block_number(
rowid ) blockno,
       fid,fname,ftype
from jax_t1;

-- 检查各数据块在x$bh 中的存储情况
select * from x$bh
where file # = &fileno
 
and dbablk between &blockno1 and &blockno2;  --90794   90803

 

2, 同时打开多个 session, 同时执行下述语句 , 然后到 v$session_wait 中查询结果如下 .

declare
  i
integer ;
  vid
varchar2 ( 400 );
begin
  i:=
0 ;
 
 
loop
 
exit when i > 1000000 ;
   
select fname into vid from jax_t1 where fid = 1 ;
    i := i+
1 ;
 
end loop ;
end ; .

 

 

select a.* from v$session_wait a, v$session b
where a.sid = b.sid
 
and b.STATUS = 'ACTIVE'
 
and b. type <> 'BACKGROUND'

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值