您的位置:首页 > 数据库 > Oracle

Oracle - 使用各种SQL来熟知buffer cache使用情况

2013-04-02 00:57 477 查看
这篇文章是参照甲骨论老相老师的教学视频:
http://v.youku.com/v_show/id_XMzkyMjE3NTA0.html
所做的学习笔记

1. 查看某个对象所占用buffer状态:

上一章提过了, 使用如下语句:

select o.object_name,

decode(state, 0, 'free', 1, 'xcur' , 2, 'scur', 3, 'cr',

4, 'read', 5, 'mrec' , 6, 'irec', 7, 'write',

8, 'pi') as state,

count(1) blocks

from x$bh b, dba_objects o

where b.obj = o.data_object_id

and o.object_name = 'CL_DEPT'

and o.owner = 'HR'

group by o.object_name, state

order by blocks desc;

如图:



如图, 表hr.cl_dept占用6个 xcur状态的buffer, 3个cr状态的buffer啦.

2. 查看某个对象所占用buffer所对应的dbf文件中的block

使用如下语句:

select object_name, DBARFIL, DBABLK

from x$bh a, dba_objects b

where a.obj = b.data_object_id

and b.object_name = 'CL_DEPT'

and b.owner= 'HR';

其中视图x$bh中 DBARFIL 就是知dbf文件编号啦, 而DBABLK就是block的编号

如下图:



可以见到相应地有9个buffer, 但是实际上只有6个 DBABLK编号哦, 因为9个buffer中只有6个xcur状态的buffer啦, 而3个CR 块是不对应dbf文件的.

可以用下面命令来查看数据文件编号啦



3. 查看具体某个BLOCK对应buffer状态
既然上面已经获得了数据文件编号和block的编号, 就可以在x$bh中查看某个BLOCK的状态了.

语句:

select DBARFIL, DBABLK, STATE from x$bh

where DBARFIL = 4

and DBABLK = 175;



可以见到, 在4号dbf文件中, 175编号的block在buffer cache里有4个相关的buffer, 其中只会有1个是状态是xcur的, 其余3个的state是3, 就是3个CR块啦.

4. 查看buffer cache所有对象的buffer占用状态

其实就是第一条sql语句作一些修改就得啦, 不过既然老相老师有讲, 我也写出来吧.

select o.object_name,

decode(state, 0, 'free', 1, 'xcur' , 2, 'scur', 3, 'cr',

4, 'read', 5, 'mrec' , 6, 'irec', 7, 'write',

8, 'pi') as state,

count(1) blocks

from x$bh b, dba_objects o

where b.obj = o.data_object_id

group by o.object_name, state

order by o.object_name, state



group by o.object_name, state

注意, 如果对blocks这个列排序, 就知道baffer_cache哪个对象占用数据最多啦~

5. 查找热块

首先说明一下什么是热块, 之前已经介绍过在buffer cache里所有干净的buffer都会被挂在LRU链, 按照访问次数(逻辑读次数)排序,次数多的在热端, 次数少的在冷端. 所以实在上就是查找访问次数最多的几个buffer

而在x$bh中包含了所有buffers的信息, 其中TCH列意思就是touch, 1个buffer每被逻辑读一次,那么TCH的值就加1, 所以只需按照这个值排序就ok了.

命令如下:

select

o.object_name,

b.dbarfil file#,

b.dbablk block#,

b.tch touches

from x$bh b, dba_objects o

where b.obj = o.data_object_id

and b.tch >0

order by b.tch;



可以见到 JOB$ 这个对象在1号数据文件中2008 和 2008号block 被访问次数最多, 逻辑读发生244次啦~

6. 查找数据库文件所有block的总数

呢个好简单:

select sum(blocks) from dba_data_files;




7. 查看buffer cache可以使用比率

其实这个比率就是 (free buffers的数量+ 干净buffer的数量 )/ buffer的总数

free buffer在 x$bh 中的state 是0, 我们可以根据这个判断.

那么state不是0的可分成干净的和脏的, 我们可以用lrba_seq这个字段来判断

lrba_seq意思是脏buffer第一次变脏时所对应的redo entries在redo log file里的位置.

可以根据lrba_seq来判断,如果lrba_seq=0, 则说明这个buffer是干净的,
否则是脏的

下面这个语句分别列出buffer cache里 空闲,干净,脏的buffer的数量

select decode(state, 0, 'free',

decode(lrba_seq, 0, 'AVAILABLE',

'BEING USED')) as Block_status,

count(1) as Count

from x$bh

group by decode(state, 0, 'free',

decode(lrba_seq, 0, 'AVAILABLE',

'BEING USED'));

如下图: 可以见到干净buffer 有15个(生产中最好控制在10%以内),
SGA太大没好处啦

脏的有23个, 证明物理IO读取很少啦.





8.
查看前10条最耗缓存(逻辑IO最多)的sql语句所占的缓存比率.

在生产中这个比例最好控制在5%以内.

使用如下语句:

select
sum(pct_bufgets) as Percent

from (select rank() over (order
by buffer_gets desc) as rank_bufgets,

to_char(100 * ratio_to_report(buffer_gets) over (),
'999.99') as pct_bufgets

from v$sqlarea)

where rank_bufgets < 11;

简单解析下上面语句啦~

其中rank 是oracle的1个排名的函数,
返回1个排名的值, over()是rank的1个附加条件,

rank() over (order
by buffer_gets desc) 的意思就是返回1个值, 这个值是按照buffer_gets倒序排列的排名整数.

详细用法可以参考这里:
http://docs.oracle.com/cd/E11882_01/server.112/e26088/functions141.htm#SQLRF00690
而ratio_to_report 是 oracle的另1个函数, 作用是返回1个字段的值占这张表这个字段的所有值的比率. 也可以通过over()附加条件..

100
* ratio_to_report(buffer_gets) over () 的意思就是返回某一行buffer_gets值在表里所占的比率啦~

详细用法可以参考这里:
http://docs.oracle.com/cd/B19306_01/server.102/b14200/functions124.htm
而 v$sqlarea 中的字段 buffer_gets就是逻辑读次数的意思啦

执行如下图: 这个比率太大了, 因为是学习用数据库嘛



如果在生产数据库中,这个数字很大, 例如20%以上, 说明有用户执行了若干个占用缓存很大的sql了, 一般来讲执行这种规模的sql语句会托慢数据库的啦.

9.
查看前10条物理IO最多sql语句

select disk_reads, substr(sql_text,1,4000) from v$sqlarea

where rownum <= 10 order by disk_reads desc;

对应buffer_gets, v$sqlarea 字段disk_reads就算物理读次数啦.

所以

select buffer_gets, substr(sql_text,1,4000) from v$sqlarea

where rownum <= 10 order by buffer_gets desc;

就是查看逻辑读次数最多的10条sql.

其实在操作系统级别也有很多工具来查看物理IO的状态啦.

例如:

iostat



vmstat



top



mpstat

这个只查看cpu状态的, mpstat -P n 可以用来查看第n个cpu的状态, 如果系统有多cpu的话



10.
查看buffer_cache每个对象具体占用情况

这条sql语句就复9杂了, 我在视频上也抄不下来, 幸好甲骨论论坛能找到下载, 老相好人啊.

SELECT /*+ ORDERED USE_HASH(o u) MERGE */

DECODE(obj#,

NULL,

to_char(bh.obj),

u.name || '.' || o.name) name,

COUNT(*) total,

SUM(DECODE((DECODE(lru_flag,
8, 1, 0) + DECODE(SIGN(tch - 2), 1, 1, 0)), /*sign用来判断数值的正负*/

2, 1,

1,1,

0)) hot,

SUM(DECODE(DECODE(SIGN(lru_flag
- 8), 1, 0, 0, 0, 1) +DECODE(tch, 2, 1, 1, 1, 0, 1, 0),

2,1,

1,0,

0)) cold,

SUM(DECODE(BITAND(flag, POWER(2,
19)), 0, 0, 1)) fts, /*BITAND函数请见下面注1,POWER函数见注2*/

SUM(tch) total_tch,

ROUND(AVG(tch), 2) avg_tch,
/*round 是四舍5入函数啦*/

MAX(tch) max_tch,

MIN(tch) min_tch

FROM x$bh bh, sys.obj$ o, sys.user$ u

WHERE

bh.obj <> 4294967295

AND bh.state in (1, 2, 3)

AND bh.obj = o.dataobj#(+)

AND bh.inst_id = USERENV('INSTANCE')

AND o.owner# = u.user#(+)

-- AND o.owner# > 5

AND u.name NOT like 'AURORA$%'

GROUP BY DECODE(obj#,

NULL,

to_char(bh.obj),

u.name || '.' || o.name)

ORDER BY total desc

/

注1:

BITAND函数 返回两个数值按位 AND运算的结果, 返回的值是十进制..

BITAND( ) 将 nExpression1 的每一位同 nExpression2 的相应位进行比较。如果 nExpression1 和 nExpression2 的位都是 1,相应的结果位就是 1;否则相应的结果位是 0。

例如 BITAND(6,3) 的结果是2. 因为6的2进制是110, 3是011, 所以and后是 010 就是2啦..

详细请参考:
http://docs.oracle.com/cd/E11882_01/server.112/e26088/functions021.htm#SQLRF00612
注2:

POWER函数就是指数函数啦, 例如Power(3,2) 就是等于3的2次方=9 如果底数小于0 幂必须是整数

可以参考:
http://docs.oracle.com/cd/E11882_01/server.112/e26088/functions129.htm#SQLRF00689
执行效果如下图:



11. 汇总buffer_cache每个对象的各状态buffer个数

这条语句就简单多啦~

SELECT t.name AS tablespace_name,

o.object_name,

SUM(DECODE(bh.status, 'free', 1, 0)) AS free,

SUM(DECODE(bh.status, 'xcur', 1, 0)) AS xcur,

SUM(DECODE(bh.status, 'scur', 1, 0)) AS scur,

SUM(DECODE(bh.status, 'cr', 1, 0)) AS cr,

SUM(DECODE(bh.status, 'read', 1, 0)) AS read,

SUM(DECODE(bh.status, 'mrec', 1, 0)) AS mrec,

SUM(DECODE(bh.status, 'irec', 1, 0)) AS irec

FROM v$bh bh

JOIN dba_objects o ON o.data_object_id = bh.objd

JOIN v$tablespace t ON t.ts# = bh.ts#

GROUP BY t.name, o.object_name

order by xcur desc

效果如下图:



12. 查看buffer_cache每个对象占用多少个buffer,
有多少block被缓存到buffer cache中.

呢个就犀利了, 首先要创建1个试图buffer map

create or replace view buffer_map as

select

o.owner owner,

o.object_name object_name,

o.subobject_name subobject_name,

o.object_type object_type,

count(distinct file# || block#) num_blocks

from

dba_objects o,

v$bh bh

where

o.data_object_id = bh.objd

-- and o.owner not in ('SYS','SYSTEM')

and

bh.status != 'free'

group by

o.owner,

o.object_name,

o.subobject_name,

o.object_type

order by

count(distinct file# || block#) desc

;

跟住就可以用下面语句查询了~

column c0 heading "Owner"                                    format a12
column c1 heading "Object|Name"                              format a30
column c2 heading "Object|Type"                              format a8
column c3 heading "Number of|Blocks in|Buffer|Cache"         format 99,999,999
column c4 heading "Percentage|of object|blocks in|Buffer"    format 999
column c5 heading "Buffer|Pool"                              format a7
column c6 heading "Block|Size"                               format 99,999

select
buffer_map.owner                                          c0,
object_name                                       c1,
case when object_type = 'TABLE PARTITION' then 'TAB PART'
when object_type = 'INDEX PARTITION' then 'IDX PART'
else object_type end c2,
sum(num_blocks)                                     c3,
(sum(num_blocks)/greatest(sum(blocks), .001))*100 c4,
buffer_pool                                       c5,
sum(bytes)/sum(blocks)                            c6
from
buffer_map,
dba_segments s
where
s.segment_name = buffer_map.object_name
and
s.owner = buffer_map.owner
and
s.segment_type = buffer_map.object_type
and
nvl(s.partition_name,'-') = nvl(buffer_map.subobject_name,'-')
group by
buffer_map.owner,
object_name,
object_type,
buffer_pool
having
sum(num_blocks) > 10
order by
sum(num_blocks) desc
;


下面是效果图:



13. 查看buffer_cache当前命中率.

缓存命中率的定义之前都提过啦, 就是缓存中逻辑读的次数/ 逻辑读+ 物理读的总次数.

语句如下:

select (1 -(sum(decode(name,
'physical reads',value,0))/

(sum(decode(name, 'db block gets',value,0))
+ sum(decode(name,'consistent gets',value,0))))

)* 100 as Hit_Radio

from v$sysstat;

解析一下:

官方在线文档基本的定义为如下:

DB block gets:the number of accesses to the current image of a block

Consistent gets:the number of accesses to a read-consistent image of a block

Physical reads:the number of blocks read from disk

这 其中主要涉及到了Oracle读取数据的consistent mode和current mode这两个模式,对于db block gets是在current mode下读取的block数目(单位应该是“块次”,同一个block读取了两个算做2),而consistent gets是在consistent mode下读取的block数目(单位同上)。

current mode下读取数据是为了保证读取到的数据是当前时间点上最新的数据,这样做的目的一般都是为了DML语句的需求,比如需要更新,自然需要知道最新的数据 才行;consistent mode呢主要是为了保证Oracle数据一致读的特性,一般都是在select情况下发生,读到的数据可能是一个实际存在的block,也有可能需要根 据scn信息以及transaction相关信息以及回滚段中数据来构造。

而physical reads是与logical reads相对的一个概念,两者的区别是读取的数据是从buffer中读取到还是从disk上的db file中取到。通过v$sysstat也可以看到,里面还有db block gets from cache以及consistent gets from cache两项,且这两项的数值与db block gets和consistent gets并不相同且小于后两者。所以不管是db
block gets还是consistent gets,都可能出现了physical reads和logical reads两种情况(由buffer中的是否已经存在需要的数据),也即是说,db block gets与consistent gets两者已经构成了一次数据库操作中读取的所有block的总次数了。因此,logical reads自然也就可以通过如下公式算的:logical reads = (db block gets + consistent gets) - physical reads。

注,上面3段转自:http://fengyaping1210.itpub.net/post/39890/486348

执行一下:



在生产中, 这个值一般在98以上,才是正常的

仲有好多, 老相老师话以后再详细讲~
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: