oracle学习笔记 使用各种SQL来熟知buffer cache使用情况

时间:2022-03-14 07:41:29


oracle学习笔记  使用各种SQL来熟知buffer cache使用情况


这节课我们通过一些sql语句更深入的了解一下我们的buffercache


一)几个sql语句


先对select结果进行一下格式化处理
SQL> set pagesize 1000
SQL> set linesize 120
SQL> column object_name format a10


(1)


select distinct object_name,DBARFIL,DBABLK from x$bh a,dba_objects b
where a.obj=b.object_id and object_name='T2';
将t2这个表这个对象使用内存的情况列出来


使用上节课讲的内容查询
select
o.object_name,
decode(state,0,'free',1,'xcur',2,'scur',3,'cr', 4,'read',5,'mrec',
6,'irec',7,'write',8,'pi') state,
count(*) blocks
from x$bh b, dba_objects o
where b.obj = o.data_object_id
and o.object_name = 'T2'
group by o.object_name, state
order by blocks desc;
结果
OBJECT_NAM STATE     BLOCKS
---------- ----- ----------
T2         cr             2
T2         xcur           2
说明t2表在内存有4个块


本节语句执行和输出结果
SQL> select distinct object_name,DBARFIL,DBABLK from x$bh a,dba_objects b
where a.obj=b.object_id and object_name='T2';  2

OBJECT_NAM    DBARFIL     DBABLK
---------- ---------- ----------
T2                  1      62305
T2                  1      62306


结果中列出了t2在内存里面的两个块
对应磁盘上1号文件的62305块和62306块
因为语句中加了唯一约束distinct,结果经过了过滤


将distinct去掉
select object_name,DBARFIL,DBABLK from x$bh a,dba_objects b
where a.obj=b.object_id and object_name='T2';
如果t2表的block块在内存有对应的buffer
则结果输出每个buffer对应的数据文件中的block的对应文件号和块号


执行和结果
SQL> select object_name,DBARFIL,DBABLK from x$bh a,dba_objects b
where a.obj=b.object_id and object_name='T2';  2

OBJECT_NAM    DBARFIL     DBABLK
---------- ---------- ----------
T2                  1      62305
T2                  1      62306
T2                  1      62306
T2                  1      62306


结果中列出了四个列,说明t2的block块对应有四个buffer块在内存
和上节课讲的块状态查询结果相符。


结果说明实际在x$bh里面t2表占4行
但t2在dbf数据文件只是占两个块
因为dbf中两个block
可以对应buffercache中的两个current还可以有两个cr


这个例子告诉大家
虽然某个表有两个块但在内存它可能有4个5个buffer


(2)


select class, flag, state, lru_flag from x$bh
where dbarfil = 1 and dbablk = 62306;


我知道了内存块对应的磁盘块的DBARFIL(块的相对文件号)和DBABLK(在数据文件上的块号)
如1号文件的62305块在内存里面有
我就可以查这个块在内存的状态


SQL> select class, flag, state, lru_flag from x$bh
where dbarfil = 1 and dbablk = 62305;  2

     CLASS       FLAG      STATE   LRU_FLAG
---------- ---------- ---------- ----------
         4          0          1          0
         4          0          0          4

STATE列有一个1为XCUR,一个0为free
也就是62305的block块在内存中对应1个current一个free块
free实际没有占空间



(3)


select
o.object_name,
decode(state,0,'free',1,'xcur',2,'scur',3,'cr', 4,'read',5,'mrec',
6,'irec',7,'write',8,'pi') state,
count(*) blocks
from x$bh b, dba_objects o
where b.obj = o.data_object_id and state <> 0
group by o.object_name, state
order by blocks asc;
把目前buffercache里面的所有对象的内存的占用情况列出来了


这个语句object_name列较长
调整一下结果的输出格式
column object_name format a30


结果内容较长只取其中一部分
OBJECT_NAME                    STATE     BLOCKS
------------------------------ ----- ----------
WRI$_ADV_MESSAGE_GROUPS_PK     xcur           1
RULE_MAP$                      xcur           1
AQ$_QUEUE_TABLES               xcur           1

.
.
REFCON$                        xcur         863
VIEWTRCOL$                     xcur         863
COL$                           xcur         863

436 rows selected.


如结果中
WRH$_SYS_TIME_MODEL            xcur           8
对象WRH$_SYS_TIME_MODEL占用了8个xcur状态块


KOTMD$                         xcur           9
KOTMD$对象在内存里面占了9个xcur块


这个语句中
where b.obj = o.data_object_id and state <> 0
其中state <> 0说明结果中把free状态的块去掉了
如果没有这个条件结果中会有很多对象对应的free状态块


order by blocks asc;
结果以blocks列值大小升序排列
asc为升序排列,换为desc是降序排列
如结果中最后一个对象
COL$                           xcur         863
COL$表在内存里面占用了863个xcur块
从结果中看它占的xcur块数最多


通过这个命令可以将
buffercache里面占用buffer最多的对象给找出来
非常有用
可以知道目前我的buffercache里面有哪些对象
那些对象分别占用了多少的buffer
这是我们关心的


(4)


select decode(wbpd.bp_id,
1,'keep',
2,'recycle',
3,'default',
4,'2k pool',
5,'4k pool',
6,'8k pool',
7,'16k pool',
8,'32k pool',
'unknown') pool,
bh.owner,
bh.object_name object_name,
count(1) numOfBuffers
from x$kcbwds wds,
x$kcbwbpd wbpd,
(select set_ds, x.addr, o.name object_name, u.name owner
from sys.obj$ o, sys.user$ u, x$bh x
where o.owner# = u.user#
and o.dataobj# = x.obj
and x.state != 0
and o.owner# != 0
) bh
where wds.set_id >= wbpd.bp_lo_sid
and wds.set_id <= wbpd.bp_hi_sid
and wbpd.bp_size != 0
and wds.addr = bh.set_ds
--and object_name='T2'
group by decode(wbpd.bp_id,
1,'keep',
2,'recycle',
3,'default',
4,'2k pool',
5,'4k pool',
6,'8k pool',
7,'16k pool',
8,'32k pool',
'unknown'),
bh.owner,
bh.object_name
order by 1, 4, 3, 2;


这个语句和上面的(3)号语句差不多
只不过它做的更详细一些


POOL     OWNER                          OBJECT_NAME                    NUMOFBUFFERS
-------- ------------------------------ ------------------------------ ------------
default  SYSTEM                         AQ$_QUEUES_CHECK                          1
default  SYSTEM                         AQ$_QUEUE_TABLES                          1
.
.
default  SYSMAN                         MGMT_METRICS_1HOUR_PK                    58
default  SYSMAN                         MGMT_METRICS                             81
default  SYSMAN                         MGMT_SEVERITY                           113

91 rows selected.


结果较多只列出一部分
如其中一句
default  SYSMAN                         MGMT_METRICS                             81
属于SYSMAN用户的MGMT_METRICS对象占了81个buffer
其实用(3)号语句就可以了,就够用了


(5)


SELECT
   obj      object,
   dbarfil  file#,
   dbablk   block#,
   tch      touches
FROM
   x$bh
WHERE
   tch > 10
ORDER BY
   tch asc;
为寻找热块


这里面有个热块的概念


默认一个buffer在内存里面会发生很多次逻辑读logic read
每发生一次逻辑读这个块的一个状态touch都会增加


LRU链是最近最少使用链
一端挂的是冷块一端挂的是热块
一个块被逻辑读的次数多就在热端,被逻辑读的次数少就在冷端
判读这个块是冷和热就是根据这个块的touch属性


块的touch值越大说明这个块越热
越热说明这个块被频繁的逻辑读
说明这个块是个热块


上面(5)语句会将我们数据库里面目前所有的块给列出来了
并以touch列升序排列
结果较多只取一部分
    OBJECT      FILE#     BLOCK#    TOUCHES
---------- ---------- ---------- ----------
        40          1        251         11
      8796          3      30884         11
        96          1        722         11
         .
         .
       237          1       1657        362
       237          1       1658        370
       338          1       2682        374

210 rows selected.


1号文件的2682块touches值374目前最热


这个块被访问是因为这个对象被访问
我们可以根据1 和 2682 把对象的名字取出来
先格式化
column object_name format a12
然后使用命令:
select object_name,DBARFIL,DBABLK from x$bh a,dba_objects b
where a.obj=b.object_id and DBARFIL=1 and DBABLK=2682;
执行结果
OBJECT_NAME     DBARFIL     DBABLK
------------ ---------- ----------
SYS_C00648            1       2682
SYS_C00648            1       2682

说明1号文件 2682块 对应的是SYS_C00648对象
我们发现这个对象目前被最频繁的访问


寻找热块可以把最热的块找到
也可以把热块对应的对象的名字找出来


(6)


select
   sum(blocks)
from
   dba_data_files;
将整个数据库所有数据文件中block的总和取出来
也就是说数据库里面有那么多的数据文件到底有多少个block


执行结果
SUM(BLOCKS)
-----------
     116480

从dba_data_files发现数据库有116480个blocks
目前总计有十几万个block


(7)


select decode(state,0, 'FREE',1,decode(lrba_seq,0,'AVAILABLE','BEING USED'),3,
 'BEING USED', state) "BLOCK STATUS",count(*)
from  x$bh
group by decode(state,0,'FREE',1,decode(lrba_seq,0,'AVAILABLE','BEING USED'),3, 'BEING USED',
state);


这个语句将buffercache里面
这三类块
BEING USED 正在使用的,目前这个块是脏的认为被使用了                                     
FREE   是没有使用的                                        
AVAILABLE  是干净的                                   
把它们占的块数给它们列出来


执行结果
BLOCK STATUS                               COUNT(*)
---------------------------------------- ----------
BEING USED                                      507
AVAILABLE                                      5832
FREE                                           7202

对我们来讲可用的块是
AVAILABLE                                      5832
FREE                                           7202


目前我们来看
因为我使用的库是实验没怎么用,FREE占了百分之五十多
目前buffercache里面仍有大量的空间被剩余


我们有时候要判断目前buffercache到底空间够不够
第一看FREE
free是彻底没用的
free的空间最好在10%以内
free太多了没有意义浪费资源,而且还有些负作用不是很明显但是有副作用
第二看AVAILABLE就是clean干净的
他俩加起来是可用的


BEING USED是dirty脏的由DBWn进程写到磁盘变干净后才能被再次使用



(8)


select sum(pct_bufgets) "Percent"
from (select rank() over ( order by buffer_gets desc ) as
rank_bufgets,to_char(100 * ratio_to_report(buffer_gets) over (),'999.99') pct_bufgets from v$sqlarea )
where rank_bufgets < 11;


将最浪费内存的前十个sql语句所占有的比例输出


结果
   Percent
----------
     51.67


最浪费内存的前十个sql语句它占用内存的比例为51.67


sql语句需要访问对象
前十个sql语句访问内存对象占用了总内存读的51%
这个其实没有很大的意义


有这个例子
是因为我们经常出现
数据库当前负载不是很多只有五六个用户在访问
但是因为某个用户执行了一个大的sql语句
导致数据库速度变得很慢


我们就可以执行这个(8)sql语句
如果查出发现这个数字很高如95%
就确认一点
在前十名里面某一个或多个sql语句它占用非常大的资源
进一步找前十个sql语句分别是谁,一个一个的去判断


通过上面的语句可大体判断出是前十个sql语句有问题
有这么一个小意义,有时会用到


(9)


select disk_reads, substr(sql_text,1,4000) from v$sqlarea  order by disk_reads asc;
找出消耗物理IO资源最大的的SQL语句
给大家列出来,有时候会用到
语句中disk_reads为物理io
以所有sql语句所发生的所造成的物理io顺序给排一下序
我们一般喜欢用升序asc


结果较多只列出一部分
DISK_READS
----------
SUBSTR(SQL_TEXT,1,4000)
----------------------------------------------------------------------------------------------------
         0
SELECT LAST_LOAD_TIME FROM MGMT_TARGETS WHERE TARGET_GUID=:B1

         0
SELECT BLACKOUT_GUID, START_TIME, END_TIME, STATUS FROM MGMT_BLACKOUT_WINDOWS WHERE TARGET_GUID=:B2
AND START_TIME <= :B1

.
.
      1442
select /*+ rule */ bucket, endpoint, col#, epvalue from histgrm$ where obj#=:1 and intcol#=:2 and ro
w#=:3 order by bucket

      3029
select /*+ index(idl_ub1$ i_idl_ub11) +*/ piece#,length,piece from idl_ub1$ where obj#=:1 and part=:
2 and version=:3 order by piece#


435 rows selected.


发现最后的sql语句最消耗物理io,消耗了3029个物理io


如果你发现某个sql语句物理io特别的高的话
就找这个sql语句针对这个sql语句找问题


语句中用到的v$sqlarea视图
持续跟踪所有shared pool中的共享cursor,在shared pool中的每一条SQL语句都对应一列
它记录了shared SQL area中语句统计信息,在分析SQL语句资源使用方面非常重要
我们可以看看它的结构
可以执行desc v$sqlarea;语句
结果较多不列了
如BUFFER_GETS为内存读、逻辑读


通过(9)语句你会发现这个数据库物理io非常忙
当然也可以通过linux操作系统的一些命令观察和判断我们目前的一些情况
如前面讲过的常用的一些操作系统的命令:iostat vmstat top free


这里再介绍一个命令mpstat
先执行一下
[oracle@redhat4 ~]$ mpstat
Linux 2.6.9-78.ELsmp (redhat4)  2016年09月22日

11时16分33秒  CPU   %user   %nice %system %iowait    %irq   %soft   %idle    intr/s
11时16分33秒  all    0.28    0.02    0.39    0.50    0.01    0.00   98.81   1025.73


mpstat是Multiprocessor Statistics的缩写,是实时系统监控工具
在多CPUs系统里,其不但能查看所有CPU的平均状况信息,而且能够查看特定CPU的信息
mpstat最大的特点是:可以查看多核心cpu中每个计算核心的统计数据;
而类似工具vmstat只能查看系统整体cpu情况


mpstat的语法如下
mpstat [-P {cpu|ALL}] [internal [count]]


-P {cpu | ALL} 表示监控哪个CPU, cpu在[0,cpu个数-1]中取值
               为ALL时每个处理器信息都列出,同时也列出所有处理器的总体信息,
无此参数时只列出所有处理器的总体信息
internal 相邻的两次采样的间隔时间,无此参数时结果只输出一次
count 采样的次数,count只能和internal一起使用


当没有任何参数时,mpstat则显示系统启动以后所有信息的平均值
有参数值时如:
mpstat -P ALL 2 5查看多核CPU所有的核心的和每个核心的当前运行状况信息,
每2秒更新一次,显示5次,最后再输出一次执行命令期间的平均值


结果中值的含义
%user     表示处理用户进程所使用 CPU 的百分比。用户进程是用于应用程序(如Oracle数据库)的非内核进程。   
%nice     表示使用 nice 命令对进程进行降级时 CPU 的百分比。 
%system   表示内核进程使用的 CPU 百分比 
%iowait   表示等待进行 I/O 所使用的 CPU 时间百分比 
%irq      表示用于处理系统中断的 CPU 百分比 
%soft     表示用于软件中断的 CPU 百分比 
%idle     显示 CPU 的空闲时间 
%intr/s   显示每秒 CPU 接收的中断总数


这个命令老师用的很多
列一些用法
mpstat 1 10
列出所有处理器的总体信息,1秒输出一次,共输出10次,最后再输出一下这十次的平均值


mpstat -P 0 1
列出0号处理器的信息,1秒输出一次,直到用户把这个命令停止,这里可以使用Ctrl+C完成


我的实验环境有两个cpu
上面我把零号cpu的使用情况列出来了
也可以把1号cpu的使用情况列出来
mpstat -P 1 1


mpstat对多cpu的环境非常有用


如果把语句(9)disk_reads可以改写为BUFFER_GETS


select BUFFER_GETS, substr(sql_text,1,4000) from v$sqlarea  order by BUFFER_GETS asc;


找出消耗逻辑读资源最大的SQL语句


结果中最后部分:
BUFFER_GETS
-----------
SUBSTR(SQL_TEXT,1,4000)
------------------------------------------------------------------------------------------------------------------------
.
.
      97945
select intcol#,nvl(pos#,0),col#,nvl(spare1,0) from ccol$ where con#=:1

     101741
select /*+ rule */ bucket_cnt, row_cnt, cache_cnt, null_cnt, timestamp#, sample_size, minimum, maximum, distcnt, lowval,
 hival, density, col#, spare1, spare2, avgcln from hist_head$ where obj#=:1 and intcol#=:2


556 rows selected.


最后一句最消耗资源最消耗BUFFER_GETS就是内存读


内存读主要消耗cpu资源,特别产生一些锁(latch)的争用
物理读主要消耗io资源



(10)


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)),
            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,
 SUM(tch) total_tch,
 ROUND(AVG(tch), 2) avg_tch,
 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
 /


结果为buffercache的具体使用情况
跟前面的语句很相似


直接执行结果较乱,所以先执行
column name format a20
set linesize 160
set pagesize 1000
对select语句进行格式化
另外list命令可显示最近执行的一个sql命令


结果中name列占用空间较多可以使用
SQL> column name format a20
改变它的显示所占用的屏幕宽度为20个字符
它不会截掉多出的部分而是改为多行输出name列
每行的宽度一样,直至此列所有内容输出完


执行结果较多只列出一部分

NAME                      TOTAL        HOT       COLD        FTS  TOTAL_TCH    AVG_TCH    MAX_TCH    MIN_TCH
-------------------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ----------
SYS.ICOLDEP$                841        828         13        767       7397        8.8         75          1
SYS.COLTYPE$                841        828         13        767       7397        8.8         75          1

.
.
SYSMAN.MGMT_NOTIFY_D          1          1          0          0         75         75         75         75
EVICES

SYSMAN.PK_MGMT_JOB_C          1          1          0          0          3          3          3          3
ALLBACKS

SYSMAN.PK_MGMT_JOB_E          1          1          0          0          3          3          3          3
XEC_EVPARAMS


652 rows selected.



它列出了所有的对象以及所有对象的块使用情况
也是进一步通过它来了解buffercache


name列为对象,后面是这个对象使用的各种块的状态



(11)


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


buffer cache中每一个对象的使用情况
也是把内存的使用情况给列出来


先准备一下这个语句的输出格式
SQL> column object_name format a30
SQL> column TABLESPACE_NAME format a10
SQL> set linesize 120


然后执行语句,执行结果较多只列出一部分
TABLESPACE OBJECT_NAME                          FREE       XCUR       SCUR         CR       READ       MREC       IREC
---------- ------------------------------ ---------- ---------- ---------- ---------- ---------- ---------- ----------
SYSTEM     COL$                                  254        841          0          0          0          0          0
SYSTEM     REFCON$                               254        841          0          0          0          0          0
SYSTEM     NTAB$                                 254        841          0          0          0          0          0
.
.
SYSAUX     I_WRI$_OPTSTAT_TAB_OBJ#_ST              3          0          0          0          0          0          0
SYSAUX     WRI$_OPTSTAT_HISTGRM_HISTORY           34          0          0          0          0          0          0
SYSAUX     WRI$_DBU_HIGH_WATER_MARK                1          0          0          0          0          0          0
SYSAUX     SYS_LOB0000008932C00004$$               1          0          0          0          0          0          0

696 rows selected.


结果为对象和对象的使用情况



(12)


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
;


把一些段一些对象具体的对buffercache的使用情况给列出来


老师执行这条语句有正确结果输出
但在我的实验环境中的结果是:

   buffer_map,
   *
ERROR at line 12:
ORA-00942: table or view does not exist

说是没有buffer_map这个表或视图


在我的数据库中寻找名为buffer_map的对象


SQL> select TABLE_NAME from dba_tables where TABLE_NAME like '%BUFFER_MAP%';

no rows selected
数据库中的所有表中没有


SQL> select VIEW_NAME from dba_views where VIEW_NAME like '%BUFFER_MAP%';

no rows selected
数据库的所有视图中没有


SQL> select object_name from dba_objects where object_name like '%BUFFER_MAP%';

no rows selected
甚至数据库中所有的对象中也没有


所以推测这个buffer_map表应该是老师自己建的
我这里就看不到结果了



(13)


REM dbbuffer

select decode(pd.bp_id,1,'KEEP',2,'RECYCLE',3,'DEFAULT',
         4,'2K SUBCACHE',5,'4K SUBCACHE',6,'8K SUBCACHE',
         7,'16K SUBCACHE',8,'32KSUBCACHE','UNKNOWN') subcache,
         bh.object_name,bh.blocks
from x$kcbwds ds,x$kcbwbpd pd,(select /*+ use_hash(x) */ set_ds,
         o.name object_name,count(*) BLOCKS
         from obj$ o, x$bh x where o.dataobj# = x.obj
         and x.state !=0 and o.owner# !=0
         group by set_ds,o.name) bh
where ds.set_id >= pd.bp_lo_sid
and ds.set_id <= pd.bp_hi_sid
and pd.bp_size != 0
and ds.addr=bh.set_ds;

with bh_lc as
       (select /*+ ORDERED */
          lc.addr, lc.child#, lc.gets, lc.misses, lc.immediate_gets,
          lc.immediate_misses, lc.spin_gets, lc.sleeps,
          bh.hladdr, bh.tch tch, bh.file#, bh.dbablk, bh.class,
          bh.state, bh.obj
        from
          x$kslld ld,
          v$session_wait sw,
          v$latch_children lc,
          x$bh bh
        where lc.addr =sw.p1raw
          and sw.p2= ld.indx
          and ld.kslldnam='cache buffers chains'
          and lower(sw.event) like '%latch%'
          and sw.state='WAITING'
          and bh.hladdr=lc.addr
       )
     select bh_lc.hladdr, bh_lc.tch, o.owner, o.object_name, o.object_type,
            bh_lc.child#, bh_lc.gets,
            bh_lc.misses, bh_lc.immediate_gets,
            bh_lc.immediate_misses, spin_gets, sleeps
     from
       bh_lc,
       dba_objects o
     where bh_lc.obj = o.object_id(+)
   union
     select bh_lc.hladdr, bh_lc.tch, o.owner, o.object_name, o.object_type,
            bh_lc.child#, bh_lc.gets, bh_lc.misses, bh_lc.immediate_gets,
            bh_lc.immediate_misses, spin_gets, sleeps
     from
       bh_lc,
       dba_objects o
     where bh_lc.obj = o.data_object_id(+)
  order by 1,2 desc
/


也是把内存对象使用情况列出来


部分结果:
SUBCACHE     OBJECT_NAME                        BLOCKS
------------ ------------------------------ ----------
DEFAULT      RLM$SCHACTIONORDER                      1
DEFAULT      SYS_IOT_TOP_49769                       1
DEFAULT      MGMT_TARGET_PROPERTIES                  3
DEFAULT      MGMT_METRICS_RAW_PK                    24
.
.
DEFAULT      MGMT_DB_LICENSE_ECM_PK                  2
DEFAULT      MGMT_HA_RMAN_CONFIG_ECM                 4
DEFAULT      MGMT_HA_RAC_INTR_CONN_PK                1

389 rows selected.


最后面几个语句没有详细讲,
大家需要将语句列出来执行再详细的看里面的一些结果


上面总共十三个sql语句中老师用的比较多的是(3)号语句,希望大家掌握


讲的不多,只演示一下
只是把语句给大家列出来
同学如果都学过了都熟的话可以直接拿过来用
这里只是告诉大家有这些命令
你也可以知道一些结果
如果没有相关知识现在看结果可能模糊一些



二)dbms_rowid包


dbms_rowid是oracle的一个知识点


有一个表,在磁盘上的一个dbf文件中
表中有三个数据
假设这个表在dbf中占两个块


现在有这么个要求

1、这个表里面的这三行的行地址是多少

行地址就是表中某一行在那个文件的那个块里面的第几行
这叫rowid
就是这个行的物理地址

2、根据表中行只想知道它在那个块里面


实际中有很多这些需求


对表t的操作老师没有实际演示
我在这里对t表的操作也不实际做了只讲一下大概过程


首先创建表t
create table t
    ( a int,
      b varchar2(4000) default rpad('*',4000,'*'),
      c varchar2(3000) default rpad('*',3000,'*' )
    );
插入一些数据
insert into t (a) values ( 1);
insert into t (a) values ( 2);
insert into t (a) values ( 3);
删一些数据
delete from t where a = 2 ;
插入一些数据
insert into t (a) values ( 4);
发现有三行数据
SQL> select a from t;

         A
----------
         1
         4
         3
又插入一些数据
insert into t(a) select rownum from all_users;                            
commit;
更新一些数据
update t set b=null,c=null;
commit;
insert into t(a) select rownum+1000 from all_users;


前面做的是
建了一个表,然后对表进行大量的增删改查


然后访问t表把t表的所有数据列出来
SQL> select dbms_rowid.rowid_block_number(rowid), a from t;


DBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID)          A
------------------------------------ ----------
                               42610          1
                               42611          4
                               42612          3
                               42613          1
                               42613       1017
                               42614          2
                               42614       1016
                               42615          3
                               42615       1015
                               42616          4
                               42616       1014
                               43785          5
                               43785       1013
                               43786          6
                               43786       1012
                               43787          7
                               43787       1011
                               43788          8
                               43788       1010
                               43789          9
                               43789       1009
                               43790         10
                               43790       1008
                               43791         11
                               43791       1007
                               43792         12
                               43792       1006
                               43793         13
                               43793       1005
                               43794         14
                               43794       1004
                               43795         15
                               43795       1003
                               43796         16
                               43796       1002
                               43797         17
                               43797       1001

37 rows selected.


因为过程中使用了系统表all_users所以不同的环境结果会有区别


DBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID)列为表某行所在的块的编号
每一行输出为t表中每一行和对应此行所在的block块的编号
数据共有37行占了好多块


这里用到了dbms_rowid包,是借用别人写的一个存储过程一个函数
这个函数的意义
可以根据表里面的每一行的rowid把它所对应的对象号、文件号、块号、行号全部取出来


例子最后删除了t表
drop table t;


现在做个实际的例子


先把DBMS_ROWID函数给建一下


使用语句
create or replace function get_rowid
(l_rowid in varchar2)
return varchar2
is
ls_my_rowid  varchar2(200);         
rowid_type  number;         
object_number  number;         
relative_fno  number;         
block_number  number;         
row_number  number; 
begin
 dbms_rowid.rowid_info(l_rowid,rowid_type,object_number,relative_fno, block_number, row_number);         
 ls_my_rowid := 'Object# is      :'||to_char(object_number)||chr(10)||
  'Relative_fno is :'||to_char(relative_fno)||chr(10)||
  'Block number is :'||to_char(block_number)||chr(10)||
  'Row number is   :'||to_char(row_number);
 return ls_my_rowid ;
end;

执行成功函数建立


这里使用我们已有的表t2
SQL> select * from t2;

        ID NAME
---------- --------------------
         1 xkj
         2 jiagulun


SQL> select rowid,t2.* from t2;

ROWID                      ID NAME
------------------ ---------- --------------------
AAAM7xAABAAAPNiAAA          1 xkj
AAAM7xAABAAAPNiAAB          2 jiagulun


结果t2有两行
AAAM7xAABAAAPNiAAA为第一行的行地址
AAAM7xAABAAAPNiAAB为第二行的行地址
行地址就是rowid
它包含的信息有
这个行所对应的对象的编号、行所在块的文件编号、行所在块的块号、行号


将rowid加入sql语句
select get_rowid('AAAM7xAABAAAPNiAAB') row_id from dual;


执行它
SQL> select get_rowid('AAAM7xAABAAAPNiAAB') row_id from dual;

ROW_ID
--------------------------------------------------------------------------------
Object# is      :52977
Relative_fno is :1
Block number is :62306
Row number is   :1


根据行的rowid
将它对应的对象编号、文件号、块号和行号给列出来了
结果为
AAAM7xAABAAAPNiAAB的rowid所对应的信息
此行它所在对象的编号Object id是52977
文件号是在1号文件里面
而且在一号文件的62306块里面
还有是第1行


这个包是老师在网上看到的写的不错的一个东西给大家列出来了



三)缓冲区命中率、清空buffer cache 等


还有我们一直关注的关于命中率的概念
命中率高不一定没问题,命中率低一定有问题


查询命中率的语句:

(1)


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 "Hit Ratio"
         from v$sysstat;
执行结果

 Hit Ratio
----------
99.0659252


现在命中率为99
正常的都在98%以上


数据库长期运行我们希望命中率99%以上
长期运行下命中率在98和99之间差的不小就是效率差的很大


如何找一些有问题的sql语句:
(2)


SELECT executions,
buffer_gets,
disk_reads,
first_load_time,
sql_text
FROM v$sqlarea
ORDER BY disk_reads;
它将sharedpool中所有sql语句的情况都给列出了


再给出两个个查询命中率的语句:
(3)


SELECT (P1.VALUE + P2.VALUE - P3.VALUE) / (P1.VALUE + P2.VALUE)
  FROM v$sysstat P1, v$sysstat P2, v$sysstat P3
 WHERE     P1.name = 'db block gets'
       AND P2.name = 'consistent gets'
       AND P3.name = 'physical reads';


(4)


SELECT (P1.VALUE + P2.VALUE - P3.VALUE) / (P1.VALUE + P2.VALUE)
  FROM v$sesstat P1,
       v$statname N1,
       v$sesstat P2,
       v$statname N2,
       v$sesstat P3,
       v$statname N3
 WHERE     N1.name = 'db block gets'
       AND P1.statistic# = N1.statistic#
       AND P1.sid =141
     AND    N2.name = 'consistent gets'
     AND    P2.statistic# = N2.statistic#
     AND    P2.sid = P1.sid
     AND    N3.name = 'physical reads'
     AND    P3.statistic# = N3.statistic#
     AND    P3.sid = P1.sid;


一个查询磁盘中所有数据dbf文件使用情况的语句:
(5)


SELECT A.file_name, B.phyrds, B.phyblkrd
FROM SYS.dba_data_files A, v$filestat B
WHERE B.file# = A.file_id
ORDER BY A.file_id;


这些语句执行都很正常,不写出结果了



清空buffercache使用语句
alter system flush buffer_cache;


执行
SQL> alter system flush buffer_cache;

System altered.


执行的时候很简单
实际上我们将所有的buffer都成free了
这个在生产环境中很危险的
因为接着会发生大量的物理io
在生产上不要轻易的去执行这个命令


在数据库里面
我们可以设置不同的块大小的一些pool
以及不同类型的pool
这些以后讲



这次讲了block和buffer的一些知识
后面的讲的一些sql语句讲的粗糙一些
只是简单执行一下没有详细的讲
还有些内容只是提前给大家提出来了
最后面一块大家可以先不去理他


2016年9月25日

                                    文字:韵筝