1 buffer cache的設置優化
buffer cache的設置隨着oracle版本的升級而不斷變化。8i下使用db_block_buffers來設置,該參數表示buffer cache中所可以包含的內存數據塊的個數;9i之後使用db_cache_size來設置,該參數表示buffer cache的總共的容量,能夠用字節、K、M爲單位來進行設置。而到了10g之後則更加簡單,甚至能夠不用去單獨設置buffer cache的大小。由於10g引入了ASMM(Automatic Shared Memory Management)這樣一個能夠進行自我調整的組件,該組件能夠自動調整shared pool size、db cache size等SGA中的組件。只須要設置sga_target參數,則其餘組件就可以根據系統的負載和歷史信息自動的調整各個部分的大小。要啓動ASMM,只須要設置statistics_level爲typical或all。
oracle8.0之前只能設置一種buffer cache,而從8.0之後,oracle提供了三種類型的buffer cache,分別是default、keep、recyle。keep和recycle是可選的,default必須存在。8i之前使用db_block_buffer設置default、buffer_pool_keep設置keep、buffer_pool_recycle設置recyle。而8i之後使用db_cache_size設置default、db_keep_cache_size設置keep、db_recycle_cache_size設置recycle。10g不能自動設置db_keep_cache_size和db_recycle_cache_size,必須手工設置。
同時,8i之前,這三種buffer cache是獨立指定的,互不制約。而8i之後,這三種buffer cache是有相互制約關係的。若是指定了keep和recycle的buffer cache,則default類型的buffer cache的大小就是db_cache_size - buffer_pool_keep - buffer_pool_recycle。
一般將常常訪問的對象放入keep類型的buffer cache裏,而將不常訪問的大表放入recycle類型的buffer cache裏。其餘沒有指定buffer cache類型的對象都將進入default類型的buffer cache裏。爲對象指定buffer cache類型的方法以下:
SQL
>
create
table
test (n
number
) storage (buffer_pool keep); SQL
>
alter
table
test storage (buffer_pool recycle);
若是沒有指定buffer_pool短語,則表示該對象進入default類型的buffer cache。
這裏要說明的是,從名字上看,很容易讓人誤覺得這三種buffer cache提供了三種不一樣的管理內存數據塊的機制。但事實上,它們之間在管理和內部機制上沒有任何的區別。它們僅僅是爲DBA們提供了一個選擇,就是可以將數據庫對象分紅「很是熱的」、「比較熱的」和「不熱的」這三種類型。由於數據庫中總會存在一些「很是熱」的對象,它們頻繁的被訪問。而若是某個時候系統偶爾作了一次大表的全表掃描,就有可能將這些對象清除出內存。爲了防止這種狀況的發生,咱們能夠設置keep類型的buffer cache,並將這種對象都移入keep buffer cache中。一樣的,數據庫中也總會有一些很大的表,可能天天爲了生成一張報表,而只須要訪問一次就能夠了。但有可能就是這麼一次訪問,就將大部分的內存數據塊清除出了buffer cache。爲了不這種狀況的發生,能夠設置recycle類型的buffer cache,並將這種偶爾訪問的大表移入recycle buffer cache。
毫無疑問,若是你要設置這三種類型的buffer cache,你須要本身研究並等於你的數據庫中的對象進行分類,並計算這些對象的大小,從而纔可以正確的把它們放入不一樣的buffer cache。可是,無論怎麼說,設置這三種類型的buffer cache只能算是最低層次的優化,也就是說在你沒有任何辦法的狀況下,能夠考慮設置他們。可是若是你可以優化某條buffer gets很是高SQL使其buffer gets下降50%的話,就已經比設置多個buffer cache要好不少了。
9i之後還提供了能夠設置多種數據塊尺寸(二、四、八、16 或 32k)的buffer cache,以便存放不一樣數據塊尺寸的表空間中的對象。使用初始化參數:db_Nk_cache_size來指定不一樣數據塊尺寸的buffer cache,這裏的N就是二、四、八、16 或 32。建立數據庫時,使用初始化參數:db_block_size所指定缺省的數據塊尺寸用於system表空間。而後能夠指定最多4個不一樣數據塊尺寸的表空間,每種數據塊尺寸的表空間必須對應一種不一樣尺寸的buffer cache,不然不能建立不一樣數據塊尺寸的表空間。
SQL
>
create
tablespace tbs_test_16k
2
datafile
'
C:\oracle\oradata\ora92\tbs_test_16k.dbf
'
size 10M
3
blocksize 16k;
create
tablespace tbs_test_16k
*
ERROR 位於第
1
行: ORA
-
29339
: 表空間塊大小
16384
與配置的塊大小不匹配 SQL
>
show parameter db_16k_cache_size NAME TYPE VALUE
--
---------------------------------- ----------- ------------------------------
db_16k_cache_size big
integer
0
咱們能夠看到,因爲16k數據塊所對應的buffer cache沒有指定,因此建立16k數據塊的表空間會失
敗。因而咱們先設置db_16k_cache_size,而後再試着建立16k數據塊的表空間。
SQL
>
alter
system
set
db_16k_cache_size
=
10M; 系統已更改。 SQL
>
create
tablespace tbs_test_16k
2
datafile
'
C:\oracle\oradata\ora92\tbs_test_16k.dbf
'
size 10M
3
blocksize 16k; 表空間已建立。
不一樣尺寸數據塊的buffer cache的管理和內部機制與缺省數據塊的buffer cache沒有任何的分別。它最大的好處是,當使用可傳輸的表空間從其餘數據庫中將不一樣於當前缺省數據塊尺寸的表空間傳輸過來的時候,能夠不作不少處理的直接導入到當前數據庫,只須要設置對應的數據塊尺寸的buffer cache便可。同時,它對於調優OLTP和OLAP混合的數據庫也有必定的用處。OLTP環境下,傾向於使用較小的數據塊,而OLAP環境下,因爲基本都是執行全表掃描,所以傾向於使用較大的數據塊。這時,能夠將OLAP的錶轉移到使用大數據塊(好比32k)的表空間裏去。而將OLTP的表放在中等大小的數據塊(好比8k)的表空間裏。
對於應該設置buffer cache爲多大,oracle從9i開始經過設置初始化參數:db_cache_advice,從而提供了能夠參照的建議值。oracle會監控default類型、keep類型和recycle類型的buffer cache的使用,以及其餘五種不一樣數據庫尺寸(二、四、八、16 或 32k)的buffer cache的使用。在典型負荷的時候,啓用該參數,從而收集數據幫助用戶肯定最佳的db_cache_size的大小。該參數有三個值:
1) off:不收集數據。
2) on:開始分配內存收集數據,有可能引起CPU和內存的負擔,可能引發4031錯。
3) ready:不收集數據,可是收集數據的內存已經預先分配好了。經過把該參數值從off設置爲ready,而後再設置爲on,就能夠避免出現4031錯。
oracle會根據當前所監控到的物理讀的速率,從而估算出在不一樣大小尺寸的buffer cache下,所產生的可能的物理讀的數量。oracle會將這些收集到的信息放入視圖:v$db_cache_advice中。每種類型的buffer cache都會有相應的若干條記錄來表示所建議的buffer cache的大小。好比下面,咱們顯示對於缺省類型的、缺省數據塊尺寸的buffer cache的建議大小應該是多少。
SQL
>
SELECT
size_for_estimate, buffers_for_estimate,
2
estd_physical_read_factor,estd_physical_reads
3
FROM
v$db_cache_advice
4
WHERE
NAME
=
'
DEFAULT
'
5
AND
block_size
=
(
SELECT
VALUE
6
FROM
v$parameter
7
WHERE
NAME
=
'
db_block_size
'
)
8
/
SIZE_FOR_ESTIMATE BUFFERS_FOR_ESTIMATE ESTD_PHYSICAL_READ_FACTOR ESTD_PHYSICAL_READS
--
--------------- -------------------- ------------------------- -------------------
4
500
1.3869
40154
8
1000
1.3848
40093
12
1500
1.1861
34339
16
2000
1.1397
32996
20
2500
1
28952
24
3000
1
28952
28
3500
1
28952
32
4000
1
28952
36
4500
0.8671
25104
40
5000
0.8671
25104
44
5500
0.8671
25104
48
6000
0.7422
21488
52
6500
0.7422
21488
56
7000
0.7422
21488
60
7500
0.554
16040
64
8000
0.554
16040
68
8500
0.554
16040
72
9000
0.554
16040
76
9500
0.554
16040
80
10000
0.554
16040
這裏的字段estd_physical_read_factor表示在相應的buffer cache尺寸(由字段size_for_estimate表示)
下,估計從硬盤裏讀取數據的次數除以在內存裏讀取數據的次數。若是沒有發生物理讀則該比值爲空。在
內存足夠的前提下,這個比值應該是越低越好的。從上面的輸出中,咱們能夠看到,若是將buffer cache
設置爲60M,能夠得到較好的性能,物理讀也將會有一個顯著的降低。可是設置爲大於60M的話(好比
64M或68M),則不會下降物理讀,反而浪費內存空間。因此從上面的查詢結果中,咱們能夠知道,設置
爲60M是比較合適的。
2 buffer cache的統計信息
爲了對buffer cache進行性能的診斷,oracle提供了不少有關buffer cache的統計信息。這些統計信息大體能夠分紅三類:1)有關用戶發出的對內存數據塊的請求相關的統計信息;2)有關DBWR後臺進程對內存數據塊處理相關的統計信息;3)RAC相關的統計信息。
咱們在診斷buffer cache時,不須要關注全部的統計信息。這裏主要介紹幾個重要的統計信息,其餘的統計信息均可以到《
Oracle9i Database Reference: Appendix C》中找到。以下所示:
SQL
>
SELECT
name, value
FROM
v$sysstat
WHERE
name
in
(
2
'
session logical reads
'
,
3
'
physical reads
'
,
4
'
physical reads direct
'
,
5
'
physical reads direct (lob)
'
,
6
'
consistent gets
'
,
7
'
db block gets
'
,
8
'
free buffer inspected
'
)
9
/
NAME VALUE
--
-------------------------------------------------------------- ----------
session logical reads
73797
db block gets
498
consistent gets
73299
physical reads
29017
free buffer inspected
0
physical reads direct
40
這裏作些簡單的解釋。
1) session logical reads:全部的邏輯讀的數據塊的數量。注意,其中包括先從硬盤上讀數據塊到內存裏,再從內存裏讀數據塊。
2) consistent gets:在一致性(consistent read)讀模式下讀取的內存裏的數據塊數量。包括從rollback segment裏讀取的數據塊數量以及從data block buffer裏讀取的數據塊數量。主要是經過select產生的。Update/delete也能產生不多量的此類數據塊。注意:若是oracle的運行時間過長,因爲oracle的bug致使consistent gets大大超過實際的數量。所以建議使用‘no work - consistent read gets’, ‘cleanouts only - consistent read gets’,‘rollbacks only - consistent read gets’, ‘cleanouts and rollbacks - consistent read gets’之和來代替consistent gets的值。
3) db block gets:在當前(current)模式下讀取的內存裏的數據塊的數量。不是讀取過去某個時點的數據塊,而必須是當前最新的數據塊。主要是經過update/delete/insert來產生的,由於DML須要當前最新的數據塊才能對之進行改變。在字典管理表空間下,一些得到當前可用擴展空間的select語句也會產生此類數據塊,由於必須獲得當前最新的空間使用信息才能擴展。邏輯上,session logical reads = consistent gets + db block gets。
4) physical reads:從硬盤裏讀取的數據塊的數量。注意,這個數量大於實際從硬盤裏讀取的數量,由於這部分block也包括了從操做系統緩存裏讀取的數據塊數量。
5) physical reads direct:有些數據塊不會先從硬盤讀入內存再從內存讀入PGA再傳給用戶,而是繞過SGA直接從硬盤讀入PGA。好比並行查詢以及從臨時表空間讀取數據。這部分數據塊因爲不緩存使得hit ratio不會被提升。
6) physical reads direct (lob):與physical reads direct同樣。
7) free buffer inspected:這個值表示爲了找到可用數據塊而跳過的數據塊的數量。這些被跳過的數據塊就是髒的或被鎖定的數據塊。明顯,這個值若是持續增加或很高,就須要增長buffer cache的大小了。
在得到了這些統計信息之後,咱們能夠計算buffer cache的命中率:
1Hit Ratio
=
1
– (physical reads – physical reads direct
-
physical reads direct (lob) )
/
session logical reads 2Miss ratio
=
(physical reads – physical reads direct
-
physical reads direct (lob) )
/
session logical reads
一般在OLTP下,hit ratio應該高於0.9。不然若是低於0.9則須要增長buffer cache的大小。在考慮
調整buffer cache hit ratio時,須要注意如下幾點。
1) 若是上次增長buffer cache的大小之後,沒有對提升hit ratio產生很大效果的話,不要盲目增長buffer cache的大小以提升性能。由於對於排序操做或並行讀,oracle是繞過buffer cache進行的。
2) 在調整buffer cache時,儘可能避免增長不少的內存而只是提升少許hit ratio的狀況出現。
咱們還能夠查詢每種buffer cache的統計信息,主要關注的仍是consistent_gets和db_block_gets以及
physical_reads的值。
SQL
>
SELECT
name, block_size,physical_reads, db_block_gets,consistent_gets
2
FROM
v$buffer_pool_statistics; NAME BLOCK_SIZE PHYSICAL_READS DB_BLOCK_GETS CONSISTENT_GETS
--
------------------ ---------- -------------- ------------- ---------------
DEFAULT
8192
28978
719
77591
DEFAULT
16384
2
80
11
v$sysstat中名稱以DBWR開頭的都是有關DBWR後臺進程相關的統計信息。當DBWR進程寫完髒數據塊之後或者掃描完LRU鏈表之後更新這些統計信息。DBWR會基於被觸發的頻率以及所處理的內存數據塊的數量與總內存數據塊的數量的比例,來進行自我調整。咱們能夠經過這些統計信息獲得一些對當前DBWR運行狀況的認識。
3 buffer cache的等待事件
與buffer cache相關的等待事件包括:latch free、buffer busy waits、free buffer waits。曾經發生過的等
待事件能夠從v$system_event(一個等待事件對應一行記錄)和v$session_event(一個session一個等待事件對應一行記錄)中看到。而當前系統正在經歷的等待事件能夠從v$session_wait看到。
3.1 latch free等待
等待事件「latch free」中與buffer cache有關的有兩類:cache buffers chains latch和cache buffers lru chain latch。在理解了上面所描述的有關buffer cache的內部管理機制之後,就應該很容易理解這兩個latch產生的緣由。
對於buffer cache中的每一個hash chain鏈表來講,都會有一個名爲cache buffers chains latch的latch來保護對hash chain的併發操做,這種latch一般也叫做hash latch或CBC latch。數據庫中會有不少的cache buffers chains latch,每一個latch都叫作child cache buffers chains latch。一個child cache buffers chains latch會管理多個hash chain。前面咱們知道,hash chain的數量由一個隱藏參數:_db_block_hash_buckets決定。一樣也有一個隱藏參數:_db_block_hash_latches來決定有多少個cache buffers chains latch來管理這些hash chain。該參數的缺省值由buffer cache中所含有的內存數據塊的多少決定,當內存數據塊的數量
•少於2052個時,_db_block_hash_latches = power(2,trunc(log(2, 內存塊數量 - 4) - 1))
•多於131075個時,_db_block_hash_latches = power(2,trunc(log(2, db_block_buffers - 4) - 6))
•位於2052與131075 buffers之間,_db_block_hash_latches = 1024
可使用下面的SQL語句來肯定當前系統的cache buffers chains latch的數量。
SQL
>
select
count
(
distinct
(hladdr))
from
x$bh;
COUNT
(
DISTINCT
(HLADDR))
--
---------------------
1024
SQL
>
select
count
(
*
)
from
v$latch_children
where
name
=
'
cache buffers chains
'
;
COUNT
(
*
)
--
--------
1024
在知道了cache buffers chains latch的數量之後,咱們只須要用hash chain的數量除以latch的數量之後,就能夠算出每一個latch管理多少個hash chain了。咱們將下面7532除以1024,就能夠知道,當前的系統中,每一個latch大概對應8個hash chain。
SQL
>
select
x.ksppinm, y.ksppstvl, x.ksppdesc
2
from
x$ksppi x , x$ksppcv y
3
where
x.indx
=
y.indx
4
and
x.ksppinm
like
'
\_%
'
escape
'
\
'
5
and
ksppinm
like
'
%_db_block_hash_buckets%
'
6
; KSPPINM KSPPSTVL KSPPDESC
--
-------------------- -------- -------------------------------------
_db_block_hash_buckets
7523
Number
of
database
block hash buckets
當數據庫在hash chain搜索須要的數據塊時,必須先得到cache buffers chains latch。而後在掃描hash chain的過程當中會一直持有該latch,直到找到所要的數據塊纔會釋放該latch。當有進程一直在掃描某條hash chain,而其餘進程也要掃描相同的hash chain時,其餘進程就必須等待類型爲cache buffers chains latch的latch free等待事件。
不夠優化的SQL語句是致使cache buffers chains latch的主要緣由。若是SQL語句須要訪問過多的內存數據塊,那麼必然會持有latch很長時間。找出邏輯讀特別大的sql語句進行調整。v$sqlarea裏那些buffer_gets/executions爲較大值的SQL語句就是那些須要調整的SQL語句。這種方式不是頗有針對性,比較盲目。網上曾經有人提供了一個比較有針對性的、查找這種引發較爲嚴重的cache buffers chains latch的SQL語句的方式,其原理是根據latch的地址,到x$bh中找對應的buffer header,x$bh的hladdr表示該buffer header所對應的latch地址。而後根據buffer header能夠找到所對應的表的名稱。最後能夠到v$sqltext(也能夠到stats$sqltext)中找到引用了這些表的SQL語句。我也列在這裏。where條件中的rownum<10主要是爲了避免要返回太多的行,只要可以處理掉前10個latch等待就能有很大改觀。
select
/**/
/*+ rule */
s.sql_text
from
x$bh a,dba_extents b, (
select
*
from
(
select
addr
from
v$latch_children
where
name
=
'
cache buffers chains
'
order
by
sleeps
desc
)
where
rownum
<
11
) c, v$sqltext s
where
a.hladdr
=
c.addr
and
a.dbarfil
=
b.relative_fno
and
a.dbablk
between
b.block_id
and
b.block_id
+
b.blocks
and
s.sql_text
like
'
%
'
||
b.segment_name
||
'
%
'
and
b.segment_type
=
'
TABLE
'
order
by
s.hash_value,s.address,s.piece
/
還有一個緣由可能會引發cache buffers chains latch,就是熱點數據塊問題。這是指多個session重複訪問一個或多個被同一個child cache buffers chains latch保護的內存數據塊。這主要是應用程序的問題。大多數狀況下,單純增長child cache buffers chains latches的個數對提升性能沒有做用。這是由於內存數據塊是根據數據塊地址以及hash chain的個數來進行hash運算從而獲得具體的hash chain的,而不是根據child cache buffers chains latches的個數。若是數據塊的地址以及hash chain的個數保持一致,那麼熱點塊仍然頗有可能會被hash到同一個child cache buffers chains latch上。能夠經過v$session_wait的p1raw字段來判斷latch free等待事件是不是因爲出現了熱點塊。若是p1raw保持一致,那麼說明session在等待同一個latch地址,系統存在熱點塊。固然也能夠經過x$bh的tch來判斷是否出現了熱點塊,該值越高則數據塊越熱。
SQL
>
select
sid, p1raw, p2, p3, seconds_in_wait, wait_time, state
2
from
v$session_wait
3
where
event
=
'
latch free
'
4
order
by
p2, p1raw; SID P1RAW P2 P3 SECONDS_IN_WAIT WAIT_TIME STATE
--
-- -------- --- --- --------------- ---------- ------------------
38
6666535C
13
1
1
2
WAITED KNOWN TIME
42
6666535C
13
1
1
2
WAITED KNOWN TIME
44
6666535C
13
3
1
4
WAITED KNOWN TIME ………………………
85
6666535C
13
3
1
12
WAITED KNOWN TIME
214
6666535C
138
1
1
2
WAITED KNOWN TIME
接下來,咱們就能夠根據p1raw的值去找到所對應的內存數據塊以及對應的表的名稱了。
select
a.hladdr, a.
file
#, a.dbablk, a.tch, a.obj, b.
object_name
from
x$bh a, dba_objects b
where
(a.obj
=
b.
object_id
or
a.obj
=
b.data_object_id)
and
a.hladdr
=
'
6666535C
'
;
要解決熱點塊的問題,能夠經過將熱點塊中的行分散到多個數據塊中去,這樣原來的熱點塊就變成了多個數據塊,這樣被hash到同一個latch的概率就下降了。若是熱點塊屬於表,則能夠先將表的數據導出來,而後增長表的pctfree值,最後將數據再導入。若是熱點塊屬於索引,則能夠設定較高的 pctfree參數後,重建索引。注意,這會增長索引的高度。
經過前面咱們已經知道,每一個working set都會有一個名爲cache buffers lru chain的latch(也叫作lru latch)來管理。任何要訪問working set的進程都必須先得到cache buffers lru chain latch。cache buffers lru chain latch爭用也是因爲低效的掃描過多的內存數據塊的SQL語句引發的。調整這些語句以下降邏輯讀和物理讀。只要修改一下上面找引發cache buffers chains latch的SQL語句便可找到這樣的SQL語句。
select
/**/
/*+ rule */
s.sql_text
from
x$bh a,dba_extents b, (
select
*
from
(
select
addr
from
v$latch_children
where
name
=
'
cache buffers lru chain
'
order
by
sleeps
desc
)
where
rownum
<
11
) c, v$sqltext s
where
a.hladdr
=
c.addr
and
a.dbarfil
=
b.relative_fno
and
a.dbablk
between
b.block_id
and
b.block_id
+
b.blocks
and
s.sql_text
like
'
%
'
||
b.segment_name
||
'
%
'
and
b.segment_type
=
'
TABLE
'
order
by
s.hash_value,s.address,s.piece
/
3.2 buffer busy waits等待
當一個session在讀取或修改buffer cache裏的內存數據塊時,首先必須得到cache buffers chains latch,得到之後,到hash chain上遍歷直到找到須要的buffer header後。這時,該session必須在該buffer header上以share或exclusive模式(具體哪一個模式由該session的操做決定)得到一個buffer lock或一個buffer pin。一旦buffer header被pin住,session就將釋放cache buffers chains latch,而後能夠在該buffer上進行操做了。若是沒法得到buffer pin,那麼該session就會等待buffer busy waits等待事件。該等待事件不會出如今session的私有PGA裏。
buffer busy waits等待事件不能像latch free等待那樣能夠相對比較容易的進行過後跟蹤。對於該等待事件,oracle提供了v$waitstat視圖。v$waitstat裏的記錄都是buffer busy waits等待事件發生時進行更新的。也就是說,該視圖體現的都是buffer busy waits等待事件的統計數據。但這隻能給你提供一個大概的buffer busy waits的分佈。若是要想具體的診斷該等待事件,只能當發生該等待時,到v$session_wait裏去找緣由,從而才能找到解決的辦法。處理buffer busy wait等待事件時,首先使用下面的SQL語句找到發生等待的數據塊類別以及對應的segment。
select
'
Segment Header
'
class, a.segment_type, a.segment_name, a.partition_name
from
dba_segments a, v$session_wait b
where
a.header_file
=
b.p1
and
a.header_block
=
b.p2
and
b.event
=
'
buffer busy waits
'
union
select
'
Freelist Groups
'
class, a.segment_type, a.segment_name, a.partition_name
from
dba_segments a, v$session_wait b
where
b.p2
between
a.header_block
+
1
and
(a.header_block
+
a.freelist_groups)
and
a.header_file
=
b.p1
and
a.freelist_groups
>
1
and
b.event
=
'
buffer busy waits
'
union
select
a.segment_type
||
'
block
'
class, a.segment_type, a.segment_name, a.partition_name
from
dba_extents a, v$session_wait b
where
b.p2
between
a.block_id
and
a.block_id
+
a.blocks
-
1
and
a.
file_id
=
b.p1
and
b.event
=
'
buffer busy waits
'
and
not
exists
(
select
1
from
dba_segments
where
header_file
=
b.p1
and
header_block
=
b.p2);
而後,根據不一樣的數據塊類型進行相應的處理。
1) 若是數據塊類型爲data block,若是版本爲10g以前,則能夠同時參照p3列的值來共同診斷。若是p3爲130意味着同時有不少session在訪問同一個data block,並且該data block沒有在內存裏,而必須從磁盤上獲取。有三種方法能夠下降該事件出現的頻率:
a、下降併發性。這個比較難實現。
b、找出並優化含有這些segment的SQL語句,以下降物理和邏輯讀。
c、增長freelists和freelist groups。
若是沒有足夠的freelists,當同時對同一個表進行insert時,這就很容易引發buffer busy waits等待。若是正在等待buffer busy waits的session正在進行insert操做,那麼須要檢查如下那個表有多少freelists了。固然,因爲freelists的不足主要會致使對於segment header的buffer busy waits等待。
若是p3爲220意味着有多個session同時修改在一個block(該block已經被讀入內存了)裏的不一樣的行。這種狀況一般出如今高DML併發性的環境裏。有三種方法能夠下降該事件出現的頻率:
a、下降併發性。這個比較難實現。
b、經過增長pctfree減小block裏含有的行數。
c、將該對象移到擁有較小block尺寸的表空間裏(9i或以上)。
2) 若是數據塊類型爲data segment header(表或索引的segment header,不是undo segment header)上發生buffer busy waits等待事件,一般代表數據庫裏有些表或索引的段頭具備頻繁的活動。
進程訪問segment header主要有兩種緣由:一是得到或修改process freelists信息;二是擴展HWM。有三種方法能夠下降該事件出現的頻率:
a、增長爭用對象的freelists和freelist groups的數量。
b、肯定pctfree和pctused之間的間隔不要過小。
c、確保next extent的尺寸不要過小。
d、9i之後,使用ASSM特性來管理block。
3) 若是數據塊類型爲undo segment headers的爭用等待,代表數據庫中的rollback segments太少,或者他們的extent size過小,致使對於同一個segment header的大量更新。若是使用了9i之後的auto undo management,則不用處理,由於oracle會根據須要自動建立新的undo segments。若是是9i以前,則能夠建立新的private rollback segments,並把它們online,或者經過下降transactions_per_rollback_segment參數來減輕該等待。
4) 若是數據塊類型爲undo block,說明有多個session同時訪問那些被更新過的block。這是應用系統的問題,在數據庫來講對此無能爲力。
3.3 buffer busy waits等待
在一個數據塊被讀入buffer cache以前,oracle進程必須爲該數據塊得到一個對應的可用的內存數
據塊。當session在LRU list上沒法發現一個可用的內存數據塊或者搜尋可用的內存數據塊被暫停的時候,該session就必須等待free buffer waits事件。
從前面的描述,咱們已經知道,一個須要可用內存數據塊的前臺進程會連續掃描LRU 鏈表,直到達到一個限定值(也就是隱藏參數_db_block_max_scan_pct所指定的值,表示已經掃描的buffer header數量佔整個LRU鏈表上的buffer header的總數量,在9i中該限定值爲40%)。若是到該限定值時還沒找到可用內存數據塊時,該前臺進程就會觸發DBWR進程以便清空一些髒數據塊,從而使得在輔助LRU鏈表上可以掛上一些可用的內存數據塊。在DBWR進程工做時,該前臺進程就必須等待free buffer waits。
oracle跟蹤每次對於可用的內存數據塊的請求次數(記錄在v$sysstat裏的free buffer requested),也跟蹤每次請求可用的內存數據塊失敗的次數(記錄在v$system_event裏的free buffer waits的total_waits)。而v$sysstat裏的free buffer inspected則說明oracle爲了找到可用的內存數據塊所所跳過的數據塊的個數,若是buffer cache很空,有不少空的數據塊的話,則該值爲0。若是free buffer inspected相對free buffer requested來講很高,則說明oracle進程須要掃描更多的LRU鏈表上的數據塊才能夠找到可用的數據塊。
SQL
>
select
*
2
from
v$sysstat
3
where
name
in
(
'
free buffer requested
'
,
'
free buffer inspected
'
); STATISTIC# NAME CLASS VALUE
--
-------- ------------------------------ ----------- ----------
75
free buffer requested
8
290532493
79
free buffer inspected
8
2983596
SQL
>
select
*
2
from
v$system_event
3
where
event
=
'
free buffer waits
'
; EVENT TOTAL_WAITS TOTAL_TIMEOUTS TIME_WAITED AVERAGE_WAIT TIME_WAITED_MICRO
--
--------------- ----------- -------------- ----------- ------------ -----------------
free buffer waits
1003
476
71075
71
710749256
能夠看到,該系統的free buffer waits等待不多,總共等待的時間才0.476秒。同時也能夠看到,請求了290532493(free buffer requested)個可用的內存數據塊,可是在這個過程當中只跳過了2983596(free buffer inspected)個數據塊,兩者相差2個數量級。說明系統很容易就找到可用的內存數據塊。 若是一個session花費了不少的時間等待free buffer waits等待事件的話,一般可能有如下緣由: 1) 低效率的SQL語句:對於那些引發很大邏輯讀的SQL語句(v$sql裏的disk_reads),那些SQL語句可能進行了全表掃描,索引全掃描、或者經過了不正確的索引掃描表等。調整這些SQL語句以下降邏輯讀。 2) DBWR進程不夠多:也能夠經過增長DBWR checkpoints的個數來下降free buffer waits。9i下,能夠經過減少fast_start_mttr_target參數來縮短MTTR,從而增長DBWR進程啓動的次數。然而,這也有可能引發進程等待write complete waits事件。 3) I/O子系統太慢。 4) 延遲的塊清除(block clearouts):一般發生的情形是,晚上向數據庫導入了一個很大的表。而後早上運行應用系統時,會發現有有進程在等待buffer busy waits。這是由於第一個訪問該表的進程將進行一個延遲的塊清除,而這會致使free buffer waits等待事件。解決方法是在導入表完畢之後,執行一句全表掃描,好比一般是:select count(*) from該大表。這樣在後面的進程再次訪問的時候就不會產生free buffer waits等待事件了。 5) buffer cache過小:遇到free buffer waits事件,首先想到的就是增長buffer cache的大小。