前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >性能优化:Cache Buffer Chain Latch等待事件

性能优化:Cache Buffer Chain Latch等待事件

作者头像
数据和云
发布2018-03-06 15:35:58
1.2K0
发布2018-03-06 15:35:58
举报
文章被收录于专栏:数据和云数据和云

彭小波

ACOUG核心成员,Oracle用户组年轻专家。擅长Oracle数据库架构规划、SQL,OWI方面的优化。曾服务于各大企业数据库的维护以及系统开发,目前从事百年人寿保险股份有限公司的数据库服务与运维工作。

产生的背景

Oracle为了将物理 IO 最小化,把最近使用过的数据块保持在内存中。为了管理这些内存,oracle 使用如图的结构,Hash Chain 的结构,Hash Chain 位于共享池中,使用典型内存结构 Bucket->Chain->Header 结构进行管理 lock# 组成的,当扫描块时使用Hash函数进行hash运算,使用hash值查找 hash bucket,具有相同hash值的 buffer haeder 在 hash bucket 上以 chain 形式链接。Buffer header 有指向实际缓冲区的指针。注意:Hash Chain结构是在共享池中,而实际缓冲区信息存储在高速缓冲区中。Hash Chain 结构利用 cache buffers chain Latch来保护。

当进程扫描特定的数据块时,必须获得相应数据块所在 Hash Chain 管理的 cache buffers chain Latch。基本上一个进程获得仅有的一个 cache buffers chain Latch,一个 cache buffers chain Latch 管理多个 Hash Chain。当多个进程同时检索Buffer Cache时,获得 cache buffers chain Latch 的过程中发生争用,就会产生该等待事件。Hash Chain 结构的起点是Hash表,Hash 表由多个 hash bucket 组成,块地址是由 file#+b cache buffers chain Latch 等待事件。

进程扫描特定的数据块的过程如下: 1、Oracle 以每个块的文件号、块号和类型做 HASH 运算,得到 HASH 值。根据 HASH值,到 HASH 表中取出指定块的内存地址 2、获取 CBC Latch 3、根据 HASH 值,搜索 CBC 链表 4、根据 DBA 找到 BH(Buffer Header) 加 Buffer Pin 5、加完 Buffer Pin 马上释放 CBC Latch 6、访问 Buffer 开始 fetch 数据 7、获取 CBC Latch 8、释放 Buffer Pin 9、释放 CBC Latch

使用 SQL 语句可以获得 hash_latches,hash_buckets 数量,因此一个锁存器保护 Bucket数量是1048576/32768=32个。

SQL> select x.ksppinm name, y.ksppstvl value, y.ksppstdf isdefault, decode(bitand(y.ksppstvf, 7), 1, 'MODIFIED', 4, 'SYSTEM_MOD', 8 'FALSE') ismod, decode(bitand(y.ksppstvf, 2), 2, 'TRUE', 'FALSE') isadj from sys.x$ksppi x, sys.x$ksppcv y where x.inst_id = userenv('Instance') and y.inst_id = userenv('Instance') and x.indx = y.indx and x.ksppinm like '%db_block_hash%' order by translate(x.ksppinm, ' _', ' ');

产生的原因

1.执行效率低下的SQL,低效的 SQL 语句是发生 Latch:cache buffers chains 争用的主要原因。发生在多个进程同时扫描大范围的表或索引时。

2.出现热块 hot block 时,由于编写 SQL 语句时,SQL 持续扫描少数特定块(between and ,in,not in, exists),多个会话同时执行 SQL 语句时,发生 Latch:cache buffers chains 争用。

【案例1 Latch:cache buffers chains争用事件重现 】

--1.创建测试表

create table t1(id int,name varchar2(10)); insert into values(1,'xiaobo'); commit;

--2.获取t1表的第一行数据及 ROWID,根据 dbms_rowid 包查出这行数据的文件号、块号

SQL> select rowid, dbms_rowid.rowid_relative_fno(rowid) file#, dbms_rowid.rowid_block_number(rowid) block#, id, name from emm.t1 where rownum = 1; 2 3 4 5 6 7 ROWID FILE# BLOCK# ID NAME ------------------ -------- ---------- ----- ---------- AAADfaAAFAAAACDAAA 5 131 1 xiaobo

注意:这里的 DBA(Data Block Address) 就是由5号文件和131号块组成

--3.根据 DBA获取 CBC Latch 的地址

SQL> select hladdr from x$bh where file#=5 and dbablk=131; HLADDR ---------------- 00000001D1C266D8

--4.根据CBC Latch的地址可以查出这个 CBC Latch 被获得的次数

SQL> select addr,name,gets from v$latch_children where addr='00000001D1C266D8'; ADDR NAME GETS ---------------- --------- ------ 00000001D1C266D8 cache buffers chains 46

--5.再次读取t1表的第一行数据,再次产生一次逻辑读

SQL>select id,name from emm.t1 where rowid='AAADfaAAFAAAACDAAA'; ID    NAME ------- ------------ 1    xiaobo

--6.CBC Latch 的次数变为 48,说明一次逻辑读产生两次 CBC Latch

SQL> select addr,name,gets from v$latch_children where addr='00000001D1C266D8'; ADDR NAME GETS ---------------- ------------------------ ------- 00000001D1C266D8 cache buffers chains 48

这里说明一次逻辑读要加两次 CBC Latch,一次为了加 Buffer Pin,一次为了释放 Buffer Pin!

使用 oradebug 跟踪 CBC Latch 争用事件

SQL> oradebug setmypid Statement processed. SQL> oradebug peek 0x1D1C266D8 4 -- 观察 CBC Latch 地址为 0x1D1C266D8 开始之后的4字节信息的值为0 [1D1C266D8, 1D1C266DC) = 00000000 SQL> oradebug poke 0x1D1C266D8 4 1 --修改 CBC Latch 地址为 0x1D1C266D8 开始的4字节信息的值为1,相当于获取了 Latch BEFORE: [1D1C266D8, 1D1C266DC) = 00000000 --修改前的值 AFTER: [1D1C266D8, 1D1C266DC) = 00000001 --修改后的值

--7. 再开一个新的会话,会话号为768

SQL> conn / as sysdba Connected. SQL> select sid from v$mystat where rownum=1; SID ---------- 768

--8.在新会话768下再查询T1表的第一行,我观察到不会堵塞

SQL>select id,name from emm.t1 where rowid='AAADfaAAFAAAACDAAA'; ID   NAME -------- ------------ 1   xiaobo

--9.我们回到 oradebug 的会话,这次我们不是使用 select 语句,而使用 update 语句来获 取 latch

SQL> update emm.t1 set id=2 where rowid='AAADfaAAFAAAACDAAA'; 1 row updated.

--10.再次使用 oradebug 模拟获取 latch

SQL> oradebug setmypid Statement processed. SQL> oradebug poke 0x1D1C266D8 4 1 BEFORE: [1D1C266D8, 1D1C266DC) = 00000000 AFTER: [1D1C266D8, 1D1C266DC) = 00000001

--11.回到刚才768会话下,查询T1表的第一行,这时我观察到产生了堵塞

SQL>select id,name from emm.t1 where rowid='AAADfaAAFAAAACDAAA';

--12.我们再开第三个会话,查看会话号768的等待事件,我们看到产生了 CBC Latch 的等待事件

最后在第一个会话中释放 lacth

SQL> oradebug poke 0x1D1C266D8 4 0 BEFORE: [1D1C266D8, 1D1C266DC) = 00000001 AFTER: [1D1C266D8, 1D1C266DC) = 00000000

总结: 在获取保护 hash bucket 的 cache buffers chains latch 时,如果是读取工作(select),就以 shared 模式获得(这也是我们刚才在实验中 select 时没有产生争用的原因)。如果是修改工作(update),就以 exclusive 模式获得。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2016-08-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 数据和云 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
数据库专家服务
数据库专家服务(Database Expert Service,DBexpert)为您提供专业化的数据库服务。仅需提交您的具体问题和需求,即可获得腾讯云数据库专家的专业支持,助您解决各类专业化问题。腾讯云数据库专家服务团队均有10年以上的 DBA 经验,拥有亿级用户产品的数据库管理经验,以及丰富的服务经验。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档