博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
通过案例学调优之--和 BUFFER CACHE 相关的主要 Latch
阅读量:6339 次
发布时间:2019-06-22

本文共 11214 字,大约阅读时间需要 37 分钟。

2.1、和 BUFFER CACHE 相关的主要 Latch 有:
Latch:cache buffers lru chain
Latch: cache buffers chains既然Latch是用来保护共享内存块不被并行破坏,那就了解BUFFER CACHE的相关原理,进 而得知什么时候需要用到这个Latch,才能够有相应的解决方案。

2.2BUFFER CACHE 是用来缓存数据块的地方,那么数据的查询和修改都要通过它来完成。 接下来就看看访问数据的流程是怎样的:


2.2.1当一个进程要访问数据时,首先要查找 BUFFER CACHE 看看数据是否已经存在?

(Y) 如果数据在 BUFFER CACHE 中存在,则根据数据的状态来判断是否可以直接访问 还是需要构造一致性读取?

(N) 如果数据在 BUFFER CACHE 中不存在,则需要从数据文件中读取数据块到 BUFFER CACHE 中去。这个时候,需要查找在 BUFFER CACHE 中寻找足够的内存空间来读取相关的数 据。
2.2.2现在 BUFFER CACHE 那么大,一个 BUFFER 一个 BUFFER 的扫描过去是相当的消耗资源以及查 询的时间,那我们怎样才能快速地查到数据了?
可以看看下面关于 
BUFFER CACHE 的示图:

这边我们先看下面几点:
1) 图中右边的有一块 Buffers Memory,其中每一块小格就是一个 Buffer(用来存放从数据文

件中读取的数据块 Block)

2)  图中左边的有许多 Buffer Header 用虚线指向 Buffers Memory 中的相应的 Buffer

3)  图中左边的有许多实线箭头,这些箭头(其实就是数据结构的链表结构中的指针)将不 同的 Buffer Header 连接成一条 Hash Chain,这边也就是 Cache Buffers Chain(双向链表)。

4)  另外,还有一个 Hash Bucket,其实这只是一个逻辑上的概念,即每一个 Hash Bucket 都 会有一条 Hash Chain 来将 Buffer Header(按照 HASH 算法分类后)连接起来,并由一个Cache Buffers Chains Latch 来进行管理其并发操作。

每当将一个Block读入到Buffer Cache的时候,首先会构造一个与之对应的Buffer Header, 然后根据 HASH 算法( Hash Bucket = MOD(Data Block Address, _DB_BLOCK_HASH_BUCKETS) ), 将 Buffer Header 放到对应的 Hash Bucket 的 Cache Buffers Chain 中去,并在 Buffer Header 中 存放如下信息:

5) 最后,在看看 Hash Latch,即 Cache Buffers Chains Latch,在 Oracle 8i 之前,对应每一个Hash Bucket,Oracle使用一个独立的Latch来维护。Oracle 8i开始,Oracle增加了Hash Bucket 的数量,这样每个 Latch 需要维护多个 Bucket,由于每个 Hash Bucket 上的 Buffer Header 数量大大减低,也使得Latch 的性能反而提高。其中,BUFFER CACHE 中 Hash Bucket的个数由隐含参数_db_block_hash_buckets 决定,Cache Buffers Chains Latch 的个数由隐 含参数_db_block_hash_latches 决定。

2.2.3现在再回过头,看看怎样查找 BUFFER CACHE 看看数据是否已经存在?

(Y) 如果数据在 BUFFER CACHE 中存在的情况。
1) 根据要查找的数据块的 DBA 等信息,通过上面给的 HASH 算法( Hash Bucket = MOD(Data

Block Address, _DB_BLOCK_HASH_BUCKETS) ),得到该数据块所在的 Hash Bucket
2) 定位到对应的 Hash Bucket 上,在该 Hash Bucket 对应的 Cache Buffers Chain 中加上 Cache Buffers Chains Latch,然后从 Cache Buffers Chain 对应的第一个 Buffer Header 开始扫描查 找,直至之后一个。在这个扫描查找过程中,为防止对 Cache Buffers Chain 并发访问,

将一直持有 Cache Buffers Chains Latch
在 
Cache Buffers Chain 上查找的具体逻辑如下:


3)获得第 2)步中查到的可以直接访问的 Buffer Header 或者构造一致性读后的 Buffer Header 中的 Buffer 地址到 Buffer Memory 来获得数据。

2.2.4 如果上面在Hash Chain中查找不到对应的Buffer Header的情况下,也就前面的问题的第二 种情况:

(N) 如果数据在 BUFFER CACHE 中不存在,则需要从数据文件中读取数据块到 BUFFER CACHE 中去。这个时候,需要查找在 BUFFER CACHE 中寻找足够的内存空间来读取相关的数 据。
再看看前面给的 
BUFFER CACHE 示例图:
可以看到 
条链(LRU 和 LRUW),这 条分别将 Buffer Header 连接起来,和 Cache Buffers Chain类似。下面看看这 条链的作用:
1)LRU 表示 Least Recently Used,也就是指最近最少使用的 Buffer Header 链表。LRU 链表串 连起来的 Buffer Header 都指向可用数据块(Free Buffer)。
2)LRUW 则表示 Least Recently Used Write,也叫做 Dirty List,也就是脏数据块链表,LRUW串起来的都是修改过但是还没有写入数据文件的内存数据块所对应的 Buffer Header(Dirty Buffer)。
3)一个 Buffer Header 要么在 LRU 上,要么在 LRUW 上,不能同时存在于这两个链表上。

所以,当前面查找数据在 BUFFER CACHE 中不存在的时候(即在 Hash Chain 中查找不到对应 的 Buffer Header 的情况下):
1) 就要扫描 LRU List 寻找 Free 的 Buffer,在扫描过程将持有 Cache Buffers Lru Chain Latch(其

Latch 数量由隐含参数_db_block_lru_latches 决定)。扫描过程中会把已经被修改过的

Buffer 移动到 LRUW 列表上。
2) 找到足够的 Buffer 后,将数据块 Block 读入到 Buffer Cache,构造一个与之对应的 Buffer

Header , 然 后 根 据 HASH 算 法 ( Hash Bucket = MOD(Data Block Address, _DB_BLOCK_HASH_BUCKETS) ),将 Buffer Header 放到对应的 Hash Bucket 的 Cache Buffers Chain 中去,并在 Buffer Header 中存放相关的信息。

2.3、总的在 BUFFER CACHE 中查找数据,可以简单的表示为下图:

2.4 通常有 中情况或导致 Latch 出现竞争:
1) 某一进程长时间的持有 Latch,导致其他进程不能正常的得到 Latch,只能等待。
2) 可能存在大量的 Latch 请求。
2.4.1如果出现 Cache Buffers Chains Latch 竞用严重,根据前面的原理,那么可能有如下原因:1)当多个会话重复访问一个或多个由同一个子Cache Buffers Chains Latch保护的块时热点
块(可以关注 X$BH 中的 TCH 字段)。

2) 大量并发执行的低效 SQL。低效的 SQL 通常需要获取大量的逻辑读,而得到一次逻辑 IO

就得获得一次 Cache Buffers Chains Latch
3Hash Bucket 中存在长的 Cache Buffers Chains,导致查询数据时候,长时间持有 Latch2.4.2
如果出现 Cache Buffers Lru Chain Latch 竞用严重,那么可能有如下原因:
1) 可能 BUFFER CACHE 分配的空间不够,导致读数据到 BUFFER CACHE 的时候,不断的扫描
LRU List

案例分析:

2.5、测试:模拟 Cache Buffers Chains Latch 竞用 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
1
、建立测试table,只有一条记录
14
:
10
:
47 
SCOTT@ prod >select * 
from 
test;
         
N
----------
        
10
 
2
、查看表存储的block信息        
14
:
10
:
50 
SCOTT@ prod >select dbms_rowid.rowid_relative_fno(rowid) file#,dbms_rowid.rowid_block_number(rowid) block# 
from 
test;
     
FILE#     BLOCK#
---------- ----------
         
6        
365
 
3
、建立测试存储过程
14
:
16
:
29 
SCOTT@ prod >create 
or 
replace 
procedure test_latch is
14
:
16
:
30   
2     
i number;
14
:
16
:
30   
3    
begin
14
:
16
:
30   
4      
loop
14
:
16
:
30   
5       
select n 
into 
from 
test;
14
:
16
:
30   
6    
end loop;
14
:
16
:
30   
7    
end;
14
:
16
:
31   
8  
/
Procedure created.
 
4
、建立session测试
14
:
17
:
14 
SCOTT@ prod >select * 
from 
v$mystat 
where 
rownum=
1
;
       
SID STATISTIC#      VALUE
---------- ---------- ----------
         
1          
0          
0
  
5
、执行procedure进行测试         
14
:
17
:
27 
SCOTT@ prod >exec test_latch;
 
6
、查看会话信息(event)
14
:
20
:
38 
SYS@ prod > select sid,event,p1,p1raw,p1text,p2,p2text 
from 
v$session 
where 
sid=
1
       
SID EVENT                                  P1 P1RAW            P1TEXT                       P2 P2TEXT
---------- ------------------------------ ---------- ---------------- -------------------- ---------- --------------------
         
1 
SQL*Net message 
from 
client    
1650815232 
0000000062657100 
driver id                     
1 
#bytes
 
7
、在执行期间可以看到 Cache Buffers Lru Chain Latch 都是 Get 成功,不存在竞争     
14
:
21
:
13 
SYS@ prod >select gets,misses,sleeps,spin_gets,wait_time 
from 
v$latch
14
:
21
:
49   
2      
where 
name=
'cache buffers chains'
;
 
      
GETS     MISSES     SLEEPS  SPIN_GETS  WAIT_TIME
---------- ---------- ---------- ---------- ----------
  
63272697          
0          
0          
0          
0
 
8
、再建立另一个session,执行相同的任务
14
:
23
:
07 
SYS@ prod >conn scott/tiger
Connected.
14
:
23
:
09 
SCOTT@ prod >select * 
from 
v$mystat 
where 
rownum=
1
;
 
       
SID STATISTIC#      VALUE
---------- ---------- ----------
        
56          
0          
0
 
14
:
23
:
22 
SCOTT@ prod >exec test_latch;
        
9
、查看session event             
1
)可以看到出现latch: cache buffers chains等待事件。这就是
2
个session要同时访问同一
个 Block,这个时候在一个会话持有 Latch 的时候,另一个会话必须 Spin 等待获得 Latch。
2
)同时也能看到 cursor: pin S等待事件。 
         
14
:
23
:
42 
SYS@ prod >select sid,event,p1,p1raw,p1text,p2,p2text 
from 
v$session 
where 
sid 
in 
(
1
,
56
);
       
SID EVENT                                  P1 P1RAW            P1TEXT                       P2 P2TEXT
---------- ------------------------------ ---------- ---------------- -------------------- ---------- --------------------
         
1 
latch: cache buffers chains     
850140044 
0000000032AC1B8C address                     
150 
number
        
56 
cursor: pin S                  
3879408699 
00000000E73B143B idn                       
65536 
value
 
14
:
24
:
34 
SYS@ prod >/
       
SID EVENT                                  P1 P1RAW            P1TEXT                       P2 P2TEXT
---------- ------------------------------ ---------- ---------------- -------------------- ---------- --------------------
         
1 
latch: cache buffers chains     
850082532 
0000000032AB3AE4 address                     
150 
number
        
56 
latch: cache buffers chains     
850140044 
0000000032AC1B8C address                     
150 
number
 
14
:
24
:
46 
SYS@ prod >/
       
SID EVENT                                  P1 P1RAW            P1TEXT                       P2 P2TEXT
---------- ------------------------------ ---------- ---------------- -------------------- ---------- --------------------
         
1 
latch: cache buffers chains     
849991208 
0000000032A9D628 address                     
150 
number
        
56 
latch: cache buffers chains     
850231368 
0000000032AD8048 address                     
150 
number
         
14
:
38
:
32 
SYS@ prod >/
 
       
SID EVENT                                  P1 P1RAW            P1TEXT                       P2 P2TEXT
---------- ------------------------------ ---------- ---------------- -------------------- ---------- --------------------
         
1 
cursor: pin S                  
3879408699 
00000000E73B143B idn                     
3670016 
value
        
56 
cursor: pin S                  
3879408699 
00000000E73B143B idn                       
65536 
value
10
、这个时候可以看到 Cache Buffers Lru Chain Latch 都是 Get 出现严重的竞争,出现大量的Misses,Sleeps,Spin_gets:             
14
:
24
:
48 
SYS@ prod >select gets,misses,sleeps,spin_gets,wait_time 
from 
v$latch
14
:
25
:
06   
2  
where 
name=
'cache buffers chains'
;
      
GETS     MISSES     SLEEPS  SPIN_GETS  WAIT_TIME
---------- ---------- ---------- ---------- ----------
 
111686729       
2358       
1293       
1065    
1043230
Elapsed: 
00
:
00
:
00.00
14
:
25
:
18 
SYS@ prod >/
      
GETS     MISSES     SLEEPS  SPIN_GETS  WAIT_TIME
---------- ---------- ---------- ---------- ----------
 
115457171       
2667       
1466       
1202    
1178935
Elapsed: 
00
:
00
:
00.00
14
:
25
:
33 
SYS@ prod >/
      
GETS     MISSES     SLEEPS  SPIN_GETS  WAIT_TIME
---------- ---------- ---------- ---------- ----------
 
115987352       
2722       
1497       
1226    
1204103
Elapsed: 
00
:
00
:
00.00

查看CPU资源信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
[oracle@RH6 ~]$ top
top - 
14
:
42
:
57 
up  
2
:
20
,  
4 
users,  load average: 
2.12
2.14
1.66
Tasks: 
177 
total,   
3 
running, 
174 
sleeping,   
0 
stopped,   
0 
zombie
Cpu(s): 
67.1
%us, 
32.6
%sy,  
0.0
%ni,  
0.0
%id,  
0.0
%wa,  
0.3
%hi,  
0.0
%si,  
0.0
%st
Mem:   1207500k total,  1143680k used,    63820k free,   101824k buffers
Swap:  2064376k total,        0k used,  2064376k free,   778420k cached
  
PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
 
6410 
oracle    
20   
0  
471m  58m  55m R 
49.3  
4.9  
15
:
07.16 
oracle
 
6604 
oracle    
20   
0  
468m  20m  18m R 
49.0  
1.7   
9
:
31.20 
oracle
 
1887 
oracle    
-2   
0  
468m  12m  11m S  
1.0  
1.1   
0
:
23.97 
oracle
 
1937 
oracle    
20   
0  
483m  13m  12m S  
0.3  
1.2   
0
:
00.06 
oracle
    
1 
root      
20   
0  
2828 
1396 
1196 
S  
0.0  
0.1   
0
:
00.81 
init
    
2 
root      
20   
0     
0    
0    
0 
S  
0.0  
0.0   
0
:
00.00 
kthreadd
    
3 
root      RT   
0     
0    
0    
0 
S  
0.0  
0.0   
0
:
00.00 
migration/
0
    
4 
root      
20   
0     
0    
0    
0 
S  
0.0  
0.0   
0
:
00.02 
ksoftirqd/
0
    
5 
root      RT   
0     
0    
0    
0 
S  
0.0  
0.0   
0
:
00.00 
watchdog/
0
    
6 
root      
20   
0     
0    
0    
0 
S  
0.0  
0.0   
0
:
00.12 
events/
0
    
7 
root      
20   
0     
0    
0    
0 
S  
0.0  
0.0   
0
:
00.00 
cpuset

内存信息:

1
2
3
4
5
[oracle@RH6 ~]$ vmstat 
2 
2
procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu-----
 
r  b   swpd   free   buff  cache   si   so    bi    bo   
in   
cs us sy id wa st
 
3  
0      
0  
69756 
101928 
778428  
108    
0     
0    
92  
349  
321 
13  
7 
73  
7  
0
 
2  
0      
0  
69748 
101928 
778428   
64    
0     
0     
0 
1208  
539 
63 
37  
0  
0  
0

附注:

Cursor: Pin S等待,这是一个由于频繁执行SQL共享解析时产生的竞争。当一个会话尝试以共享模式(S - Share)来获得一个游标时,需要修改相应的Mutex结构的引用计数(reference count),或者增加该计数,或者减少。修改引用技术的原子操作很快(其实和Latch的获取释放类似),但是在频繁解析的情况下,仍然产生了竞争和等待,由此就产生了 cursor : pin S 的等待。

这通常是由于某些SQL以超高频繁的频率执行导致的,当然也可能与系统的CPU能力不足有关。

Mutex机制在Oracle 10g引入,用于替代Library cache pin操作,其性能更高,其原理为在每个Child Cursor上分配一个地址空间记录Mutex,当该Cursor被共享执行时,通过将该位进行加一处理来实现。虽然是指游标共享,但是更新Mutex结构的操作需要排他,当某一个SQL被频繁共享执行时,可能就会出现Pin S的等待。

每个Library Cache对象都有一个reference count (引用计数),用来表明有多少其他对象目前正保留一个对它的引用(reference).  对象A 想要引用对象B, A 就把B 的 reference count 加 1。 当A 结束了对B 的引用, A 就把 B 的reference count 减 1.   当没有任何对象再引用 B 时, B 的 reference count就减为0, B 就被清除(deallocated), 内存就被释放。清除B的时候, 被B所用的对象的 reference count 也可能减小, 也可能使它们被清除。

最简单的解决方案是,将频繁执行的SQL分区拆解,分散竞争,如以下SQL通过注释将同一条SQL分解为2条,就分散了竞争:
    select /*SQL 1*/ a from t_a where id=?

    select /*SQL 2*/ a from t_a where id=?
这种做法在Ebay、Papal、支付宝等公司被广泛采用。

在官方文档上这样解释:

A session waits for "cursor: pin S" when it wants a specific mutex in S (share) mode on a specific cursor and there is no concurrent X holder but it could not acquire that mutex immediately. This may seem a little strange as one might question why there should be any form of wait to get a mutex which has no session holding it in an incompatible mode. The reason for the wait is that in order to acquire the mutex in S mode (or release it) the session has to increment (or decrement) the mutex reference count and this requires an exclusive atomic update to the mutex structure itself. If there are concurrent sessions trying to make such an update to the mutex then only one session can actually increment (or decrement) the reference count at a time. A wait on "cursor: pin S" thus occurs if a session cannot make that atomic change immediately due to other concurrent requests. Mutexes are local to the current instance in RAC environments.


本文转自 客居天涯 51CTO博客,原文链接:http://blog.51cto.com/tiany/1575694,如需转载请自行联系原作者
你可能感兴趣的文章
Glide和Govendor安装和使用
查看>>
Java全角、半角字符的关系以及转换
查看>>
Dubbo和Zookeeper
查看>>
前端项目课程3 jquery1.8.3到1.11.1有了哪些新改变
查看>>
UOJ#179. 线性规划(线性规划)
查看>>
整合spring cloud云架构 - SSO单点登录之OAuth2.0登录认证(1)
查看>>
windows的服务中的登录身份本地系统账户、本地服务账户和网络服务账户修改
查看>>
JAVA中循环删除list中元素的方法总结
查看>>
redis 安装
查看>>
SQL some any all
查看>>
电子书下载:Programming Windows Identity Foundation
查看>>
有理想的程序员必须知道的15件事
查看>>
用于测试的字符串
查看>>
财付通和支付宝资料收集
查看>>
理解 IEnumerable 与 IEnumerator
查看>>
NHibernate 2.0 Beta 1 Released和一些工具
查看>>
【每天一个Linux命令】12. Linux中which命令的用法
查看>>
软件接口数据一致性机制
查看>>
微服务架构介绍和RPC框架对比
查看>>
Debian下使用OpenLDAP 管理端
查看>>