1. 程式人生 > >oracle學習筆記 使用各種SQL來熟知buffer cache使用情況

oracle學習筆記 使用各種SQL來熟知buffer cache使用情況



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
先執行一下
[[email protected] ~]$ 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日

                                    文字:韻箏