Free buffer waits

概要

free buffer waits待機イベントは、バッファキャッシュ内のデータブロックを読み込むか、CR(consistent read)のイメージを生成するためのフリーバッファ(free buffer)が 見つからない場合に発生します。これはバッファキャッシュが小さすぎるか、ダーティ(dirty)ブロックをディスクに記録する作業が十分に速くないということを意味します。バッファキャッシュ内において、フリーバッファを見つけられなかったプロセスはDBWRに要求(ダーティバッファをディスクに記録することの要求)を送信した後、free buffer waits待機イベントで待機します。

free buffer waits待機イベントは、バッファキャッシュ内のデータブロックを読み込むか、CR(consistent read)のイメージを生成するためのフリーバッファ(free buffer)が 見つからない場合に発生します。これはバッファキャッシュが小さすぎるか、ダーティ(dirty)ブロックをディスクに記録する作業が十分に速くないということを意味します。バッファキャッシュ内において、フリーバッファを見つけられなかったプロセスはDBWRに要求(ダーティバッファをディスクに記録することの要求)を送信した後、free buffer waits待機イベントで待機します。

Oracleは、すべてのフリーバッファ要求の回数を記録します。統計情報名V$ SYSSTATビューのfree buffer requestedです。Oracleは、フリーバッファ要求の失敗回数も記録します。これはfree buffer waitsイベントのTOTAL_WAITSで見つけることができます。フリーバッファ要求は、技術的には、buffer getsであり、フリーバッファ要求が失敗した場合、buffer missesとすることができます。V$ SYSSTATのfree buffer inspected統計情報は、Oracleのプロセスが要求されたフリーバッファを獲得するためにどのように多くのバッファを検索したのかを教えてくれます。もしfree buffer inspected数値がfree buffer requestedよりはるかに高い場合は、プロセスが利用可能なバッファを獲得するためにLRUリストをその分より検索したことを意味します。下のクエリは、システムレベルのfree buffer requested、free buffer inspectedとfree buffer waitsの統計情報を表示します。

select * 
from   v$sysstat 
where  name in ('free buffer requested', 'free buffer inspected');

STATISTIC#  NAME               CLASS               VALUE
---------------  ------------------------------     -----------------
        75 free  buffer requested         8         3,311,443,932
        79 free  buffer inspected          8            108,685,547

select * 
from   v$system_event 
where event = 'free buffer waits';

EVENT                  TOTAL_WAITS      TOTAL_TIMEOUTS     TIME_WAITED     AVERAGE_WAIT
--------------------  -----------------   ---------------   ---------------   -------------------
free buffer waits          30369             15795               2187602          72.0340479

待機パラメータと待機時間

待機パラメータ

free buffer waits待機イベントの待機パラメータは以下の通りです。

  •   P1:オラクルがバッファキャッシュに読み込むブロックに該当するFile
  •   P2:オラクルがバッファキャッシュに読み込むうBlock
  •   P3:Oracle 10gの以前では、使用されませんでした。Oracle 10gからLRU、LRUWリストのSET_IDをしまします。

待機時間

利用可能なフリーバッファのために1秒まで待機し、タイムアウトが発生した後、再び1秒を待機します

チェックポイントとソリューション

非効率的なSQL文

非効率的なSQL文がイベント発生の主な原因として作用します。V$ SQLビューで大量のディスクの読み取りI / O(DISK_READS)を実行するSQL文を見つけてみましょう。このSQLステートメントは、full table scan、index fast full scan、または選択度が良くないインデックスを使用して、テーブルをアクセスします。ディスクの読み取りI / O要求を減らすようにSQL文をチューニングしなければなりません。最も効率的な結合方法とアクセスパスを使用します。また、可能な場合は、アプリケーションレベルでdirect loads、direct inserts、parallel queriesと同じdirect reads/ writesを使用することが望まれます。Direct read/ writeオペレーションはSGAを経由しません。

不十分なDBWRプロセス数

LGWRプロセスがログバッファの容量を確保する役割を実行するように、DBWRプロセスはLRUリスト上のフリーバッファを確保する役割を果たしています。DBWRプロセスは、バッファキャッシュの”working set”との関係があります。”working set”は、LRUとLRUWリストで構成されています。もし一つのDBWRプロセスのみが存在する場合は、すべての”working set”のサービスを一つのDBWRプロセスが実行しなければなりません。多数のDBWRプロセスが存在する場合、Oracleは”working set”を均等に分配することになります。当然、より多くのDBWRプロセスはより効率的に”working set”をサービスすることができ、より高いスループットを確保することができます。下のX$ KCBWDS(kernel cache buffer working set descriptors)ビューの結果は、8つの “working set”と2つのDBWRプロセスがあることを示しています。  

select set_id, dbwr_num 
  from  x$kcbwds
order by set_id;

    SET_ID   DBWR_NUM
   ----------  --------------
         1                0
         2                0
         3                0
         4                0
         5                1
         6                1
         7                1
         8                1

多くの人が非同期I / O環境では、一つのDBWRプロセスを使用するように話を聞いたことがあるでしょう。これは、ガイドラインに過ぎず、free buffer waits待機イベントが発生した場合には、非同期I / O環境でも、多数のDBWRプロセスを使用することができます。 CPU_COUNTに応じDB_WRITER_PROCESSESパラメータを調整してDBWRプロセスの数を増加させることができます。しかし、SQL文が最適化されなくて、多数のバッファを使用する場合には、特別な効果がなくなります。

さらに、多数のDBWRプロセスを使用すれば、DBWRチェックポイントの数が増加するにつれてfree buffer waits発生回数を減少させることができます。 Oracle 9iでは、FAST_START_MTTR_TARGETパラメータを利用して、MTTR(Mean Time To Recovery)を短縮させる方法でも同様の効果を出すことができます。より短いMTTRはDBWRプロセスの活動性を高めることで、結果的にクリーンバッファ(clean buffer)の供給をより円滑にします。しかし、DBWRプロセスの活動性を高めることは、ディスクに転送されるブロックを変更しようとするプロセスがwrite complete waits待機イベントで待機する可能性を高めることになります。したがって、アプリケーションの種類に応じて、適切な調整値を見つける必要があります。

遅いI / Oサブシステム

もしDBWRでdb file parallel write待機時間が長く表示される場合、I / Oシステムに問題があると判断することができます。 DBWRでdb file paralle write待機時間が長くなると、サーバープロセスは、連鎖的にfree buffer waits待機やwrite complete waits待機で待機します。ローデバイス(Raw device)とAIO(Asychronous IO:非同期I / O)を組み合わせて使用することが、I / Oパフォーマンスを改善させる最良の方法として知られています。ローデバイスではない場合でも、AIOをサポートするシステムがあるので、これを活用することができます。 AIOを使用する場合は、DBWRの数を増やすことは意味がないという意見が多くあります。複数のDBWRを使用する目的は、最終的にAIOをソフトウェア的に実行するものだからです。しかし、Writeが非常に多いシステムであれば、AIOと複数のDBWRを同時に設定することも可能です。 OSレベルでDirect I / Oを使用することも、パフォーマンスに大きな助けになります。 Direct I / Oを使用する場合には、ローデバイスを使用する必要がないという意見もあります。 Direct I / Oを使用する場合には、CPUの数が十分であれば、DB_WRITER_PROCESSESの値を調整してDBWRの数を増加させることを並行することができます。 Oracleの基本的なDBWR数はCPU_COUNT / 8です。

I / Oシステムの性能を向上させる方法(IO_enhanceリンク)

遅れたブロック・クリーンアウト

テーブルがバッファキャッシュにロードされた後に、アプリケーションでそのテーブルを使用する前に、テーブルのfull table scanオペレーションを実行する必要があります。これらの理由は、これらのデータブロックを初めて読むプロセスがdelayed block cleanoutを行う必要があり、これはfree buffer waits待機イベントが発生します。 したがって、アプリケーションでは、テーブルを使用する前に、full table scanを実行することにより、アプリケーションで発生するfree buffer waits待機イベントを削除することができるようになります。以下の例のテストを利用して、Oracle9iでの処理方法を知ることができます。

 

  • 1. バッファキャッシュを20,000ブロックに設定します。
  • 2. FAST_START_MTTR_TARGETを5秒低く設定する。これはDBWRが活発にダーティバッファをディスクに記録するようにして、今後そのブロックのクエリを実行する場合は、必ずdelayed block cleanoutを行うようにします。
  • 3. インデックスのないテーブルに大量のレコード(約150万件程度)をinsertした後、コミットを実行します。
  • 4. データベースをシャットダウン(shutdown)した後、再起動します。
  • 5. テーブルのレコードをカウントしてみましょう。Oracleのプロセスは、そのテーブルのfull table scanオペレーションを実行します。V$ SESSION_EVENTビューを照会して、このセッションを探してみましょう。delayed block cleanoutによりfree buffer waits待機イベントを待機していることを確認することができでしょう。
  • 6. 4番と5番のプロセスを繰り返してみましょう。しかし、今回はold ITLが整理されてfree buffer waits待機イベントが発生しません。
Delayed block cleanoutとcommit cleanout - トランザクションはバッファキャッシュ内の多くのブロックを
ダーティ(dirty)にすることができます。DBWRプロセスは、様々な間隔でコミットブロックと、コミットされて
いないブロックをデータファイルに記録します。トランザクションがコミットされたときは、Oracleのプロセスは
DBWRプロセスによってディスクに記録されていないブロックに対してcommit cleanoutを実行します。
 すでにディスクに記録されたブロックは、そのブロックを最初に読むのプロセスによってまとめ(cleaned)られます。
これをdelayed block cleanoutといいます。
より多くの情報が必要な場合は、

メタリンクNote#40689.1 を参照してください。

遅れたブロック・クリーンアウト

バッファキャッシュがあまりにも小さくてフリーバッファ要求に対応することができない場合でも、free buffer waits競合が発生することになります。これを最後の原因に扱った理由は、最近では、バッファキャッシュをこのように小さく設定することは一般的ではないからです。現在のデータベースサーバーは、十分なメモリを搭載するので、DBAはバッファキャッシュを大きく設定する傾向があります。多くのDBAは、SGAを利用可能なメモリの50%に割り当てる必要があると考えています。バッファキャッシュのサイズを増加させる前に、DBWRプロセスの数を増加させた後、free buffer waits待機イベントの待機回数が減少していることを確認しなければならなりません。その後に、バッファキャッシュのサイズを増加させなければならないのです。

豆知識

Bufferの収集の仕方

  • 1. ユーザーが要求されたブロックのDBAのハッシュ関数を適用して、適切なハッシュバケット(Hash Bucket)を探します。
  • 2. ハッシュバケットについているハッシュチェーン(Hash chain)を探索してブロックに対応するバッファのヘッダが存在するかどうかを確認します。バッファヘッダが既に存在し、そのブロックがバッファ・キャッシュに上がってきている状態であれば、そのブロックを使用します。
  • 3. まだバッファキャッシュに存在しない場合、まずLRUリストを最も少なく使用された順序でフリーバッファを探します。この過程で、ダーティバッファが発見されると、LRUWリストに移動させます。フリーバッファを見つけたら、データファイルからブロックをそのバッファに読み込みます。
  • 4. LRUリストからフリーバッファが見つかる_DB_BLOCK_SCAN_MAX_PCT(デフォルトは40)パラメータの値だけスキャンをしても、フリーバッファが見つからない場合、Oracleは、スキャンを停止しDBWRにダーティブロックをディスクに記録してフリーバッファを確保することを要求します。書き込みが完了すると、バッファを使用します

分析事例

Free Buffer Waits分析事例

分析対象のインスタンスは、Active Sessionが急増した区間が存在し、この時点でのStat/ Event/ Active Session List情報を使用してFree Buffer Waitsイベント待ちが発生することが分かります。

特に、Active Session Listに示されているLogical Reads/ Physical Readsの値が0であり、これは、セッションがFree Buffer Waitsイベントの待機により、まったくI / O操作をしていないということを示します。

8_2_1

 

読みたいブロックがバッファキャッシュに存在しない場合は、LRUリストからフリーバッファを見つけ、データファイルからブロックをそのバッファに読み込む必要があります。LRUリストの一定領域をスキャンしてもフリーバッファを得られなかった場合には、LRUリストのスキャンを停止し、DBWRにダーティブロックをディスクに記録してフリーバッファを確保するように要求します。このとき、サーバプロセスはDBWRの書き込み操作が完了するまで、Free Buffer Waitsイベントで待機します。

したがって、スキャンするブロックが多く非効率的なSQLステートメントDBWRのパフォーマンスの低下は、小さなバッファキャッシュのサイズがFree Buffer Waitsイベントの発生原因になることができます。 特に、DBWRのパフォーマンスの低下は、Free Buffer WaitsイベントとWrite Complete Waitsイベントの原因となます。Write Complete WaitsイベントはDBWRが記録しているダーティバッファをサーバプロセスが要求したときに発生しますが、ディスクに記録されているバッファを読み取る確率が実際に高くないので頻繁に発生する場合は、DBWRがダーティバッファを記録する時間が過度に長いことをを意味します。

問題区間でWrite Complete Waitsイベントが発生しているか、DBWRがDB file Parallel Writeイベントを待機していることは、次のグラフを介して確認してみることができます。

8_2_2

問題が発生した区間でWrite Complete WaitsイベントとDB File Parallel Writeイベントの待機はほとんど現れません。DBWRのパフォーマンスの低下のためにFree Buffer Waitsが発生したわけではないと考えられます。

Active Sessionの推移をFree Buffer Waits、Free Buffer Inspected、Free Buffer requested、Physical Reads指標の推移と比較してみます。

8_2_3

 

Active SessionとFree Buffer Waitsイベントの推移が一致し、Free Buffer Inspected指標を見て待機時に、Oracleプロセスは、要求されたフリーバッファを獲得するために、500個以上のバッファを検索したことを知ることができます。

また、Free Buffer requestedとphysical reads指標の推移により、問題が発生したActive Session Peak以前の時点でフリーバッファの要求が増加したことを知ることができます。つまり、フリーバッファの要求が増加した、Physical Reads Peak時点(パフォーマンスの低下前の時点)に移動する必要があります。

8_2_4

 

パフォーマンスの低下時点の直前に移動し、Physical readsを基準にActive Sessionを並べてみると、1分間13万ブロック以上をディスクからスキャンしたSQL文が確認されます。このSQL文のDetail情報を見てみましょう。

8_2_5

 

9時10〜20分台で対応するSQLステートメントは、全部で249回実行され、実行中のメモリでは、1678万のブロック以上をスキャンし、ディスクでは、118万ブロック以上を読んでいます。1回の実行時に、約67000ブロック以上をスキャンし、このSQL文の実行により、バッファキャッシュを使用する別のセッションは、Free Buffer Waitsイベントで待機したものと推測されます。このため、このSQL文のブロックのスキャン量を減らすことができるようチューニングが必要になると考えられます。また、CPU数が十分であれば、Parallel Queryに変更してdirect I/ Oを利用することはできないか考えてみる必要があります。