Oracle latch vs lock
latch lock
队列行 无队列性 队列性
时长 很短 可能很长
层面 数据库资源层 业务应用层
目的 保证资源的完整性 保证业务操作的完整性
latch在sga中,并不会存在pga中,因为sga中才会存在并发。
latch主要存在两块:
共享池
- sql解析,sql重用
数据缓冲区
-数据访问,数据写入,数据读入
-修改数据块
-数据段扩展
latch获取方式
wait方式--如果无法获取请求的latch,则
1.spin
当一个会话无法获得需求的latch时,会继续使用cpu(cpu空转),达到一个间隔时,会
在此尝试申请latch,知道达到最大重试次数。
2.sleep
当一个会话无法获取需要的latch时,会等待一段时间,达到一个间隔时,在此尝试申请latch,
如此反复,知道达到最大的重试次数。
第一种是系统可以认为立马下次可以获取到latch,而第二种则sleep一段时间后再进行获取
Nowait方式
--如果无法获取请求的latch,则
不会发生sleep或者spin
转而获取其他的可用latch
对于绑定变量,olap中没必要使用绑定变量,因为sql执行不会太多。
而oltp中,建议使用绑定变量。
data buffer中的latch争用
1.表数据块争用。
2.热块索引数据热块
3.文件头修改 --并发修改
模拟下表数据块的争用
admin@ORCL> create table latch_table1 as select * from dba_objects;
Table created.
--创建访问的存储过程
admin@ORCL> create or replace procedure p1 as
2 l number;
3 begin
4 for i in 1 .. 8000 loop
5 select count(*) into l from latch_table1 where object_type = 'TABLE';
6 end loop;
7 dbms_output.put_line('successfully');
8 end;
9 /
Procedure created.
--三个会话同时执行访问latch表
admin@ORCL> select distinct sid from v$mystat;
SID
----------
10
admin@ORCL> exec p1;
admin@ORCL> select distinct sid from v$mystat;
SID
----------
192
admin@ORCL> exec p1;
admin@ORCL> select distinct sid from v$mystat;
SID
----------
71
admin@ORCL> exec p1;
--捕获到PID 33在访问时遇到了latch争用的情况。
PID:持有lantch的进程。
SID:持有latch的会话。
LADDR:latch的地址
NAME:latch的名称
GETS:获得latch的次数。
admin@ORCL> select * from v$latchholder;
PID SID LADDR NAME GETS
---------- ---------- -------------------- -------------------- ----------
33 71 000007FF0E175D80 cache buffers chains 88877
--看在会话等待事件视图中总是有这3个会话的“latch 链表”的争用,原因当多个会话同时去访问相同数据块时,它们首先申请latch获得访问权限,
如果此时申请失败,将会产生“latch: cache buffers chains”等待事件,这是因为多个会话在争抢latch资源所致
admin@ORCL> select SID,EVENT from V$SESSION_WAIT where wait_class <> 'Idle';
SID EVENT
---------- ----------------------------------------------------------------
10 latch: cache buffers chains
71 latch: cache buffers chains
192 latch: cache buffers chains
--创建三个存储过程,测试下数据块修改导致的事件
admin@ORCL> create or replace procedure p2
2 as
3 l number;
4 begin
5 for i in 1..100
6 loop
7 update latch_table1 set object_type='TABLE' where object_type='TABLE';
8 end loop;
9 dbms_output.put_line('successfully');
10 end;
11 /
Procedure created.
admin@ORCL> create or replace procedure p3
2 as
3 l number;
4 begin
5 for i in 1..100
6 loop
7 update latch_table1 set object_type='INDEX' where object_type='INDEX';
8 end loop;
9 dbms_output.put_line('successfully');
10 end;
11 /
Procedure created.
admin@ORCL> create or replace procedure p4
2 as
3 l number;
4 begin
5 for i in 1..100
6 loop
7 update latch_table1 set object_type='VIEW' where object_type='VIEW';
8 end loop;
9 dbms_output.put_line('successfully');
10 end;
11 /
Procedure created.
--首先可以看出,当DML操作进行之前,访问相同的数据块导致了热块,数据块访问的争用。
我们看到DML操作不仅仅有cache buffer chains,还会产生buffer busy waits。
admin@ORCL> select * from v$latchholder;
PID SID LADDR NAME GETS
---------- ---------- -------------------- -------------------- ----------
31 192 000007FF0E176648 cache buffers chains 5798
admin@ORCL> select * from v$latchholder;
PID SID LADDR NAME GETS
---------- ---------- -------------------- -------------------- ----------
32 10 000007FF0E195158 cache buffers chains 1641739
admin@ORCL> select * from v$latchholder;
PID SID LADDR NAME GETS
---------- ---------- -------------------- -------------------- ----------
33 71 000007FF0E162EC8 cache buffers chains 1761049
admin@ORCL> select SID,EVENT from v$session_wait where wait_class <> 'Idle';
SID EVENT
---------- ----------------------------------------------------------------
10 buffer busy waits
71 buffer busy waits
135 SQL*Net message to client
192 db file sequential read
--针对热块的问题,可以使用minimize records_per_block; 指定每个数据块中可存放行数减少到最小(即4行)
但这样也会导致Oracle会读取更多的数据块来完成查询。
--说明索引数据块中出现热块的场景
create table t1 (id number , name varchar2(200));
drop table t1 purge;
insert into t1 select object_id,object_name from dba_objects;
create index t1_index on t1(id);
execute dbms_stats.gather_table_stats('ADMIN','T1',cascade=>true);
CREATE OR REPLACE PROCEDURE P10
AS
L NUMBER;
BEGIN
FOR I IN 1..50000
LOOP
SELECT COUNT(*) INTO L FROM T1 WHERE ID < 10000;
END LOOP;
DBMS_OUTPUT.PUT_LINE('SUCESSFULLY');
END;
admin@ORCL> select s1.sid, s2.event
2 from v$session s1, v$session_wait s2
3 where s1.sid = s2.sid
4 and s1.status = 'ACTIVE'
5 and s2.event like '%buffer%';
SID EVENT
---------- ----------------------------------------------------------------
6 latch: cache buffers chains
8 latch: cache buffers chains
197 latch: cache buffers chains
--解决办法:创建反向索引