您的位置:首页 > Web前端

Cache buffer latches的形成原因分析

2009-08-15 11:34 253 查看

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'
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: