バッファキャッシュのサイズよりも大きな、TAB39_BIG表のBツリー索引IDX_TAB39_BIG_COL2に対して、INDEX FAST FULL SCANが行われるクエリを実行した後、バッファキャッシュ上にキャッシュされているオブジェクトとサイズを確認します。
$ sqlplus /nolog SQL> /* 索引高速スキャンのヒント句を指定したクエリの実行計画の確認と実行 */ connect TRY/TRY set autotrace on explain select /*+ INDEX_FFS(TAB39_BIG, IDX_TAB39_BIG_COL2) */ count(COL2) from TAB39_BIG ; COUNT(COL2) ----------- 179200 Execution Plan ---------------------------------------------------------- Plan hash value: 80225013 -------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | -------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 1001 | 7102 (1)| 00:01:26 | | 1 | SORT AGGREGATE | | 1 | 1001 | | | | 2 | INDEX FAST FULL SCAN| IDX_TAB39_BIG_COL2 | 179K| 171M| 7102 (1)| 00:01:26 | -------------------------------------------------------------------------------------------- /* バッファキャッシュ上にキャッシュされているオブジェクトとサイズの確認 */ connect / as sysdba col OWNER for a8 col OBJECT_NAME for a24 select OWNER, OBJECT_NAME, count(*) "BUFFERS", count(*)*8/1024 "MB" from V$BH, DBA_OBJECTS where OBJD = DATA_OBJECT_ID and OWNER = 'TRY' and V$BH.STATUS != 'free' group by OWNER, rollup(OBJECT_NAME) order by 4 ; OWNER OBJECT_NAME BUFFERS MB -------- ------------------------ ---------- ---------- TRY IDX_TAB39_SMALL_COL1 1 .0078125 TRY IDX_TAB39_BIG_COL1 375 2.9296875 TRY IDX_TAB39_BIG_COL2 16318 127.484375 TRY 16694 130.421875
バッファキャッシュが満杯な状況を作り出す際に、私が良く使用するテクニックです。今更ですが、今回の私の検証環境のバッファキャッシュのサイズは140MB程度と、非常に小さくしてあります。前回記事の演習2における、確認索引IDX_TAB39_BIG_COL2のサイズは208MBであり、バッファキャッシュの140MBよりも大きいです。この索引を索引高速スキャンすることで、バッファキャッシュがこの索引のブロックで満杯になっていることが確認いただけるかと思います。
上記の回答例では、TRYスキーマだけで約130MBをキャッシュしていることが分かります。これ以外にも、SYSTEMユーザーのオブジェクトがキャッシュされているので、140MBのバッファキャッシュが満杯になっていました。OWNER列の条件を解放すれば、皆さんの環境でもご確認いただけます。
ちなみに、この索引高速スキャンの実行は通常の索引スキャンと異なり高速な点も、検証環境を準備する上でとても便利です。理由は、全ての索引リーフブロックをマルチブロックでディスクから読み込めるためです。そうです。索引高速スキャンではdb file scattered read待機イベントが発生しているでしょう。ぜひ確認してみてください。
さてさて、これで、「TAB39_SMALL表に対して索引を使用した表アクセス(TABLE ACCESS BY INDEX ROWID)を行うクエリを実行した際に、db file sequential read待機イベントが発生するのか」を確認できる準備が整いました。
バッファキャッシュをフラッシュせずに、演習3で作成したSQLファイルを再度実行した後、パフォーマンス統計情報と発生した待機イベントについて確認します。
$ sqlplus TRY/TRY SQL> @sql_loop.sql NAME VALUE ------------------------------------------------ ---------- physical read IO requests 909 physical read bytes 7446528 physical read flash cache hits 0 physical read partial requests 0 physical read requests optimized 0 physical read total IO requests 909 physical read total bytes 7446528 physical read total bytes optimized 0 physical read total multi block requests 0 physical reads 909 physical reads cache 909 physical reads direct 0 physical reads direct (lob) 0 physical reads direct temporary tablespace 0 physical reads for flashback new 0 physical reads prefetch warmup 0 physical reads retry corrupt 0
まずは、実行後のパフォーマンス統計情報を確認してみると、「physical reads prefetch warmup」がカウントアップしていないことから、Pre-Warming機能が動作していなかったことが理解できます。次に、前回同様にマルチブロック読み込みを示す「physical read total multi block requests」もカウントアップしていませんので、この演習のクエリ実行ではシングルブロック読み込みしか発生していません。
以下は、events 10046のSQLトレースの結果をgrepしたものですが、待機イベントdb file sequential readだけが発生していることが確認できます。
$ cat orcl_ora_7888.trc | grep "db file scattered read" | wc -l 0 $ cat orcl_ora_7888.trc | grep "db file sequential read" | wc -l 909
少し遠回りしてしまいましたが、索引を使用した表アクセス(TABLE ACCESS BY INDEX ROWID)、つまりは、「Bツリー索引の各ブロックを1つずつアクセスして該当のリーフブロックにたどりつき、そこで特定されたROWIDを使用して表内の特定の1つのブロックを読み込む」というような、「順番(sequential)にシングルブロックをバッファキャッシュへ読み込む」場合には、db file sequential read待機イベントが発生することをご理解いただけたかと思います。
ちなみに、「待機イベント」という名前を耳にすると、待機するのだからパフォーマンスに対して悪影響があるものと捉えられがちなので、「待機イベントの発生回数をゼロにするにはどうしたらよいですか?」とご質問を頂くことがあります。この質問は誤りではないですが、正確でもありません。待機イベントには、回数と時間の2つの評価軸が存在します。回数が多くても、合計待機時間や平均待機時間が小さければ、問題のないケースが多いので、「待機イベントの平均待機時間を小さくするにはどうしたらよいですか?」がより正しいご質問となります。
次回は、バッファキャッシュよりも大きな表にアクセスした際に発生する待機イベントやカウントアップするパフォーマンス統計情報を確認し、最後にAWRレポートの読み方へ戻っていきましょう。それではまた次回お会いしましょう!
Copyright © ITmedia, Inc. All Rights Reserved.