◇ORACLEが検索結果を返すまでの流れ
ユーザがSELECT文を発行するとORACLE内部では以下のような動作をする。
1.SHARED_POOL内に同じSQL文が存在するかの確認。
2.SQL文の構文確認。
3.データディクショナリから表と列の定義を確認。
4.ユーザのオブジェクト権限を確認。
5.実行計画の確定。
6.実行計画に従いデータ(BLOCK)をDB_BUFFER_CACHEにロード。
7.結果をユーザに返す。
上記のうち1~5までがParse。
6がExecute。
7がFetchとなる。
SQL*Traceの結果を見ると7のFetchがelapsedの大部分を占めている。
約10Sec.の時間差も、ここで発生している。
なぜ、このような結果に至ったのか??
ここからは、あくまで推測でしかないが、この時、ORACLEの内部では以下の
ような動作をしていたと思われる。
・パターン1(COLUMN2のみのINDEXを使用。)
INDEX TABLE
+--+--+--+ +--+--+--+--+--+
| | | | | | | | | |
+--+--+--+ +--+--+--+--+--+
| | | | | | | | | |
+--+--+--+ +--+--+--+--+--+
| | | | | | | | | |
+--+--+--+ +--+--+--+--+--+
| |
|1.'COLUMN2 = 1'の |2.'COLUMN2 = 1'のRECORDを
| RECORDのROWIDを取得し | BUFFER_CACHEにロード。
| BUFFER_CACHEにロード。 |
↓ ↓
BUFFER_CACHE
+-------------------------------------+
| |
| |
| |
| |
+-------------------------------------+
3.TABLEから取得したRECORDの中で'COLUMN1 = 99999'の条件に合致する
RECORDをユーザプロセスへ返す。
・パターン2(COLUMN1、COLUMN2の複合INDEXを使用。)
INDEX TABLE
+--+--+--+--+ +--+--+--+--+--+
| | | | | | | | | | |
+--+--+--+--+ +--+--+--+--+--+
| | | | | | | | | | |
+--+--+--+--+ +--+--+--+--+--+
| | | | | | | | | | |
+--+--+--+--+ +--+--+--+--+--+
| |
|1.'COLUMN1 = 99999'かつ |2.'COLUMN1 = 99999'かつ
| 'COLUMN2 = 1'の | 'COLUMN2 = 1'の
| RECORDのROWIDを取得し | のRECORDを
| BUFFER_CACHEにロード。 | BUFFER_CACHEにロード。
↓ ↓
BUFFER_CACHE
+-------------------------------------+
| |
| |
| |
| |
+-------------------------------------+
3.TABLEから取得したRECORDをユーザプロセスへ返す。
2つのパターンの工程を比較すると3.に大きな違いがある。
パターン2の場合はINDEXのみで対象のRECORDを特定できる。
対してパターン1の場合はTABLEまで読み込まないと対象のRECORDを特定
できない。
おそらく、この差がelapsedに顕れたのだろう。
来週は、この仮説が正しいことを証明するための検証を実施する。
ユーザがSELECT文を発行するとORACLE内部では以下のような動作をする。
1.SHARED_POOL内に同じSQL文が存在するかの確認。
2.SQL文の構文確認。
3.データディクショナリから表と列の定義を確認。
4.ユーザのオブジェクト権限を確認。
5.実行計画の確定。
6.実行計画に従いデータ(BLOCK)をDB_BUFFER_CACHEにロード。
7.結果をユーザに返す。
上記のうち1~5までがParse。
6がExecute。
7がFetchとなる。
SQL*Traceの結果を見ると7のFetchがelapsedの大部分を占めている。
約10Sec.の時間差も、ここで発生している。
なぜ、このような結果に至ったのか??
ここからは、あくまで推測でしかないが、この時、ORACLEの内部では以下の
ような動作をしていたと思われる。
・パターン1(COLUMN2のみのINDEXを使用。)
INDEX TABLE
+--+--+--+ +--+--+--+--+--+
| | | | | | | | | |
+--+--+--+ +--+--+--+--+--+
| | | | | | | | | |
+--+--+--+ +--+--+--+--+--+
| | | | | | | | | |
+--+--+--+ +--+--+--+--+--+
| |
|1.'COLUMN2 = 1'の |2.'COLUMN2 = 1'のRECORDを
| RECORDのROWIDを取得し | BUFFER_CACHEにロード。
| BUFFER_CACHEにロード。 |
↓ ↓
BUFFER_CACHE
+-------------------------------------+
| |
| |
| |
| |
+-------------------------------------+
3.TABLEから取得したRECORDの中で'COLUMN1 = 99999'の条件に合致する
RECORDをユーザプロセスへ返す。
・パターン2(COLUMN1、COLUMN2の複合INDEXを使用。)
INDEX TABLE
+--+--+--+--+ +--+--+--+--+--+
| | | | | | | | | | |
+--+--+--+--+ +--+--+--+--+--+
| | | | | | | | | | |
+--+--+--+--+ +--+--+--+--+--+
| | | | | | | | | | |
+--+--+--+--+ +--+--+--+--+--+
| |
|1.'COLUMN1 = 99999'かつ |2.'COLUMN1 = 99999'かつ
| 'COLUMN2 = 1'の | 'COLUMN2 = 1'の
| RECORDのROWIDを取得し | のRECORDを
| BUFFER_CACHEにロード。 | BUFFER_CACHEにロード。
↓ ↓
BUFFER_CACHE
+-------------------------------------+
| |
| |
| |
| |
+-------------------------------------+
3.TABLEから取得したRECORDをユーザプロセスへ返す。
2つのパターンの工程を比較すると3.に大きな違いがある。
パターン2の場合はINDEXのみで対象のRECORDを特定できる。
対してパターン1の場合はTABLEまで読み込まないと対象のRECORDを特定
できない。
おそらく、この差がelapsedに顕れたのだろう。
来週は、この仮説が正しいことを証明するための検証を実施する。