本实验是测试由于latch引起过高的cpu资源。我们使用以下实验来模拟。
首先我们查找一下有关于latch的隐含参数
查询当前实例一共有多少个lathc.实用下面的SQL来查询。
column name format a42
column value format a24
select
x.ksppinm name,
y.ksppstvl value,
y.ksppstdf isdefault,
decode(bitand(y.ksppstvf,7),1,'MODIFIED',4,'SYSTEM_MOD','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 '%latch%'
order by
translate(x.ksppinm, ' _', ' ');
NAME VALUE ISDEFAULT ISMOD ISADJ
----------------------------------- -------------------------------------------------- --------- ---------- -----
_db_block_hash_latches 4096 TRUE FALSE FALSE
_db_block_lru_latches 96 TRUE FALSE FALSE
_db_blocks_per_hash_latch TRUE FALSE FALSE
_disable_latch_free_SCN_writes_via_ FALSE TRUE FALSE FALSE
32cas
_disable_latch_free_SCN_writes_via_ FALSE TRUE FALSE FALSE
64cas
_enable_reliable_latch_waits TRUE TRUE FALSE FALSE
_enqueue_hash_chain_latches 24 TRUE FALSE FALSE
_flashback_copy_latches 10 TRUE FALSE FALSE
_gc_latches 8 TRUE FALSE FALSE
_gcs_latches 0 TRUE FALSE FALSE
_kgl_latch_count 0 TRUE FALSE FALSE
_kgx_latches 512 TRUE FALSE FALSE
_ktc_latches 0 TRUE FALSE FALSE
_ktu_latches 0 TRUE FALSE FALSE
_latch_class_0 TRUE FALSE FALSE
_latch_class_1 TRUE FALSE FALSE
_latch_class_2 TRUE FALSE FALSE
_latch_class_3 TRUE FALSE FALSE
_latch_class_4 TRUE FALSE FALSE
_latch_class_5 TRUE FALSE FALSE
_latch_class_6 TRUE FALSE FALSE
_latch_class_7 TRUE FALSE FALSE
_latch_classes TRUE FALSE FALSE
_latch_miss_stat_sid 0 TRUE FALSE FALSE
_latch_recovery_alignment 998 TRUE FALSE FALSE
_lm_drm_xlatch 0 TRUE FALSE FALSE
_lm_num_pcmhv_latches 0 TRUE FALSE FALSE
_lm_num_pt_latches 128 TRUE FALSE FALSE
_max_sleep_holding_latch 4 TRUE FALSE FALSE
_num_longop_child_latches 24 TRUE FALSE FALSE
_session_idle_bit_latches 0 TRUE FALSE FALSE
_ultrafast_latch_statistics TRUE TRUE FALSE FALSE
32 rows selected
再来查询一下当前实例数据库中有多少个数据块。
select count(*) from v$bh;
COUNT(*)
----------
140922
根据上面的两个查询语句,我们发现140922个数据块被4096个latch管理。
--查看每个latch管理的块数
select HLADDR ,count(*) from x$bh group by rollup(HLADDR );
由于数据太多,我只截一部分图,我们发现每个latch大约管理30多个数据块。
HLADDR COUNT(*)
---------------- ----------
0000000138356438 32
0000000138356700 39
00000001383569C8 32
0000000138356C90 31
0000000138356F58 34
0000000138357220 37
00000001383574E8 35
00000001383577B0 39
0000000138357A78 27
0000000138357D40 38
0000000138358008 33
00000001383582D0 36
0000000138358598 36
0000000138358860 40
0000000138358B28 28
0000000138358DF0 33
00000001383590B8 36
0000000138359380 32
0000000138359648 30
0000000138359910 31
0000000138359BD8 29
0000000138359EA0 32
000000013835A168 37
--查询锁的丢失情况
select CHILD# ,ADDR , GETS , MISSES , SLEEPS
from v$latch_children
where name = 'cache buffers chains'
and misses>100000
order by 4, 1, 2, 3;
CHILD# ADDR GETS MISSES SLEEPS
---------- ---------------- ---------- ---------- ----------
1571 00000001384672C8 1425958067 105284 1
3042 0000000138566E00 2389392407 192232 14
根据上面的基数,我们来开始我们的实验。
首先我们建立一个测试表t1,向表中插入一些数据。
使用一个匿名块同事查询表t1。同时开10个回话。
--开10个会话,其中表t1有几万行的数据,同时运行,立刻查询上面的语句
declare
v1 emp.sal%type;
begin
for n in 1..100 loop
for k in 1..100 loop
select count(*) into v1 from t1;
end loop;
dbms_lock.sleep(1);
end loop;
end;
/
SQL> select name,gets,misses from v$latch where name='cache buffers chains';
NAME GETS MISSES
------------------------------------------ ---------- ----------
cache buffers chains 68121210 6701801
我们不断的运行,misses迅猛的增加。
那么这里给大家解释下,什么是GETS,什么是MISSES,GETS就是记录你向oracle请求查询的次数,
而misses那,是你向oracle请求,但是由于oracle比较繁忙,不能答复您的请求,也就是不能答复您的次数。
打个比方,我们在办公室经常会使用到会议室,但是公司只有一个会议室,大家都想使用这个会议室,而这时会议室正在被占用,你想使用,但是
您还不知道什么时候能使用完,您就过一会儿,去看一看有没有人在占用,一看还在占用,你就回去等。反复去查看使用
情况,您去查看的次数也就是GETS的数量,MISSES就是您发现还在占用的次数。
在数据库中,MISSES的次数越多,说明某一个数据对象越繁忙。那么数据库的速度就越慢。
因此我们要定位热点的对象,我们可以通过下面的语句来定位数据库中MISSES次数比较多的对象。
--找到哪些misses的比较多。如果100000选出来的太多,根据不同的情况,你可以加大MISSES的次数。
select CHILD# ,ADDR , GETS , MISSES , SLEEPS
from v$latch_children
where name = 'cache buffers chains'
and misses>100000
order by 4, 1, 2, 3;
CHILD# ADDR GETS MISSES SLEEPS
------ -------- ---------- ---------- ----------
924 699B50C0 1271177 127078 21
590 699A5640 1205164 127715 22
291 69997600 1205428 127716 32
981 699B7B80 2405417 185470 65
--根据addr的列,找到文件号和块号,在找到对象
select a.owner,a.segment_name,count(*) from
dba_extents a,
(select dbarfil,dbablk from x$bh where hladdr in('699B50C0' ,'699A5640' ,'69997600' ,'699B7B80' )) b
where a.RELATIVE_FNO = b.dbarfil
and a.BLOCK_ID <= b.dbablk and a.block_id + a.blocks > b.dbablk
group by a.owner,a.segment_name;
OWNER SEGMENT_NAME COUNT(*)
------------------------------ -------------------- ----------
SYS C_TOID_VERSION# 4
SYS I_OBJ# 1
SYS IDL_SB4$ 1
SCOTT T1 9
SYS C_OBJ# 1
其中scott.t1表是我们自己的业务表。有9个块,因为我们只取了前几位的地址。
可以判断scott.t1为热点。
虽然t1表在内存中,我们可以命中,但要读取,还要通过latch,如果应用太集中,
都访问一个表,必然造成这个结果。
现在不是内存小了,而是访问模式太集中了,现象为cpu的负载过高。latch丢失严重。
解决的办法为分散应用,增加或者减少索引!
SQL> create bitmap index scott.i1 on scott.t1(deptno);
索引已创建。
SQL> select name,gets,misses from v$latch where name='cache buffers chains';
NAME GETS MISSES
------------------------------------------ ---------- ----------
cache buffers chains 131912045 12869688
--现在我们再次在10个会话中运行刚才的测试程序。等结束后再次查询。
NAME GETS MISSES
------------------------------------------ ---------- ----------
cache buffers chains 132112739 12869695
发现只有极少的增加,可以忽略不计。原来增加了600万的misses.
总结:
从这个小实验,我们懂得了什么是热点块。
通过改变sql的运行来改变热点。
数据库优化无止境!要多揣摩,多动手,多思考!
pxboracle@live.com
2014.08.11 13:28
share you knowledge with the world.
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/12798004/viewspace-1249146/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/12798004/viewspace-1249146/