Cache buffer latches的形成原因分析

来源:互联网 发布:饿了么研发待遇 知乎 编辑:程序博客网 时间:2024/05/01 01:07

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都会造成一个latchcpu时间.

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_waitp1raw字段来判断latch free等待事件是否是由于出现了热点块。如果p1raw保持一致,那么说明session在等待同一个latch地址,系统存在热点块。当然也可以通过x$bhtch来判断是否出现了热点块,该值越高则数据块越热。

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

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

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

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

C, ….

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

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已经完成, L1session2获得, 其他session获取失败.

C, ….

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

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, 所以也会加入竞争队列. 我们为了计算方便, 假设使用一个先进先出的队列处理竞争,于是 L1session2获得, 其他session获取失败.

C, ….

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

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'

原创粉丝点击