V$LATCH
字段说明:
gets表示总共有这么多次请求,misses表示请求失败的次数(加锁不成功),而sleeps 表示请求失败休眠的次数,通过sleeps我们可以大体知道数据库中latch的竞争是否严重,这也间接的表征了热点块的问题是否严重
查看与热块有关的latch信息(cache buffer%):
SQL> SELECT latch#, NAME, gets, misses, sleeps
2 FROM v$latch
3 WHERE NAME LIKE 'cache buffer%';
LATCH# NAME GETS MISSES SLEEPS
---------- -------------------------------------------------- ---------- ---------- ----------
123 cache buffer handles 759 0 0
117 cache buffers lru chain 96611 12 12
122 cache buffers chains 2253780 4 4
V$LATCH_CHILDREN
包含子latch的信息,如果子latch的latch#列值相同,则说明他们有相同的父latch。
查看子latch信息(cache buffers chains):
SQL> SELECT addr, LATCH#, CHILD#, gets, misses, sleeps
2 FROM v$latch_children
3 WHERE NAME = 'cache buffers chains'
4 AND rownum < 21;
ADDR LATCH# CHILD# GETS MISSES SLEEPS
-------- ---------- ---------- ---------- ---------- ----------
290C07C4 122 1 2426 0 0
290C0940 122 2 589 0 0
290C0ABC 122 3 2701 0 0
290C0C38 122 4 1844 0 0
290C0DB4 122 5 1214 0 0
290C0F30 122 6 652 0 0
290C10AC 122 7 4897 0 0
290C1228 122 8 3474 0 0
290C13A4 122 9 977 0 0
290C1520 122 10 4210 0 0
290C169C 122 11 3392 0 0
290C1818 122 12 2913 0 0
290C1994 122 13 385 0 0
290C1B10 122 14 822 0 0
290C1C8C 122 15 2333 0 0
290C1E08 122 16 4714 0 0
290C1F84 122 17 1001 0 0
290C2100 122 18 419 0 0
290C227C 122 19 1735 0 0
290C23F8 122 20 1105 0 0
20 rows selected
根据v$latch_child.addr关联到对应的x$bh.hladdr(这是buffer header中记录的当前buffer所处的latch地址),通过x$bh可以获得块的文件编号和block编号。
SQL> SELECT dbarfil, dbablk
2 FROM x$bh
3 WHERE hladdr IN (SELECT addr
4 FROM (SELECT addr, LATCH#, CHILD#, gets, misses, sleeps
5 FROM v$latch_children
6 WHERE NAME = 'cache buffers chains'
7 ORDER BY sleeps DESC)
8 WHERE rownum < 11);
DBARFIL DBABLK
---------- ----------
1 55375
4 8500
3 756
3 5094
2 1455
1 50338
1 2154
3 30656
1 6492
3 4395
……
104 rows selected
SQL>
SQL> SELECT dbarfil, dbablk
2 FROM x$bh
3 WHERE hladdr IN
4 (SELECT addr
5 FROM (SELECT addr FROM v$latch_children ORDER BY sleeps DESC)
6 WHERE rownum < 11);
DBARFIL DBABLK
---------- ----------
1 55375
4 8500
3 756
3 5094
2 1455
1 50338
1 2154
3 30656
1 6492
3 4395
2 769
……
37 rows selected
知道了文件编号和block编号,可以通过dba_extents获取相关的segment。
SQL> SELECT DISTINCT a.owner, a.segment_name, a.segment_type
2 FROM dba_extents a,
3 (SELECT dbarfil, dbablk
4 FROM x$bh
5 WHERE hladdr IN
6 (SELECT addr
7 FROM (SELECT addr, LATCH#, CHILD#, gets, misses, sleeps
8 FROM v$latch_children
9 WHERE NAME = 'cache buffers chains'
10 ORDER BY sleeps DESC)
11 WHERE rownum < 11)) b
12 WHERE a.RELATIVE_FNO = b.dbarfil
13 AND a.BLOCK_ID <= b.dbablk
14 AND a.block_id + a.blocks > b.dbablk
15 AND a.owner = 'OCP';
OWNER SEGMENT_NAME SEGMENT_TYPE
------------------------------ -------------------------------------------------------------------------------- ------------------
OCP T TABLE
SQL> SELECT DISTINCT a.owner, a.segment_name, a.segment_type
2 FROM dba_extents a,
3 (SELECT dbarfil, dbablk
4 FROM x$bh
5 WHERE hladdr IN
6 (SELECT addr
7 FROM (SELECT addr FROM v$latch_children ORDER BY sleeps DESC)
8 WHERE rownum < 11)) b
9 WHERE a.RELATIVE_FNO = b.dbarfil
10 AND a.BLOCK_ID <= b.dbablk
11 AND a.block_id + a.blocks > b.dbablk
12 AND a.owner = 'OCP';
OWNER SEGMENT_NAME SEGMENT_TYPE
------------------------------ -------------------------------------------------------------------------------- ------------------
OCP T TABLE
SQL>
在v$sqlarea或者v$sqltext里找到与热点块有关的sql进行优化。
其实也就是下面的语句:
SELECT sql_text
FROM v$sqltext a
WHERE a.sql_text LIKE '%t%'
ORDER BY a.hash_value, a.address, a.piece;
SELECT sql_text
FROM v$sqltext a,
(SELECT DISTINCT a.owner, a.segment_name, a.segment_type
FROM dba_extents a,
(SELECT dbarfil, dbablk
FROM x$bh
WHERE hladdr IN (SELECT addr
FROM (SELECT addr,
LATCH#,
CHILD#,
gets,
misses,
sleeps
FROM v$latch_children
WHERE NAME = 'cache buffers chains'
ORDER BY sleeps DESC)
WHERE rownum < 11)) b
WHERE a.RELATIVE_FNO = b.dbarfil
AND a.BLOCK_ID <= b.dbablk
AND a.block_id + a.blocks > b.dbablk
AND a.owner = 'OCP') b
WHERE a.sql_text LIKE '%' || b.segment_name || '%'
AND b.segment_type = 'TABLE'
ORDER BY a.hash_value, a.address, a.piece;
SELECT sql_text
FROM v$sqltext a,
(SELECT DISTINCT a.owner, a.segment_name, a.segment_type
FROM dba_extents a,
(SELECT dbarfil, dbablk
FROM (SELECT dbarfil, dbablk FROM x$bh ORDER BY tch DESC)
WHERE rownum < 11) b
WHERE a.RELATIVE_FNO = b.dbarfil
AND a.BLOCK_ID <= b.dbablk
AND a.block_id + a.blocks > b.dbablk) b
WHERE a.sql_text LIKE '%' || b.segment_name || '%'
AND b.segment_type = 'TABLE'
ORDER BY a.hash_value, a.address, a.piece;
SELECT dbarfil, dbablk FROM x$bh ORDER BY tch DESC
x$bh.tch (touch count)大的block可能暗示着在当前某个周期内被访问次数比较多。
查看访问次数比较多的块所在对象:
SELECT t.owner, t.object_name, t2.dbarfil, t2.dbablk,t2.tch
FROM dba_objects t, x$bh t2
WHERE t.data_object_id = t2.obj
AND owner = 'OCP'
AND t2.ts# > 0 --ts#表示表空间块号,是什么意思呢?
ORDER BY t2.tch DESC
查看访问次数比较多的对象:
SELECT *
FROM (SELECT o.owner, o.object_name, SUM(tch) TouchTime
FROM x$bh b, dba_objects o
WHERE b.obj = o.data_object_id AND o.owner='OCP'
AND b.ts#>0 --ts#表示表空间块号,,是什么意思呢?
GROUP BY o.owner, o.object_name
ORDER BY SUM(tch) DESC)
WHERE rownum <= 10
除了优化sql外,当然对于热点的表或者索引来说,如果小的话,我们可以考虑cache在内存中,这样可能降低物理读提高sql运行速度(这并不会减少cache buffer chains的访问次数),对于序列,我们可以对序列多设置一些cache。如果是并行服务器环境中的索引对象,并且这个索引是系列递增类型,我们可以考虑反向索引。