暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Oracle Latch锁

原创 大汉_客家族_小凡仙 2022-11-04
1230

Latch

oracle中,latch是一种轻量级的锁。一般来说,latch由三种内存元素成:pid(进程id),内存地址和内存长度。Latch保证对共享数 据结构的排它性访问,以此来保证内存结构的完整性不受到损坏。在多个会话同时修改或者检视(inspect)sga中同一个内存结构时,必须串行化访问以 保证sga中数据结构的完整性。

image.png

latch的征用是无序的大家不排队而是争抢

资源请求和分配
共享池
–sql解析,sql重用。。。
数据缓冲池
–数据访问,数据写入磁盘,数据读入内存。。。
–修改数据块
–数据段扩展

当高并发来时一个会话申请到一项资源就立刻将它锁上latch据为己有

查询有多少latch
image.png

image.png

Process A holds a latch 进程得到资源并锁定

Process B waits (spins and sleeps) 进程B等待(旋转和睡眠)未获得资源空转
image.png

Latch 的获取

Spin
当一个会话无法获得需要的latch时,会继续使用CPU(cup空转),达到一个时间间隔后再次尝试申请latch,直到达到最大到重试次数。
Sleep
当一个会话无法获得需要到latch时,会等待一段时间(sleep),达到一个时间间隔后,再次尝试申请latch,如此反复,直到达到最大的重试次数。

No wait方方式 --如果无法获取请求的latch,则:
-不会发生sleep 或者spin。
-转而获取其它的latch

Shared pool里的lacth争用

SQL> create or replace procedure p1 2 as 3 l_cnt number; 4 begin 5 for i in 1 .. 10000 6 loop 7 execute immediate 'select count(*) from t where x=' || i into l_cnt; 8 end loop; 9 end; 10 / Procedure created. SQL> create or replace procedure p2 2 as 3 l_cnt number; 4 begin 5 for i in 1 .. 100000 6 loop 7 select count(*) into l_cnt from t where x = i; 8 end loop; 9 10 end; 11 / Procedure created.

可以看出P1没有绑定变量,P2有绑定变量。

SQL> create global temporary table run_stats 2 (runid varchar2(15), 3 name varchar2(80), 4 value int ) 5 on commit preserve rows; Table created. SQL> create or replace view stats 2 as select 'STAT...' || a.name name,b.value 3 from v$statname a,v$mystat b 4 where a.statistic# = b.statistic# 5 union all 6 select 'LATCH.'|| name, gets 7 from v$latch 8 union all 9 select 'STAT...Elapsed Time',hsecs from v$timer; View created. SQL> create or replace package runstats_pkg 2 as 3 procedure rs_start; 4 procedure rs_middle; 5 procedure rs_stop(p_difference_threshold in number default 0); 6 end; 7 / Package created.

创建全局临时表表包和视图用来观察

打开会话追踪

SQL> alter session set sql_trace = true; Session altered. SQL> exec p1; PL/SQL procedure successfully completed. SQL> exec p2; PL/SQL procedure successfully completed.

image.png

几乎所有项目第二个资源消耗都要远远小于第一个资源说明绑定变量和没绑定变量区别

orap分析系统没有什么问题性能问题不大
Ortp 连机交易系统需要绑定变量容易产生性能问题

buffer cache争用问题

image.png

数据块在内存区有DBWR进程会访问,会受到业务会话访问。当很多会话并发访问时间就是出现latch。
image.png

数据块首先要从磁盘上从数据文件里读内存里,通过哈希算法打散。变成散列。通过哈希算法存储在相应地址
比如图中有个一个块头是437,文件号是437。通过哈希算法算出2((1+437)mod 4 = 2);
这里到2就指像文件头了

SQL> desc X$bh Name Null? Type ----------------------------------------- -------- ---------------------------- ADDR RAW(8) INDX NUMBER INST_ID NUMBER HLADDR RAW(8) BLSIZ NUMBER **NXT_HASH RAW(8) PRV_HASH RAW(8)** NXT_REPL RAW(8) PRV_REPL RAW(8) FLAG NUMBER FLAG2 NUMBER LOBID NUMBER RFLAG NUMBER SFLAG NUMBER LRU_FLAG NUMBER TS# NUMBER FILE# NUMBER DBARFIL NUMBER DBABLK NUMBER CLASS NUMBER STATE NUMBER MODE_HELD NUMBER CHANGES NUMBER CSTATE NUMBER LE_ADDR RAW(8) DIRTY_QUEUE NUMBER SET_DS RAW(8) OBJ NUMBER BA RAW(8) CR_SCN_BAS NUMBER CR_SCN_WRP NUMBER CR_XID_USN NUMBER CR_XID_SLT NUMBER CR_XID_SQN NUMBER CR_UBA_FIL NUMBER CR_UBA_BLK NUMBER CR_UBA_SEQ NUMBER CR_UBA_REC NUMBER CR_SFL NUMBER CR_CLS_BAS NUMBER CR_CLS_WRP NUMBER LRBA_SEQ NUMBER LRBA_BNO NUMBER HSCN_BAS NUMBER HSCN_WRP NUMBER HSUB_SCN NUMBER US_NXT RAW(8) US_PRV RAW(8) WA_NXT RAW(8) WA_PRV RAW(8) OQ_NXT RAW(8) OQ_PRV RAW(8) AQ_NXT RAW(8) AQ_PRV RAW(8) OBJ_FLAG NUMBER TCH NUMBER TIM NUMBER CR_RFCNT NUMBER SHR_RFCNT NUMBER

基表里标红到两个就是数据块头

NXT_HASH PRV_HASH


000000006D5A9FE0 000000006D5A9FE0
000000006D5AA040 000000006D5AA040
000000006D5AA060 000000006D5AA060
000000006D5AA0B0 000000006D5AA0B0
000000006D5AA0C0 000000006D5AA0C0
000000006D5AA0D0 000000006D5AA0D0
000000006D5AA0E0 000000006D5AA0E0
000000006D5AA0F0 000000006D5AA0F0
000000006D5AA110 000000006D5AA110
000000006D5AA170 000000006D5AA170
000000006D5AA1E0 000000006D5AA1E0

NXT_HASH下一个数据块头地址,PRV_HASH上一个数据块头地址!
image.png

访问数据块先申请一个latches,
image.png
image.png

1.Hash the block address
先把数据块文件头做一个哈希
2.Get buket latch
获得一个latc
3.Look for header
通过hash列表就能找的文件头
4.Found read block in cache
5.Not found read block off disk
在高速缓存中找到读块
未找到磁盘上的读块
image.png

S1、2、3、4、5都去访问一个数据块这就是热块争用,一个申请到了其它到就只有先等待。

出现热块就是

image.png
image.png
访问的会话太多文件头有事务槽ITL(Interested Transaction List)满了,就需要等待!
image.png

因为uodate没有提交,搜索的会话争用资源形成Latch
桶中的缓冲区太多

Latch相关的视图–V$LATCH

V$latch
这个视图实际上是oracle对每一个latch的统计信息的一个汇总,每一条记录表示一种latch.

NAME GETS MISSES SLEEPS IMMEDIATE_GETS IMMEDIATE_MISSES ---------------------------------------------------------------- ---------- ---------- ---------- -------------- ---------------- cached attr list 0 0 0 0 0 cache buffers lru chain 20030 0 0 191461 98 cache buffers chains 3049868 3 0 123803 1 cache buffer handles 1198 0 0 0 0 cache protection latch 0 0 0 0 0 cache table scan latch 1056 0 0 1056 0 6 rows selected.

NAME:latch名称
IMMEDIATE_GETS:以Immediate模式latch请求数
IMMEDIATE_MISSES:请求失败数
GETS:以Willing to wait请求模式latch的请求数
MISSES:初次尝试请求不成功次数
SPIN_GETS:第一次尝试失败,但在以后的轮次中成功
SLEEP[x]:成功获取前sleeping次数
WAIT_TIME:花费在等待latch的时间

SQL> desc v$latchholder Name Null? Type ----------------------- -------- ---------------- PID NUMBER SID NUMBER LADDR RAW(8) NAME VARCHAR2(64) GETS NUMBER

PID:持有LATCH的进程ID
SID:拥有LATCH的会话ID
LADDR:LATCH地址
NAME:LATCH的名字
GETS:在WAIT模式或NO-WAIT模式下,获取LATCH的次数
CON_ID:容器ID

V$latch_children

数据类型 描述
addr RAW(4 , 8) 闩锁对象的地址
LATCH# NUMBER 父级闩锁的闩锁编号
CHILD# NUMBER 子锁存器编号(仅对每个父锁存器唯一)
LEVEL# NUMBER 闩锁级别
NAME VARCHAR2(50) 闩锁名称
HASH NUMBER 锁存哈希
GETS NUMBER 在愿意等待模式下请求锁存器的次数
MISSES NUMBER 在愿意等待模式下请求闩锁且请求者必须等待的次数
SLEEPS NUMBER 愿意等待的闩锁请求导致会话在等待闩锁时进入睡眠状态的次数
IMMEDIATE_GETS NUMBER
IMMEDIATE_MISSES NUMBER 无等待闩锁请求未成功(即丢失)的次数
WAITERS_WOKEN NUMBER 该列已被弃用,仅出于与Oracle早期版本的兼容性而出现。该列没有任何数据积累;它将始终为零。
WAITS_HOLDING_LATCH NUMBER 该列已被弃用,仅出于与Oracle早期版本的兼容性而出现。该列没有任何数据积累;它将始终为零。
SPIN_GETS NUMBER 愿意等待的闩锁请求错过了第一次尝试,但在旋转时成功了
SLEEP[1 , 2 , 3] NUMBER 这些列已被弃用,仅出于与Oracle早期版本的兼容性而存在,这些列未积累任何数据;它们将始终为零。作为这些列的替代,您可以查询V$EVENT_HISTOGRAM视图中相应EVENT列的值为latch free或的行latch:%。
SLEEP4 NUMBER 该列已被弃用,仅出于与Oracle早期版本的兼容性而出现。该列没有任何数据积累;它将始终为零。作为该列的替代,您可以查询V$EVENT_HISTOGRAM视图中相应EVENT列的值为latch free或的行latch:%。
SLEEP[5 , 6, 7 , 8 , 9 , 10 , 11] NUMBER 这些列已被弃用,仅出于与Oracle早期版本的兼容性而存在。这些列没有任何数据累积。
WAIT_TIME NUMBER

模拟

创建测试用存储过程

Create or replace procedure dummy is begin null; end; / 开启session 1 Begin Dummy; Dbms_lock.sleep(1000); End; / 开启session 2 alter procedure dummy compile; => session 2 将会被 'library cache pin' 堵塞。 ---开启session 3 alter procedure dummy compile; => session 3 将会被 'library cache lock'堵塞。 开启session 4 select * from (select event,total_waits,time_waited,TIME_WAITED_MICRO,AVERAGE_WAIT,TOTAL_TIMEOUTS from v$system_event where wait_class <> 'Idle' order by 3 desc) where rownum<=50;

image.png

「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论