Oracle 実行計画の見方のサンプル

Oracleの実行計画の見方のサンプルです。
(確認環境:SQL Developer 21/19)

目次

サンプル テストデータの準備
  フルスキャン
  INDEX RANGE SCAN
  Bツリーインデックスのイメージ
  INDEX UNIQUE SCAN
  NESTED LOOPS
  HASH JOIN

テストデータの準備

以下のテーブルがあるとします。件数は100万件です。

CREATE TABLE employee_data(
	id NUMBER(7,0),
	name VARCHAR2(20) not null,
	romaji VARCHAR2(20),
	primary key(id)
);
employeeテーブル
id name romaji
1 86VL1 3AOG5
2 YCPZ5 P3S0C
  ・・・

idは、プライマリーキー(PK)です。
nameはnot null制約がついています。

テストデータを100万件作成

BEGIN
  FOR i IN 1..1000000 LOOP
    INSERT INTO employee_data VALUES(i,dbms_random.string('x',5),dbms_random.string('x',5));
  END LOOP;
  COMMIT;
END;
/

idは1から100万までの連番がセットされます。
nameとromajiはランダムの5文字がセットされます。

Oracle SQL Developerで実行計画を取得します。
Oracle SQL Developerで実行計画を確認する方法

 

フルスキャン

1.インデックスがない項目の値を指定して検索します。

select * from employee_data where name = 'WUP7E'

 

2.DBMS_XPLANをクリックします。

 

3.表示されたSQLを実行します。

select * from table
(dbms_xplan.display_cursor(sql_id=>'79wv5gh9w4zwg', format=>'ALLSTATS LAST'));

 

4.実行結果が表示されます。

11行目は、「TABLE ACCESS FULL」で全件検索しています。where句にインデックスがない項目を指定したためです。

 

INDEX RANGE SCAN

1.テーブルの項目のNameにインデックスを作成します。

CREATE INDEX employee_data_idx1
On employee_data(name);

デフォルトはBツリーインデックスが作成されます。

 

2.インデックスを設定した列を指定して検索します。

select * from employee_data where name = '87VIU'

 

3.DBMS_XPLANをクリックします。

 

4.表示されたSQLを実行します。

select * from table
(dbms_xplan.display_cursor(sql_id=>'03yt8p8bd4dqn', format=>'ALLSTATS LAST'));

 

4.実行結果が表示されます。

12行目は、「INDEX RANGE SCAN」をしています。
NAME列の値は一意ではないので範囲(RANGE SCAN)になりました。
11行目は、取得したROWIDでEMPLOYEE_DATAにアクセスしています。

 

Bツリーインデックスのイメージ

以下は、Bツリーインデックス(B+Tree)のイメージです。

数値が1から1500まである場合で、300を探す場合、一番上の500より小さいので左下に行き、150より大きいので右下に行き300を見つけます。
ポイントは、全件検索しなくて良くなることです。

B-Treeは、形が木に似ているので木構造とも呼ばれます。
指定された値でソートして格納されます。

件数が多いデータから数件のデータを取得するときに効果が出ます。

カーディナリティが高い場合、B-Treeインデックスを設定します。
→カーディナリティとは値の種類が多いことです。
→カーディナリティが低い場合(性別の男女等)、Bitmapインデックスを設定します。

インデックスの列がwhere句やテーブル結合の条件で使用されてはじめて機能します。

インデックスがある列のデータが更新されると、インデックスも更新されます。
→検索は早いが更新は遅いという状態になります。

 

INDEX UNIQUE SCAN

1.where句で主キーの値を指定して検索します。

select * from employee_data where id = '34225'

 

2.DBMS_XPLANをクリックします。

 

3.表示されたSQLを実行します。

select * from table
(dbms_xplan.display_cursor(sql_id=>'4gj1qrzg0sjr5', format=>'ALLSTATS LAST'));

 

4.実行結果が表示されます。

12行目は、「INDEX UNIQUE SCAN」をしています。
ID列の値は主キーで重複がないため一意(UNIQUE SCAN)になりました。
11行目は、取得したROWIDでEMPLOYEE_DATAにアクセスしています。

 

NESTED LOOPS

1.テーブルをinner joinで結合します。
employee_data2はemployee_dataと同じ構造で100件データがあります。
テーブルの結合は、PKのidで行っています。

select 
  e1.id,
  e2.name
from employee_data e1 
  inner join employee_data2 e2
on 
  e1.id = e2.id;

 

2.DBMS_XPLANをクリックします。

 

3.表示されたSQLを実行します。

select * from table
(dbms_xplan.display_cursor(sql_id=>'3kyz57m37ssvk', format=>'ALLSTATS LAST'));

 

4.実行結果が表示されます。

13行目は、「TABLE ACCESS FULL」で全件検索しています。
14行目は、「INDEX UNIQUE SCAN」をしています。
12行目は、13,14行目で取得したレコードをNESTED LOOPSで結合しています。

 

HASH JOIN

1.テーブルをinner joinで結合します。
employee_data2はemployee_dataと同じ構造で100件データがあります。
テーブルの結合は、nameで行っています。

select 
  e1.id,
  e2.name
from employee_data e1 
  inner join employee_data2 e2
on 
  e1.name = e2.name;

※INDEX RANGE SCANでemployee_dataに追加したindexは削除済みです。

 

2.DBMS_XPLANをクリックします。

 

3.表示されたSQLを実行します。

select * from table
(dbms_xplan.display_cursor(sql_id=>'gg83r3wrp6ank', format=>'ALLSTATS LAST'));

 

4.実行結果が表示されます。

13行目は、「TABLE ACCESS FULL」EMPLOYEE_DATA2を全件検索しています。
14行目は、「TABLE ACCESS FULL」EMPLOYEE_DATAを全件検索しています。
12行目は、「HASH JOIN」しています。

関連の記事

Oracle SQL インデックス作成/使用のサンプル

△上に戻る