全部博文(389)
分类: Oracle
2013-09-06 19:54:28
观察Oracle latch的内存值
oracle通过设置某个内存的地址(实际上是一个变量),来判断某个latch是否可以得到,然后接着执行相关代码。
创建一个表
SQL> create table t1(a int); --create table
SQL> insert into values(10); --insert value
SQL>commit;
接下来得到该表行的数据块地址和文件号
SQL> select dbms_rowid.rowid_block_number(rowid),dbms_rowid.rowid_relative_fno(rowid) from t1;
DBMS_ROWID.ROWID_BLOCK_NUMBER( DBMS_ROWID.ROWID_RELATIVE_FNO(
------------------------------ ------------------------------
99025 1
SQL> select count(*) from t1; --执行一个select 操作
从buffe cache得到保护该块的latch address
SQL> select file#,dbablk,hladdr from x$bh where file#=1 and dbablk=99025;
FILE# DBABLK HLADDR
---------- ---------- ----------------
1 99025 000000008108BBE8
可以看到保护当前buffer的chains buffer chain latch的地址为0x 000000008108BBE8
SQL> oradebug peek 0x000000008108BBE8 16;
[08108BBE8, 08108BBF8) = 00000000 00000000 000A5656 000000CB
从这个值可以判断当前全是0,表示当前没有会话持有该latch,其他会话可以读取这个buffer。
假设我不断的使用一个循环该得到该latch呢,那这个值一定会被置,另外的会话就会在CBC上等待,结果真是这样的吗?接着往下看
SQL> declare
2 i int;
3 b int;
4 begin
5 for i in 1..10000000
6 loop
7 select count(*) into b from t1;
8 end loop;
9
10 end;
11 /
SQL> oradebug peek 0x000000008108BBE8 16;
[08108BBE8, 08108BBF8) = 00000000 00000000 0017418B 000000CB
事实上进行只读的时候,cbc不会被设置,我们把这种方式也叫只读CBC,这是oracle为了增加buffer的并发而改进的一种方式,只是第三个值会一直增加.
当多个会话执行之前的plsql代码段的时候,也不会以独占的方式去持有cbc,这样就可以保证多个会话的并发访问.
会话1.
SQL> declare
2 i int;
3 b int;
4 begin
5 for i in 1..10000000
6 loop
7 select count(*) into b from t1;
8 end loop;
9
10 end;
11 /
会话2
SQL> declare
2 i int;
3 b int;
4 begin
5 for i in 1..10000000
6 loop
7 select count(*) into b from t1;
8 end loop;
9
10 end;
11 /
会话3,
SQL> select event,sid from v$session_wait where wait_class<>'Idle';
EVENT SID
---------------------------------------------------------------- ----------
返回空
再次观察 CBC内存的地址,
SQL> oradebug peek 0x000000008108BBE8 16;
[08108BBE8, 08108BBF8) = 00000000 00000000 00284C24 000000CB
与我们之前的假设一致
如果我们手动来更改内存的地址,看会话会等待什么内容呢?
首先在会话1,查看当前的sid
SQL> select distinct sid from v$mystat;
SID
----------
267
在会话2上面,更改latch address的内容,模拟以exclusive的方式来占用CBC
SQL> oradebug poke 0x000000008108BBE8 8 0xffffffffffffffff;
BEFORE: [08108BBE8, 08108BBF0) = 00000000 00000000
AFTER: [08108BBE8, 08108BBF0) = FFFFFFFF FFFFFFFF
在会话1上,再次执行
SQL>select count(*) from t1;
会话被hang住
在会话2上执行查询
SQL> select event,p1 from v$session where sid=267;
EVENT P1
--------------------------------------- -------------------------
latch: cache buffers chains 2164833256
可以看到会话1一直在CBC上等待,被hang住了.P1的地址为latch的地址.
实验通过cbc来实现的,其他的latch的地址,可以通过v$latchholder可以得到当前持有latch的会话和latch的内存地址信息.