第81回 夜な夜な なにわオラクル塾 - oracle...king miller clark scott adams ford turner...

93
<Insert Picture Here> 実践!! パフォーマンス・チューニング 索引チューニング編 日本オラクル株式会社 2012042581夜な夜な! なにわオラクル塾

Upload: others

Post on 31-Jan-2021

1 views

Category:

Documents


0 download

TRANSCRIPT

  • 実践!! パフォーマンス・チューニング ~ 索引チューニング編 ~

    日本オラクル株式会社 2012年04月25日

    第81回 夜な夜な! なにわオラクル塾

  • Copyright© 2012, Oracle. All rights reserved. 2

    以下の事項は、弊社の一般的な製品の方向性に関する概要を説明するものです。また、情報提供を唯一の目的とするものであり、いかなる契約にも組み込むことはできません。以下の事項は、マテリアルやコード、機能を提供することをコミットメント(確約)するものではないため、購買決定を行う際の判断材料になさらないで下さい。オラクル製品に関して記載されている機能の開発、リリースおよび時期については、弊社の裁量により決定されます。

    OracleとJavaは、Oracle Corporation 及びその子会社、関連会社の米国及びその他の国における登録商標です。文中の社名、商品名等は各社の商標または登録商標である場合があります。

  • Copyright© 2012, Oracle. All rights reserved. 3

    本セミナーの目的とゴール

    全体

    • 索引の役割を理解し、適切な運用方法を身に付けること • 索引の種類と役割を理解する

    • Oracleデータベースの索引の種類

    • 索引の構造の理解

    • 索引が利用される条件を理解する

    • SQLの応答時間改善へのアプローチ

    • オプティマイザの理解

    • 索引を使用してのSQL応答性能改善

    • 索引のメンテナンス

  • Copyright© 2012, Oracle. All rights reserved.

    内容

    • Bツリー索引の構造 • 全表走査と索引走査のちがい

    • オプティマイザによる索引走査/全表走査の判断

    • ヒストグラムによる索引利用の効率化

    • 索引チューニングのポイント

    • さまざまな索引の種類

    4

  • Copyright© 2012, Oracle. All rights reserved.

    索引の種類

    • 索引とは

    • 百科事典についている索引のように、特定の項目を早く見つけるためのオブジェクト

    • 検索条件で使用する表の列に対して作成

    5

    索引の種類 役割

    Bツリー索引 デフォルトの設定で、最も一般的

    Bツリー・クラスタ索引 クラスタ用に定義

    ハッシュ・クラスタ索引 ハッシュ・クラスタ用に定義

    グローバル索引とローカル索引 パーティション表とパーティション索引に関連

    逆キー索引 RACアプリケーションに最も役立つ

    ビットマップ索引 サイズが小さいので、小さい値の集合を持つ列に効果的

    ファンクション索引 事前計算された関数や式の値を含む

    ドメイン索引 アプリケーションまたはカートリッジに固有の索引

    複合索引 複数列に定義されたBツリー索引

    索引構成表 表の主キーに定義された索引にデータを格納

  • Copyright© 2012, Oracle. All rights reserved.

    データ検索方法

    6

    データ検索

    索引走査

    (インデックススキャン)

    全表走査

    (フルスキャン)

    • 全表走査(フルスキャン)

    • 全てのデータを検索、比較して該当データを取得

    • 索引走査(インデックススキャン)

    • 索引にアクセスし、索引ブロックから行アドレス(ROWID)を取得

    • ROWIDを使用して直接該当データの入ったブロックにアクセス

  • Copyright© 2012, Oracle. All rights reserved.

    全表走査(フルスキャン)

    7

    EMP表

    SMITH

    ALLEN

    WARD

    KING

    MILLER

    CLARK

    SCOTT

    ADAMS

    FORD

    TURNER

    BLAKE

    TIGER

    データがバラバラに入っている

    BLAKEのデータが欲しい データブロック

    表のブロックデータを全て読み込み

    BLAKEのデータを返す

    表にあるすべての行を読み取り、 選択基準を満たしていない行を

    フィルタリング

  • Copyright© 2012, Oracle. All rights reserved.

    索引走査(インデックススキャン)

    8

    索 引

    KEY ROWID

    ALLEN rowid

    BLAKE rowid

    CLARK rowid

    EMP表

    SMITH

    ALLEN

    WARD

    KING

    MILLER

    CLARK

    SCOTT

    ADAMS

    FORD

    TURNER

    BLAKE

    TIGER

    キー順に

    並んでいる

    データの

    ある位置

    データがバラバラに入っている

    BLAKEのデータが欲しい

    少量のデータを読む場合、

    読まなければならない

    ブロックが少なくなる

    ①索引を読み込み

    BLAKEを発見

    ②索引のROWIDを利用し、

    表の中からBLAKEの

    データを読み込む

    BLAKEのデータを返す

  • Copyright© 2012, Oracle. All rights reserved.

    全表走査と索引走査

    9

    • 全表走査(フルスキャン) – 全てのデータを検索、比較する必要がある

    – マルチブロック READをサポート

    • 索引走査(インデックススキャン) – 索引は列値の昇順に格納される

    – 索引ブロックから行アドレス(ROWID)を得て直接行を検索する

    – シングルブロック READ

    – 更新時に負荷がかかる

    基本的に選択行数が少ない方が索引走査が有利になる。

  • Copyright© 2012, Oracle. All rights reserved.

    全表走査と索引走査

    10

    選択行数によっては全表走査の方が速いので、厳密に チューニングするのであれば、全表操作時と索引走査時 のタイムを測って、パフォーマンスの良い方を選択する

    例)社員番号(EMPNO) :1001~2000番の社員リストが欲しい EMP(社員)表

    • データ件数:社員番号1~2000番の2000件

    (社員番号1001~2000番の社員は全体の50%)

    • サイズ:1600KB (ブロックサイズ:8K、200ブロック(1ブロックあたり10件格納))

    select * from EMP

    where EMPNO > 1000

    and ENPNO < 2001;

    索引走査 (EMPNOに索引ありの場合)

    • I/O: 100ブロック+索引ブロック = 100+α

    全表走査 (DB_FILE_MULTIBLOCK_READ_COUNT=8の場合)

    • I/O: 200ブロック/8 = 25 1/2の絞込み

    ×

    ?

  • Copyright© 2012, Oracle. All rights reserved.

    マルチブロックREAD

    11

    1回のI/Oで複数のブロックを読み込む機能

    → DISKへのI/O回数を減らす事ができる 表

    ブロック

    8ブロック単位

    でデータを読み込む

    初期化パラメータ db_file_multiblock_read_count = 8

    全表走査 → マルチブロックREAD

    索引走査 → シングルブロックREAD

    現在のシステムは一般的に、DISK I/O ネックになる事が多いので効果大

    選択率が高くなる程、

    全表走査が有利になる

  • Copyright© 2012, Oracle. All rights reserved.

    マルチブロックREADの効果例

    12

    マルチブロックREADの設定を変えてSQL文を実行経過時間を比較

    <補足> db_file_multiblock_read_countの最大値は?

    db_file_multiblock_read_count =< 最大I/Oサイズ / db_block_size

    ※最大I/Oサイズは、オペレーティング・システムの制限を受けます。

    SQL> alter system set db_file_multiblock_read_count=1;

    SQL> SELECT * FROM employees;

    経過: 00:00:04.35

    SQL> alter system set

    db_file_multiblock_read_count=10;

    SQL> SELECT * FROM employees;

    経過: 00:00:01.37

  • Copyright© 2012, Oracle. All rights reserved.

    Bツリー索引の構成(1)

    13

    本の索引は、例えば、アルファベット順にソートされた索引だったら、 ‘A’の項目の方が‘X’の項目よりも見つけやすい(先頭に近い値が有利)

    この問題を解決して、どの値に対しても同じ工数でアクセスできるよう バランス化したのがBツリー索引

    ルートブロック

    ブランチブロック

    リーフブロック

  • Copyright© 2012, Oracle. All rights reserved.

    Bツリー索引の構成(2)

    14

    • ルートブロックからリーフブロックまでの高さが一定

    • リーフブロックには列のキー列値とROWIDを含む

    • NULL値は含まれない

    • WHERE句で頻繁に使われる列に作成すると有効

    ABE - rowid

    BABA - rowid

    ENDO - rowid

    <社員名列の索引イメージ>

    ブランチ ブロック

    リーフ

    ブロック

    ルート

    ブロック

    高さ Mよりも前

    Gよりも前

    M以降

    G以上

    ( M )

    ・・・ ・・・

    ・・・

    ( S )

    ・・・

    ( G )

  • Copyright© 2012, Oracle. All rights reserved.

    Bツリー 索引による検索イメージ

    15

    • ルートブロックから順にリーフブロックをたどって該当データを検索

    • リーフ・ブロック(最下層)には列のキー列値とROWID(物理アドレス) が含まれる

    Suzukiさんのデータが欲しい

    SELECT * FROM 社員表 WHERE 社員名=‘Suzuki’;

    Abe rowid

    Baba rowid

    ・・・・・

    Fujita rowid Hirota rowid

    ・・・・・

    Mよりも前

    Gよりも前

    M以降

    G以降

    ( M )

    Morita rowid Nakata rowid

    ・・・・・

    ( S ) ( G )

    Sよりも前

    Suzuki rowid Tanaka rowid

    ・・・・・

    S以降

    どのデータにも3ブロックの索引 アクセス+対象データのブロック (計4ブロック)でアクセス可能

    社員番号 名前 勤務地 性別

    1 Tanaka 関東 男

    2 Suzuki 関東 女

    3 Yoshida 東北 男

    4 Abe 関西 女

    5 Inoue 関東 男

    ROWID1

    ROWID2

    ROWID3

    ROWID4

    ROWID5

  • Copyright© 2012, Oracle. All rights reserved.

    索引はどういう基準でつけるべき?

    • 主キーは必ず作成する • 主キー制約を設定すると索引が自動的に作られる

    • 索引をつける対象の列の選定 1. システムで発行するSQL文を洗い出して、絞込条件になる列をピックアップ

    2. 洗い出した列に対して以下の観点で索引をつけるかどうかを決める

    • レコード件数が1/50より絞り込める場合は索引をつける

    • レコード数が1/50~1/10の絞り込みの場合は、速度の向上具合と、更新に伴う性能劣化を考慮して決める

    • レコード数が1/10より絞り込めない場合は索引をつけない

    • 実際のしきい値はレコード長など各種条件によって異なるので、あくまでも目安とすること

    3. SQLパフォーマンスチューニングに関する知識があれば、結合対象列、ソート対象列についても索引をつけることを検討する

    16

  • Copyright© 2012, Oracle. All rights reserved.

    索引を使う欠点

    17

    表データと索引データを更新しなければならない

    → 更新処理においては、負荷がかかる

    NAME SAL …

    ALLEN 100

    BLAKE 500

    CLARK 300

    EMP表

    NAME列の索引 SAL列の索引

    key rowid

    100 rowid

    300 rowid

    500 rowid

    key rowid

    ALLEN rowid

    BLAKE rowid

    CLARK rowid

    … 更新

    更新 更新

    • あまりたくさんつけない • 検索は早くなるが更新が遅くなる

    • 絞込みがあまり出来ない場合は索引をつけない方が検索が早い

  • Copyright© 2012, Oracle. All rights reserved. 18

    オプティマイザによる索引走査/全表走査の判断

  • Copyright© 2012, Oracle. All rights reserved.

    SQL文の処理ステップ

    1. 発行されたSQL文はパーサーによってパース(解析)

    • SQL文の構文チェック、意味チェック(表、列が存在するか等)

    • 「同一SQL文」が共有プールにキャッシュされているかチェック

    • キャッシュに存在すれば、すぐに実行する(soft parse)

    • キャッシュに存在しなければ、オプティマイザによる処理を行う(hard parse)

    2. オプティマイザにより最適な実行計画を検討

    • 索引を利用するか、全表走査するか

    • 複数表を結合する場合にどの順番で、どの結合方法を使うかetc

    3. ジェネレータがオプティマイザが生成した実行計画を受け取り、実行

    19

    オプティマイザ

    SQL文

    パーサ(Parser) SQL実行

    出力

    行ソース

    ジェネレータ

    Soft Parse

    Hard Parse

  • Copyright© 2012, Oracle. All rights reserved.

    SQL文の実行計画

    • 実行計画の調べ方 • SQL*PLUSのAUTOTRACEコマンド

    • Explain plan for

    • SQLトレース

    • V$SQL及びV$SQL_PLAN

    • Oracle Enterprise Manager

    • SQL Developer

    20

    1. SYSユーザでPLUSTRACEロールを作成し、SQLを実行するユーザに付与する。

    SQL> @%ORACLE_HOME%¥sqlplus¥admin¥plustrce.sql

    SQL> GRANT plustrace TO scott;

    2. SQLを実行するユーザで実行計画を保存するための表(PLAN_TABLE)を作成する。

    SQL> connect scott/tiger

    SQL> @%ORACLE_HOME%¥rdbms¥admin¥utlxplan.sql

    3. AUTOTRACE 機能を ON にし、SQL文を実行する。

    SQL> SET AUTOTRACE ON

    SQL> SELECT ...

  • Copyright© 2012, Oracle. All rights reserved.

    実行計画の例

    21

    SELECT last_name,department_name FROM employees JOIN departments USING (department_id);

    ------------------------------------------------------------------------------------

    | Id | Operation | Name | Rows | Bytes | Cost (%CPU)|・・・ ------------------------------------------------------------------------------------

    | 0 | SELECT STATEMENT | | 106 | 2862 | 6 (17)|

    | 1 | MERGE JOIN | | 106 | 2862 | 6 (17)|

    | 2 | TABLE ACCESS BY INDEX ROWID| DEPARTMENTS | 27 | 432 | 2 (0)|

    | 3 | INDEX FULL SCAN | DEPT_ID_PK | 27 | | 1 (0)|

    |* 4 | SORT JOIN | | 107 | 1177 | 4 (25)|

    | 5 | TABLE ACCESS FULL | EMPLOYEES | 107 | 1177 | 3 (0)|

    SELECT last_name,department_name FROM employees JOIN departments USING (department_id) WHERE department_id=10;

    ------------------------------------------------------------------------------------------

    | Id | Operation | Name | Rows | Bytes | Cost (%CPU)|・・・ ------------------------------------------------------------------------------------------

    | 0 | SELECT STATEMENT | | 1 | 27 | 2 (0)|

    | 1 | NESTED LOOPS | | 1 | 27 | 2 (0)|

    | 2 | TABLE ACCESS BY INDEX ROWID| DEPARTMENTS | 1 | 16 | 1 (0)|

    |* 3 | INDEX UNIQUE SCAN | DEPT_ID_PK | 1 | | 0 (0)|

    | 4 | TABLE ACCESS BY INDEX ROWID| EMPLOYEES | 1 | 11 | 1 (0)|

    |* 5 | INDEX RANGE SCAN | EMP_DEPARTMENT_IX | 1 | | 0 (0)|

    結合方法 EMPLOYEES表への アクセス方法

    DEPARTMENTS表への アクセス方法

  • Copyright© 2012, Oracle. All rights reserved.

    オプティマイザとは

    • オプティマイザ:問合せの結果を生成する最も効率的な方法 (物理的なアクセス手順)を決定し、実行計画を作成する機能

    • 索引を利用するか

    • 全表スキャンを利用するか

    • 複数の表を結合するときに、結合順序/結合方法はどうするかなど

    • ルールベースオプティマイザ(RBO)

    • あらかじめ定義されたルール、ランキングに基づいて実行計画を生成

    • SQL文の書き方のみでアクセスパスが決まり、データの量/特性に依存しない

    • Oracle 10g 以降ではサポートされない

    • コストベースオプティマイザ(CBO)

    • オプティマイザ統計に基づきコストを算出し、最もコストの低い実行計画を生成

    • データの量/特性によってアクセスパスが決まる

    22

  • Copyright© 2012, Oracle. All rights reserved. 23

    ヒストグラムによる索引利用の効率化

  • Copyright© 2012, Oracle. All rights reserved.

    最適でないアクセスパスの選択例1

    • 10000件のうち5000件がヒットしているにもかかわらず索引スキャン

    24

    SQL> SELECT * FROM emp WHERE deptno=1;

    実行計画 ----------------------------------------------------------------------------------------

    | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |

    ----------------------------------------------------------------------------------------

    | 0 | SELECT STATEMENT | | 4953 | 2437K| 2378 (1)| 00:00:29 |

    | 1 | TABLE ACCESS BY INDEX ROWID| EMP | 4953 | 2437K| 2378 (1)| 00:00:29 |

    |* 2 | INDEX RANGE SCAN | DEPT_IDX | 4953 | | 11 (0)| 00:00:01 |

    ----------------------------------------------------------------------------------------

    SQL> SELECT COUNT(*) FROM emp WHERE deptno=1;

    COUNT(*)

    ----------

    5000 ⇒10000件のうち5000件がHit

  • Copyright© 2012, Oracle. All rights reserved.

    最適でないアクセスパスの選択例2

    • 10000件のうち1件しかヒットしてないにもかかわらず全表スキャン

    25

    SQL> SELECT * FROM emp WHERE deptno>500;

    実行計画 --------------------------------------------------------------------------

    | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |

    --------------------------------------------------------------------------

    | 0 | SELECT STATEMENT | | 8 | 4120 | 204 (0)| 00:00:03 |

    |* 1 | TABLE ACCESS FULL| EMP | 8 | 4120 | 204 (0)| 00:00:03 |

    --------------------------------------------------------------------------

    SQL> SELECT COUNT(*) FROM emp WHERE deptno>500;

    COUNT(*)

    ----------

    1 ⇒10000件のうち1件がHit

  • Copyright© 2012, Oracle. All rights reserved.

    EMP表の状態

    • データの分布に偏りがある

    26

    合計:10000件

    * deptno= 1~200にデータが分布 特異値としてdeptno=1000を1件

    * DEPTNOに対してDEPT_IDX という索引を作成

  • Copyright© 2012, Oracle. All rights reserved.

    なぜ最適でないアクセスパスが選択されるのか?

    • オプティマイザは、列値は最小値と最大値間に均一に分散していると考える

    • 実際の値の分布に偏りがある場合、最適でないアクセスパスを選択する場合がある

    27

    DEPTNO

    10人

    人数

    DEPTNO

    5000人

    人数

    1 2 3 4 ・・・

    ・・・

    998 999 1000 1 2 3 4 ・・・

    ・・・

    199 200 1000

    1000の部門にそれぞれ10人ずつ均等に配属されている

    部門番号1の部門に

    社員が5000人(全体の50%) 配属されている

    全体の1% 全体の50%

    索引走査 全表走査

    オプティマイザの判断 実際

  • Copyright© 2012, Oracle. All rights reserved.

    データの分布に偏りがある場合の解決法

    • ヒストグラムを作成することで改善する可能性 • データの分布状況を統計情報として取得できる

    • データの実際の分布状況に応じて最適なアクセスパスを選択できる

    • 検索対象データ数が少ない場合は索引スキャン

    • 検索対象データ数が多い場合は全表スキャン

    28

  • Copyright© 2012, Oracle. All rights reserved.

    ヒストグラムの種類

    • ヒストグラムの種類 • 頻度分布ヒストグラム(Frequency)

    • それぞれの値が何行あるか正確に記録できる

    • 値の種類数が254以下である場合に作成できる

    • 高さ調整ヒストグラム(Hight Balanced)

    • 頻度分布ほど正確ではないがデータの偏りを検出できる

    29

    SQL> exec DBMS_STATS.GATHER_TABLE_STATS (

    ownname=>スキーマ名,

    tabname=>表名,

    estimate_percent =>100(サンプリング率),

    method_opt=>'FOR COLUMNS SIZE n deptno',

    cascade =>TRUE(索引の情報も取得するか));

    FOR ALL INDEXED COLUMNS:すべての索引列について取得

    FOR ALL COLUMNS:すべての列について取得

    FOR COLUMN 列名:特定の列について取得

    SIZE AUTO:ヒストグラム・バケット数を自動設定

    SiZE n:ヒストグラム・バケット数を指定

    FOR ALL COLUMNS SIZE AUTO

    :どの列にヒストグラムが必要かOracleが判別

  • Copyright© 2012, Oracle. All rights reserved.

    頻度分布ヒストグラム

    • method_opt引数で列の種類数よりも大きな値を指定する

    30

  • Copyright© 2012, Oracle. All rights reserved.

    頻度分布ヒストグラム

    • それぞれの値が何行あるか正確に記録される

    31

    SQL> SELECT endpoint_value, endpoint_number

    2 > FROM user_tab_histograms

    3 > WHERE table_name='EMP' and

    4 > column_name='DEPTNO’

    ENDPOINT_VALUE ENDPOINT_NUMBER

    -------------- ---------------

    1 5000

    2 5025

    3 5050

    ・・・ ・・・ 199 9975 200 9999

    1000 10000

    1

    10

    100

    1000

    10000

    1 2 3 4 198 199 200 1000 DEPTNO

    件数

    ・・・

  • Copyright© 2012, Oracle. All rights reserved.

    高さ調整ヒストグラム

    • method_opt引数で列の種類数よりも小さな値を指定する

    32

  • Copyright© 2012, Oracle. All rights reserved.

    高さ調整ヒストグラム

    • 頻度分布ヒストグラムほど正確ではないが、ヒストグラムなしよりも精度が高い

    • 指定したバケット数で分割し、ソートした上で同じ件数ずつバケットに格納

    • 各バケットの最後の値(endpoint_value)を記録し、データの偏りを検出するために使う

    • 複数バケットのendpoint_valueが等しければ、他の値よりも多く存在する(ポピュラー値)

    • 領域使用率向上のためポピュラー値がある場合には、最後のバケット情報のみ記録

    33

    DEPTNO

    件数

    SQL> SELECT endpoint_value, endpoint_number

    2 > FROM user_tab_histograms

    3 > WHERE table_name='EMP'

    4 > column_name='DEPTNO’

    ENDPOINT_VALUE ENDPOINT_NUMBER

    -------------- ---------------

    1 12

    9 13

    25 14

    41 15

    ・・・ ・・・ 169 23

    185 24

    1000 25 0

    0.2

    0.4

    0.6

    0.8

    1

    0 1 2 3 4 13 14 15 23 24 25

    ・・・ ・・・

  • Copyright© 2012, Oracle. All rights reserved.

    高さ調整ヒストグラムのイメージ

    34

    DBMS_STATS.GATHER_TABLE_STATS (

    ownname =>スキーマ名, tabname => 表名,

    estimate_percent => 100,

    block_sample => FALSE,

    method_opt =>'FOR ALL INDEXED COLUMNS SIZE 4',

    cascade =>TRUE);

    12件のデータ

    ( 1が3分の2 ) 1 1 1 1 1 1 1 1 5 12 20 100

    全体をつ4のバケットに分割

    1 1 1 1 1 1 1 1 5 12 20 100

    データの最小値 と 各々のバケットの最大値 を統計情報に加える

  • Copyright© 2012, Oracle. All rights reserved.

    高さ調整ヒストグラムのイメージ

    35

    1 1 1 5 100

    ヒストグラムで偏りを調べると 1以下のバケットは2つなので 全体の50%→ 全表走査

    SELECT * FROM 表 WHERE 列 = 1;

    ヒストグラムを使わない → 索引操作

    各々のバケットの最大値

  • Copyright© 2012, Oracle. All rights reserved.

    ヒストグラム利用方法

    <補足>

    • バケット数

    • デフォルトのバケット数(75)がほとんどの場合に有効

    • よりよい結果を得るために、別の値を試す事も必要

    • ヒストグラムを使っても意味がないケース

    • where 句で使用されない列

    • データが均一に分布している表

    • 列が一意で等価検索しかされない

    36

    • ヒストグラムが存在しない場合

    • CBOは値の最小値~最大値の間にデータが均一に分散されていると考える

    • ヒストグラムが存在する場合

    • CBOはデータの分布状況を見て最適なアクセスパスを選択できる

  • Copyright© 2012, Oracle. All rights reserved.

    ヒストグラム統計収集の自動化

    • 9i以前のデータベースでは、データ分布が均一でないためにパフォーマンスが劣化している部分についは、手動でヒストグラム情報を取得する必要

    • 10gからの自動オプティマイザ統計収集では、ヒストグラム関連の統計情報がデフォルトで取得される

    37

  • Copyright© 2012, Oracle. All rights reserved. 38

    索引チューニングのポイント

  • Copyright© 2012, Oracle. All rights reserved.

    索引がうまく使われない4つのパターン

    39

    索引を作成したのに検索が遅い時どう考えれば良いか? <4つのチェックポイント>

    1. 索引を使用する事で速くなる処理か?

    2. 索引を利用できるSQL文か?

    3. オプティマイザが索引利用を選択しているか?

    4. 索引のメンテナンスをしているか?

  • Copyright© 2012, Oracle. All rights reserved.

    1.索引を使用する事で速くなる処理か? 全表走査と索引走査

    40

    • 表のサイズや選択率(選択行数)によっては全表走査の方が速い可能性

    選択率が高い場合には

    全表走査が有利

    単一行へのアクセスは 索引走査が有利

    • 全表走査(フルスキャン)

    • 全てのデータを検索、比較する必要がある

    • マルチブロック READにより、少ないI/O 回数でデータをみ込むことができる

    • 索引走査(インデックススキャン)

    • 索引から行アドレス(ROWID)を得て、単一の ブロックを読み込むことができる

    全表走査 索引走査

    表のサイズ 小 表が大きいほど読み込むデータ量が増加するので、表が大きい場合には向かない

    大 大量のデータがあっても読み込むデータは 一部なので、大きい表にも有効

    検索対象の割合 多 検索対象の割合が多い場合には、全てのブロックを読み込んだほうが効率的

    少 大きな表から一部のデータを読み込む場合に効率的

    読み込み方 マルチブロックREAD シングルブロックREAD

  • Copyright© 2012, Oracle. All rights reserved. 41

    <参考>索引作成の基準

    • 検索対象となる列に対して以下の観点で索引をつけるかどうかを決める

    (実際のしきい値はレコード長など各種条件によって異なるので、あくまでも目安として)

    レコード件数が1/50より絞り込める場合は索引をつける

    レコード数が1/50~1/10の絞り込みの場合は、速度の向上具合と、更新に伴う性能劣化を考慮して決める

    レコード数が1/10より絞り込めない場合は索引をつけない

    厳密にチューニングするのであれば、全表走査時と索引走査時の タイムを測って、パフォーマンスの良い方を選択する

    どれくらいの選択率なら 索引を付けた方がいいの?

  • Copyright© 2012, Oracle. All rights reserved.

    1.索引を使用する事で速くなる処理か? 索引の限界

    42

    • 索引検索でもパフォーマンスが上がらないケース

    • 表サイズが大きく、検索対象データも多い場合、索引と表に大量のアクセスが 発生するため、パフォーマンスがあがらない

    4月の売上 データを集計したい

    4月1日のデータを 検索したい

    大量の索引読み込みが行われる検索では、 索引を使ってもDISK I/Oがボトルネックになることも

    内部的に 表を分割

    1月

    2月

    3月

    4月

    5月

    6月

    7月

    8月

    4月の売上 データを集計したい マルチブロック

    READ

    パーティショニング機能で 読み込みを効率化

    パーティショニング機能とは

    • 単一の表を内部的に複数の 領域に分割して格納する機能

    • 表名等は変わらないため、 SQLの変更は不要

  • Copyright© 2012, Oracle. All rights reserved.

    2.索引を利用できるSQL文か? 索引が使われないSQL文

    43

    • SQL文によっては、索引があっても使用されない可能性 • 索引列に対してNULL条件やNOT条件が使用されている場合

    • 条件式に計算を含む場合

    • LIKE条件を使った中間一致・後方一致検索をする場合

  • Copyright© 2012, Oracle. All rights reserved.

    2.索引を利用できるSQL文か? NULL条件やNOT条件が使用されている場合

    44

    SELECT EFROM EMP WHERE COMM IS NULL ;

    SELECT ENAME FROM EMP WHERE DEPTNO = 30 ;

    • IS NULLやIS NOT NULL条件を使用した検索例

    COMM列に索引がある場合

    SELECT ENAME FROM EMP WHERE COMM IS NOT NULL;

    • NOT条件を使用した検索例

    DEPTNO列に索引がある場合

    SELECT ENAME FROM EMP WHERE COMM = 0.1;

    SELECT ENAME FROM EMP WHERE DEPTNO != 30 ;

  • Copyright© 2012, Oracle. All rights reserved.

    2.索引を利用できるSQL文か? 条件式に計算や関数を含む場合

    45

    SELECT ENAME FROM EMP WHERE SAL*1.1 > 10000;

    SELECT ENAME FROM EMP

    WHERE HIREDATE = TO_DATE('010403','DDMMYY');

    • 列に計算式を含む検索例

    SAL列に索引がある場合

    • 列に関数を使用する検索例

    HIRE_DATE列に索引がある場合

    SELECT ENAME FROM EMP WHERE SAL > 10000/1.1;

    SELECT ENAME FROM EMP

    WHERE TO_CHAR( HIREDATE,'DDMMYY')='010403’;

  • Copyright© 2012, Oracle. All rights reserved.

    2.索引を利用できるSQL文か? LIKE条件を使った検索をする場合

    46

    SELECT ENAME FROM EMP WHERE ENAME LIKE ‘Su%';

    SELECT ENAME FROM EMP WHERE ENAME LIKE '%zu%';

    SELECT ENAME FROM EMP WHERE ENAME LIKE '%ki';

    • 索引は昇順、降順にデータが並べられているため、前方一致には 索引が使われるが、中間一致・後方一致では索引が使われない

    • LIKE条件を使った検索例

    SAL列に索引がある場合

  • Copyright© 2012, Oracle. All rights reserved.

    3.適切な実行計画が選択されているか? オプティマイザと実行計画

    47

    • オプティマイザが適切な実行計画を選択していない可能性

    • 実行計画を確認する

    • 適切な実行方法を指定(ヒント)

    1. SYSユーザでPLUSTRACEロールを作成し、SQLを実行するユーザに付与する。

    SQL> @%ORACLE_HOME%¥sqlplus¥admin¥plustrce.sql

    SQL> GRANT plustrace TO scott;

    2. SQLを実行するユーザで実行計画を保存するための表(PLAN_TABLE)を作成する。

    SQL> connect scott/tiger

    SQL> @%ORACLE_HOME%¥rdbms¥admin¥utlxplan.sql

    3. AUTOTRACE 機能を ON にし、SQL文を実行する。

    SQL> SET AUTOTRACE ON

    SQL> SELECT ...

    参考 実行計画の調べ方 (SQL*PlusのAUTOTRACE機能)

    SQL文

    SQLの実行

    オプティマイザが実行計画を生成

    ない

    オプティマイザが 索引を使うか使わないかの

    判断をする

    メモリ上に 実行計画があるか

    プログラム

    ある

  • Copyright© 2012, Oracle. All rights reserved.

    3.適切な実行計画が選択されているか? 効率的な実行計画が立てられない場合

    48

    SELECT name FROM emp WHERE deptno=20 AND job=‘営業’;

    EMPには10,000行

    DEPTNO列とJOB列には索引がある

    DEPTNO列のうちDEPTNO=20の占める割合は30%

    JOB列の値のうち営業が占める割合は30%

    コストベースオプティマイザの分析

    予想されるI/O ⇒1万行×30%×30% = 900行(全体の9 %と判断)

    ⇒ コストを比較した結果JOB列の 索引走査 を選択

    • データの偏りなどにより、コストベース・オプティマイザが最適な実行計画を立てられない場合

    実際 : 営業のDEPTNOが20で、営業のほとんど人の DEPTNOが20だった場合 1万行 × 30% = 3000行 (全体の30%)

    ⇒全表走査のほうが効率的

    ⇒ ヒントによる チューニング

  • Copyright© 2012, Oracle. All rights reserved.

    3.適切な実行計画が選択されているか? ヒントによるチューニング(全表走査)

    49

    • ヒント:コストベースオプティマイザに、より良い実行方法を指定する手法

    • 適切な索引の使用や、結合順序の指定、処理の優先度(スループット重視 or OLTP向き)をSQL文の中で指定

    • /*+ と */ の間でヒントを指定し、SQLに直接埋め込む

    SELECT name FROM emp WHERE deptno=20 AND job=‘営業’;

    実際 : 営業のDEPTNOが20で、営業のほとんど人の DEPTNOが20だった場合 1万行 × 30% = 3000行 (全体の30%) ⇒全表走査のほうが効率的

    SELECT /*+ FULL(emp)*/ NAME FROM emp

    WHERE deptnp=20 AND job=‘営業’;

    全表走査を実行 させる「ヒント」

    ヒントを使って全表走査を指定

  • Copyright© 2012, Oracle. All rights reserved.

    3.適切な実行計画が選択されているか? ヒントによるチューニング(索引スキャン)

    50

    <例> sales表の「cust_id_indx」索引を使用させる

    SELECT /*+ INDEX(sales cust_id_indx) */

    sales_date,sales_amount

    FROM sales

    WHERE customer_id=100;

    • /*+ INDEX(表 索引名) */

    • 特定の索引を使用するようオプティマイザに指示する

    • 一つの表に複数の索引がある場合、最適な索引を指示することができる

    索引を指定する 「ヒント」

  • Copyright© 2012, Oracle. All rights reserved.

    3.適切な実行計画が選択されているか? ヒントによるチューニング(高速全索引スキャン)

    51

    • /*+ INDEX_FFS ( 表 索引… ) */

    • 高速全索引スキャンを実行するようオプティマイザに指示する

    • 索引の中に求めるデータがすべてあるため、索引をマルチブロックREADで 読み込むことで、必要なデータを取得することができる (表にアクセスする必要がない)

    <例> 高速全索引スキャン

    CREATE TABLE emp

    (empno NUMBER(10) PRIMARY KEY,

    name VARCHAR2(30) NOT NULL(※), salary NUMBER(10),

    deptno NUMBER(5));

    CREATE INDEX name_idx

    ON emp(name);

    (※)高速全索引スキャンは、索引キー内の列の少なくとも1つの

    列にNOT NULL制約がついている必要がある

    表アクセス不要

    SELECT /*+ INDEX_FFS(emp name_idx) */ name

    FROM emp;

    nameの一覧の問い合わせ

    索引を読めば、NAMEの データが取得できる

    (表へのアクセスは不要)

  • Copyright© 2012, Oracle. All rights reserved.

    3.適切な実行計画が選択されているか? ヒントを書くときの注意点

    • ヒントの指定方法が間違っていた場合、ヒントは無視される • 索引名や表名が間違っていた場合

    • 表名に表別名が指定されていた場合

    エラー出力はされないため、ヒント指定後は必ず実行計画を確認

    • ヒント内で索引が複数指定されている場合は、最もコストが低い索引が 使用される

    • ヒントの使用により、実行計画が固定されてしまう • 最適な実行計画は、データの件数、値によって変わってくる可能性があるが ヒントを指定することで実行計画が固定されてしまう

    定期的なヒントの見直しが必要

    52

    <例> SELECT /*+ INDEX(e deptno_index) */

    name

    FROM emp e WHERE deptno=20;

    ヒント内で表名「emp」を 指定すると、ヒントが

    無視される

  • Copyright© 2012, Oracle. All rights reserved.

    <参考>SQLプロファイルによる実行計画の最適化

    53

    実行計画がどのように変わるのかを確認

    統計の追加により、索引スキャンを選択するように変わり、見積もり時間も大幅

    に短くなっている

    SQLチューニングアドバイザによるチューニング

  • Copyright© 2012, Oracle. All rights reserved.

    4.索引のメンテナンスをしているか? 索引メンテナンスの必要性

    • 表のメンテナンスに伴う索引のメンテナンス

    • 表データを移動した場合(MOVEコマンド等)

    • 索引内のアドレスと行データのアドレスが異なり、索引が使用できない可能性

    • 索引の断片化に伴うメンテナンス

    • データを追加、削除、変更した場合

    • 索引ブロックが断片化し、パフォーマンスが劣化する可能性

    • 不要な索引のメンテナンス

    • 使われていない索引があることにより、DML文のパフォーマンスに悪影響を 与える可能性

    54

    索引の定期的なメンテナンスが必要

  • Copyright© 2012, Oracle. All rights reserved.

    4.索引のメンテナンスをしているか? 索引断片化の例(データを追加する場合)

    55

    1~ 51~

    1~ 27~

    51~ 76~

    1 3 5 ・・・ 23 25

    27 29 31 ・・・ ・・・ 49

    51 53 55 ・・・ ・・・ 75

    77 79 81 ・・・ 98 99

    1~ 51~

    1~ 24~ 27~

    51~ 76~

    1 3 5 ・・・ 23

    24 25

    51 53 55 ・・・ ・・・ 75

    77 79 81 ・・・ ・・・ 99

    27 29 31 ・・・ ・・・ 49

    ブロックが 分割される

    <例>昇順にデータを追加した場合

    • INSERT 98 INSERT 99

    <例>ランダムにデータを追加した場合

    • INSERT 24

    • 昇順にデータを追加するよりもランダムに追加する方が断片化しやすい

    最後の ブロックに 追加される

    ※スライドの図はイメージあり、厳密な索引構造ではありません

  • Copyright© 2012, Oracle. All rights reserved.

    4.索引のメンテナンスをしているか? 索引断片化の例(データを変更・削除する場合)

    56

    51~

    27~ 76~

    1 3 5 ・・・ 23 25

    27 29 31 ・・・ ・・・ 49

    51 53 55 ・・・ ・・・ 75

    77 79 81 ・・・ ・・・ 99

    51~

    27~ 76~

    <例>データを削除した場合

    • DELETE 23,31,53,81

    <例>データを変更した場合

    • UPDATE 23 ⇒ 24

    削除

    • データを更新・削除すると、削除済みエントリが残る

    • データを削除した場合:論理削除のみが行われる(領域は減らない)

    • データを更新した場合:論理削除とデータの追加が行われる(領域が増える)

    1 3 5 ・・・ 23

    24 25

    51 53 55 ・・・ ・・・ 75

    77 79 81 ・・・ ・・・ 99

    27 29 31 ・・・ ・・・ 49

    削除 古いエントリを論理削除し、 新しいエントリを追加

    論理削除が

    行われる

    ※スライドの図はイメージあり、厳密な索引構造ではありません

  • Copyright© 2012, Oracle. All rights reserved.

    4.索引のメンテナンスをしているか? 索引構造情報の分析方法

    57

    ANALYZE INDEX 索引名 VALIDATE STRUCTURE ;

    • 索引構造の分析

    • 索引に含まれるブロック数や高さ

    • 索引に含まれている削除済みエントリ数

    INDEX_STATS データディクショナリに分析結果を格納

    SQL> SELECT blocks,pct_used,lf_rows,del_lf_rows FROM index_stats;

    BLOCKS PCT_USED LF_ROWS DEL_LF_ROWS HEIGHT ------ -------- ------- ----------- ------

    56 54 4373 949 2

    主な項目 BLOCKS 使用ブロック数

    PCT_USED 領域の使用率(%)

    LF_ROWS 全リーフ行数(削除済み含)

    DEL_LF_ROWS 削除されたリーフの行数

    HEIGHT Bツリーの高さ

  • Copyright© 2012, Oracle. All rights reserved.

    4.索引のメンテナンスをしているか? 索引再構築の目安

    • メンテナンスの目安 • 領域の使用比率(PCT_USED)を定期的に監視し、使用率が低下したら 再構築を検討

    • 一般的に、下記の数値を超えたタイミングで再構築を検討

    • 階層の高さが4階層以上 ( HEIGHT => 4 )

    • 削除された行エントリーの占める割合が20~30%を越える場合 ( DEL_LF_ROW/LF_ROWS > 0.2 )

    • 表に対する大量データ操作の後、再構築

    • 大量のデータを追加・削除した場合 例:夜間に大量のデータをローディングした

    • 表のメンテナンスをした場合 例:ALTER TABLE MOVEコマンドなどで表を移動した場合

    • ある程度傾向をみて定期バッチで再構築 (データの更新量により、1回/1週間~1回/1ヶ月)

    58

  • Copyright© 2012, Oracle. All rights reserved.

    4.索引のメンテナンスをしているか? 索引の再構築

    59

    • 索引の再構築方法

    • 索引の再作成(削除して再作成)

    •索引のREBUILD

    ALTER INDEX 索引名 REBUILD; 索引のREBUILD

    • 既存の索引をもとに索引を作成し、新しい索引の作成後、古い索引を削除

    • 索引のREBUILDのメリット

    • 既存の索引(ソート済みのデータ)をもとに、新しく索引を作成するため、一から索引を作成するよりも高速

    • 索引の再構築中も、古い索引を使用してアクセス(SELECT)可能

    • オンライン再構築(索引の再構築中にDML操作可能)が可能 (注意:オンライン再構築はEnterprise Editionの機能です)

    • 索引のREBILDのデメリット

    • 新しい索引を索引してから古い索引を削除するので、一時的に2倍の 領域が必要

  • Copyright© 2012, Oracle. All rights reserved.

    4.索引のメンテナンスをしているか? 索引の作成のテクニック

    • 索引作成のパラレル化 • 高速に索引を作成(Enterprise Editionの機能)

    • 問合せサーバー・プロセスごとに別々の記憶域パラメータが使用

    • INITIAL値を5MB、並行度を12で索引を作成する場合は、作成時に60MB以上の記憶域を使用

    • 索引作成時のNOLOGGINGの使用 • CREATE INDEX文でNOLOGGINGを指定すると、索引の作成時の

    REDOログ生成を最小限におさえる

    • REDOログ・ファイルの領域を節約

    • 索引の作成に要する時間が削減

    • 大規模な索引のパラレル作成のパフォーマンスが向上

    60

  • Copyright© 2012, Oracle. All rights reserved.

    4.索引のメンテナンスをしているか? 未使用索引の確認と削除

    61

    ALTER INDEX 索引名 MONITORING USAGE;

    ALTER INDEX 索引名 NOMONITORING USAGE;

    • 使用されていない索引を特定し、削除する

    • 使われていない索引が無駄な領域をとるのを防ぐため

    • 更新操作のボトルネックになるため

    • 未使用索引の特定方法

    この間、索引が使われたかどうかを監視し、 使用状況をV$OBJECT_USAGEビューに格納

    未使用索引の監視

    SELECT index_name,used FROM V$OBJECT_USAGE;

    INDEX_NAME USED

    --------------- ---

    DEPT_ID_IDX YES

    EMP_ID_IDX NO

    「USED」列が「NO」の索引は、この期間使用されなかった

  • Copyright© 2012, Oracle. All rights reserved.

    4.索引のメンテナンスをしているか? Enterprise Managerを活用した削除候補の確認

    62

    SQLアクセスアドバイザで索引削除のアドバイスが可能

    ワークロードの有効範囲に「完全なワークロード」を選択

    アドバイザ結果例

  • Copyright© 2012, Oracle. All rights reserved.

    4.索引のメンテナンスをしているか? 索引削除前の影響の確認

    • 索引を削除する前に削除によって発生する影響をテストする場合使用禁止索引・不可視索引を使用

    • 使用禁止索引

    • オプティマイザで無視され、DMLではメンテナンスされない

    • 初期化パラメータSKIP_UNUSABLE_INDEXESがTRUE(デフォルト)の場合

    • 表に対するDML文は続行されますが、使用禁止索引のメンテナンスは実行されない

    • 一意制約を規定する使用禁止索引がある場合は、DML文はエラーで終了

    • SKIP_UNUSABLE_INDEXESがFALSEの場合

    • DML文はエラーで終了

    • SELECT文は使用禁止索引を使用する場合、文はエラーで終了

    • 不可視索引

    • 不可視索引はDML文中でも維持される

    • OPTIMIZER_USE_INVISIBLE_INDEXES初期化パラメータを明示的にTRUEに設定しないと使用されない

    • 索引を削除する前に、削除した状態をテスト可能

    • アプリケーション全体に影響を与えずに、アプリケーションの特定の操作またはモジュールに対して一時的な索引構造を使用可能

    63

    バルク・ロードのパフォーマンスを向上させる場合、

    オプティマイザによるその索引の使用を停止する場合 にも活用

  • Copyright© 2012, Oracle. All rights reserved.

    索引を作成したのに検索が遅い! 索引チューニング 4つのチェックポイントの整理

    1. 索引を使用する事で速くなる処理か? • 表のサイズや選択率(選択行数)によっては全表走査の方が速い可能性

    • 大量の索引読み込みが行われる検索ではパーティショニングが有効

    2. SQLの構文によっては、索引があっても使用されない可能性 • 索引列に対してNULL条件やNOT条件が使用されている場合

    • 条件式に計算を含む場合

    • LIKE条件を使った中間一致・後方一致検索をする場合

    3. オプティマイザが適切な実行計画を選択していない可能性 • 実行計画を確認し、適切な実行方法を指定(ヒント)

    4. 表のメンテナンスに伴う索引のメンテナンス • 表データを移動した場合(MOVEコマンド等)

    • 索引の断片化に伴うメンテナンス

    • 不要な索引のメンテナンス

    64

  • Copyright© 2012, Oracle. All rights reserved. 65

    様々なタイプの索引

  • Copyright© 2012, Oracle. All rights reserved.

    ビットマップ索引とは?

    66

    • 列値と各レコードがその値に該当するか否かをビットで表した索引

    • 検索処理ではビットの有無で条件に該当するか否かが判定される

    ROWID 関東 関西 東北

    ROWID1 1 0 0

    ROWID2 1 0 0

    ROWID3 0 0 1

    ROWID4 0 1 0

    ROWID5 1 0 0

    勤務地列のビットマップ索引

    番号 名前 勤務地 性別

    1 Tanaka 関東 男

    2 Suzuki 関東 女

    3 Yoshida 東北 男

    4 Abe 関西 女

    5 Inoue 関東 男

    ROWID1

    ROWID2

    ROWID3

    ROWID4

    ROWID5

    ROWID 男 女

    ROWID1 1 0

    ROWID2 0 1

    ROWID3 1 0

    ROWID4 0 1

    ROWID5 1 0

    性別列のビットマップ索引

    社員表

    Abe rowid

    Baba rowid

    ・・・・・

    Hirota rowid

    Inoue rowid ・・・・・

    AからL

    AからG

    MからZ

    HからL

    A~ 左 M~ 右

    Morita rowid Nakano rowid

    ・・・・・

    M~左 S~ 右

    A~ 左 H~ 右

    MからR

    Suzuki rowid Tanaka rowid

    ・・・・・

    SからZ

    名前列の Bツリー索引

  • Copyright© 2012, Oracle. All rights reserved.

    ビットマップ索引の特徴と作成例

    67

    • カーディナリティの低い(値の種類が少ない)列に有効 • 地域(東北・関東・中部・関西 など)

    • 性別(男・女) 年代(10代・20代・30代 など)

    • 複数の列をWHERE条件に指定している場合、各列にビットマップ索引を作成しておくことで、ビット演算による高速な検索を行うことが可能 • 関東に住んでいる20代男性

    • 製品Aを買った男性 など

    • ビットマップ索引の作成例 • CREATE INDEX文で「BITMAP」を指定

    ROWID 関東 関西 東北

    ROWID1 1 0 0

    ROWID2 1 0 0

    ROWID3 0 0 1

    ROWID4 0 1 0

    ROWID5 1 0 0

    ROWID 男 女

    ROWID1 1 0

    ROWID2 0 1

    ROWID3 1 0

    ROWID4 0 1

    ROWID5 1 0

    関西に住んでいる 女性は?

    CREATE BITMAP INDEX 索引名 ON 表名(列名);

  • Copyright© 2012, Oracle. All rights reserved.

    Bツリー索引とビットマップ索引の比較

    68

    Bツリー索引 ビットマップ索引

    カーディナリティの高い (種類の多い)列に適している

    カーディナリティの低い (種類の少ない)列に適している

    ORを使用した検索には それほど適していない

    OR条件などのビット演算による 高速な検索を行うことが可能

    更新のオーバーヘッドが大きい 更新のオーバーヘッドが非常に大きい

    OLTP向き DWH向き

    索引のサイズ比較的大きい 索引のサイズ比較的小さい

    ROWID Tanaka Suzuki Yoshida ・・・

    ROWID1 1 0 0 0

    ROWID2 0 1 0 0

    ROWID3 0 0 1 0

    ROWID4 0 0 0 1

    ・・・ 0 0 0 0

    名前列のビットマップ索引

    男 rowid 男 rowid

    ・・・・・

    男 rowid 男 rowid

    ・・・・・

    女 rowid

    女 rowid

    ・・・・・

    女 rowid

    女 rowid

    ・・・・・

    ( 男 ) (女)

    (女 )

    性別列のBツリー索引 × ×

  • Copyright© 2012, Oracle. All rights reserved.

    逆キー索引とは?

    69

    • 索引列のデータをビット単位で反転させ、反転させたデータをソートして 索引に格納する索引

    • 索引のキー値を逆にすることにより、挿入値を索引のリーフ・キー全体 に分散させることができる

    51~

    27~ 76~

    1 3 5 ・・・ 23 25

    27 29 31 ・・・ ・・・ 49

    51 53 55 ・・・ ・・・ 75

    77 79 81 ・・・ 98 99

    INSERT 96

    INSERT 97

    INSERT 98

    INSERT 99

    <通常の索引>

    • 連続した値がINSERTされる環境では 特定のブロックにアクセスが集中

    51~

    27~ 76~

    09 19

    39 49

    59 69

    INSERT 90→09

    INSERT 91→19

    INSERT 93→39

    INSERT 94→49

    INSERT 95→59

    INSERT 96→69

    <逆キー索引>

    • 値を逆にすることによりアクセスを 分散させることが可能

    ※スライドの図はイメージあり、厳密な索引構造ではありません

  • Copyright© 2012, Oracle. All rights reserved.

    逆キー索引の特徴と作成例

    70

    • 逆キー索引のメリット

    • 索引のキー値を逆にすることにより、挿入値を索引のリーフ・キー全体に 分散させることができるため、特定の索引ブロックにアクセスが集中する ことを防ぐことが可能

    • 逆キー索引のデメリット

    • 範囲検索( 、betweenなど)に索引を使うことができない

    • ビットマップ索引の作成例

    • CREATE INDEX文で「REVERSE」を指定

    CREATE INDEX 索引名 ON 表名(列名) REVERSE;

  • Copyright© 2012, Oracle. All rights reserved.

    複合索引(コンポジット索引)とは?

    71

    • 複数の列を指定した索引

    親コード 分類 種別 製品名

    1 A あ XXX

    3 B う XXX

    ・・・ ・・・ ・・・ ・・・

    2 A い XXX

    3 C あ XXX

    ・・・ ・・・ ・・・ ・・・

    3 C か XXX

    2 A さ XXX

    ・・・ ・・・ ・・・ ・・・

    1 B い XXX

    2 B え XXX

    ・・・ ・・・ ・・・ ・・・

    • 親コードが1で、分類がAで、種別が「う」の 製品を検索

    • 親コードが3で、分類がCの製品を検索

    CREATE TABLE 製品表

    ( 親コード number(30), 分類 varchar2(30), 種別 varchar2(30), 製品名 number(10));

    以下のような製品表の索引を検討

    以下のような条件で検索を検討

  • Copyright© 2012, Oracle. All rights reserved.

    単一列索引と複合索引の作成例

    72

    親コード 分類 種別 製品名

    1 A あ XXX

    3 B う XXX

    ・・・ ・・・ ・・・ ・・・

    2 A い XXX

    3 C あ XXX

    ・・・ ・・・ ・・・ ・・・

    3 C か XXX

    2 A さ XXX

    ・・・ ・・・ ・・・ ・・・

    1 B い XXX

    2 B え XXX

    ・・・ ・・・ ・・・ ・・・

    単一列索引 それぞれの列に索引を作成

    CREATE INDEX 製品_idx

    ON 製品表(親コード,分類,種別);

    CREATE INDEX 製品_親_idx ON 製品表(親コード);

    CREATE INDEX 製品_分類_idx ON 製品表(分類);

    CREATE INDEX 製品_種別_idx ON 製品表(種別);

    複合索引 複数列にまとめて一つの索引を作成

  • Copyright© 2012, Oracle. All rights reserved.

    複合索引の構造

    73

    • 複合索引の構造

    • 指定した索引列のデータが、指定した列の順にソートされて、リーフ・ブロックに格納される

    • 単一列索引を3つ読み、マージするよりも効率的

    親コード 分類 種別 1 A あ ROWID

    1 A い ROWID

    1 A う ROWID

    1 B あ ROWID

    1 B え ROWID

    1 C あ ROWID

    2 A あ ROWID

    2 A う ROWID

    2 B あ ROWID

    2 C あ ROWID

    2 C い ROWID

    3 A い ROWID

    ・・・ ・・・ ・・・ ・・・

    ルート ブロック

    ブランチ ブロック

    リーフ ブロック

    一つ目のキー列を元に Bツリーのツリー構造が構成

    親コード 分類 種別 製品名

    1 A あ XXX

    3 B う XXX

    ・・・ ・・・ ・・・ ・・・

    2 A い XXX

    3 C あ XXX

    ・・・ ・・・ ・・・ ・・・

    3 C か XXX

    2 A さ XXX

    ・・・ ・・・ ・・・ ・・・

    1 B い XXX

    2 B え XXX

    ・・・ ・・・ ・・・ ・・・

    各キー列値ごとに階層的に ソートされて格納されている

  • Copyright© 2012, Oracle. All rights reserved.

    複合索引の検索イメージ

    74

    SELECT * FROM 製品表 WHERE 親コード=1 AND 分類 =‘A’ AND 種別 =‘う’;

    親コード 分類 種別

    1 A あ ROWID

    1 A い ROWID

    1 A う ROWID

    1 B あ ROWID

    1 B え ROWID

    1 C あ ROWID

    2 A あ ROWID

    2 A う ROWID

    2 B あ ROWID

    2 C あ ROWID

    2 C い ROWID

    3 A い ROWID

    ・・・ ・・・ ・・・ ・・・

    SELECT * FROM 製品表 WHERE 親コード=1 AND 分類=‘A’; 親コード 分類 種別

    1 A あ ROWID

    1 A い ROWID

    1 A う ROWID

    1 B あ ROWID

    1 B え ROWID

    1 C あ ROWID

    2 A あ ROWID

    2 A う ROWID

    2 B あ ROWID

    2 C あ ROWID

    2 C い ROWID

    3 A い ROWID

    ・・・ ・・・ ・・・ ・・・

    • 複合索引を使った検索例

    • 索引を使って、複数の検索条件にあった行を絞り込みが可能

    • 索引に含まれる全ての列を指定しなくても、複合索引をつかうことが可能

  • Copyright© 2012, Oracle. All rights reserved.

    複合索引を利用できる条件

    75

    • 複合索引の対応条件とパフォーマンス

    SELECT * FROM 製品表 WHERE 親コード=? AND 分類 =? AND 種別 =?;

    ○:WHERE句に条件あり ×:WHERE句に条件なし

    ・・・◎

    ・・・○

    ・・・△

    ・・・×

    複合索引の使用がパフォーマンス最適

    複合索引を使用可能 単一列索引より複合索引のほうが早いケースが多い (列数や各列のサイズなどによって変わる)

    9i以降複合索引を使用可能 複合索引より単一列索引のほうが早いケースが多い (パフォーマンスが最適かどうかはデータ構造などによる)

    複合索引を使用不可

    親コード 分類 種別

    ○ ○ ○

    ○ ○ ×

    ○ × ○

    ○ × ×

    × ○ ○

    × ○ ×

    × × ○

    × × ×

    WHRER句の条件にどの列を使うかに よって、索引を使用できるかどうか、 および、パフォーマンスが変わる

  • Copyright© 2012, Oracle. All rights reserved.

    キー圧縮型索引

    • キー圧縮を使用して、Bツリー索引または索引構成表の主キー列値の一部を圧縮 • キー列の接頭辞が同じ値で繰り返し格納されることを回避し索引に使用される領域が大幅に減少

    • 領域が大幅に節約され、各索引ブロックに格納できるキー数が増え、パフォーマンスが向上

    • 利用場面 • 一意の複数列索引がある場合

    • ROWIDを追加してキーを一意にしている非一意索引がある場合

    • キー圧縮の使用 • COMPRESS句を使用

    • 接頭辞の長さをキー列の数で指定

    CREATE INDEX orders_mod_stat_ix ON orders ( order_mode, order_status)

    TABLESPACE users COMPRESS 1;

    • ディスク I/O とメモリ消費を削減効果例) • ディスクスペースの節約:

    • 索引領域の75%を節約できた実績

    • DB全体で30%を削減

    • パフォーマンス:

    • 高いCPU利用率を I/O 削減により埋め合わせでき、10-20%のスループット向上を実現

    76

  • Copyright© 2012, Oracle. All rights reserved.

    キー圧縮索引の構造

    77

    Department1 Job1

    Department1 Job1

    Department1 Job1

    Department1 Job2

    Department1 Job2

    Department1 Job2

    Department2 Job1

    Department2 Job1

    Department2 Job1

    D1J1

    D1J1

    D1J1

    D1J2

    D1J2

    D1J2

    D2J1

    D2J1

    D2J1

    Prefix Suffix Prefix

    Suffix

  • Copyright© 2012, Oracle. All rights reserved.

    ファンクション索引

    • 関数(ファンクション)や式(計算等)を含んだ索引

    • 式の処理結果に対して索引を作成したもの

    • WHERE句にファンクションや式を含む文を効率化

    • Oracle8iから使用可能

    • コストベース・オプティマイザ(CBO)のみで利用可能

    78

    例:データベースの中の文字データが大文字か小文字か分からない場合

    SELECT * FROM employees

    WHERE UPPER(first_name) = 'RICHARD' ;

    CREATE INDEX uppercase_idx

    ON employees (UPPER(first_name));

  • Copyright© 2012, Oracle. All rights reserved.

    索引構成表とは?

    79

    • データ全体をBツリー索引に格納している索引

    • 索引のキー列だけでなく、その他の列(非キー列)もリーフブロックに格納 している索引

    • 索引にアクセスするだけでデータが取得できるため、より高速な検索が可能

    ① 索引のリーフ・ ブロックから ROWIDを読む

    ②ROWIDをもとに 表を検索

    100

    ①索引キー列の 検索のみで データまで到達

    エントリ・ヘッダ キー列 非キー列

    Suzuki 東京 20000 100 ROWID

    エントリ・ヘッダ キー列

    <通常の索引を使用した検索> <索引構成表を使用した検索>

    2段階の処理が必要で余分なI/Oが発生 検索時のI/Oを減少させるので高速

  • Copyright© 2012, Oracle. All rights reserved.

    索引構成表作成例

    80

    CREATE TABLE countries

    ( emp_id NUMBER(2) PRIMARY KEY,

    name VARCHAR2(40),

    ・・・・

    address VARCHAR2(25),

    ・・・・ )

    ORGANIZATION INDEX TABLESPACE indx

    PCTTHRESHOLD 20

    OVERFLOW TABLESPACE data;

    100 Suzuki 東京 20000

    行の残りの部分

    PCTTHRESHOLD内の行

    東京都渋谷区・・・

    オーバーフロー領域

    • 索引構成表の作成例

    • CREATE TABLEで「ORGANIZATION INDEX」を指定

    • しきい値(PCTTHRESHOLD)を設定し、一部のデータを別の領域に格納 することもできる

  • Copyright© 2012, Oracle. All rights reserved.

    様々なタイプの索引 表の特性、検索条件に合わせて最適な索引を選択

    • ビットマップ索引 • 列値と各レコードがその値に該当するか否かをビットで表した索引

    • カーディナリティの低い列で、ビット演算による高速な検索を行うことが可能

    • 複合索引 • 索引列のデータをビット単位で反転させ、反転させたデータをソートして

    索引に格納する索引

    • 挿入値を索引のリーフ・キー全体に分散させ、特定の索引ブロックにアクセス が集中することを防ぐことが可能

    • 逆キー索引 • 複数の列を指定した索引

    • 索引を使って、複数の検索条件にあう行を絞り込みが可能

    • 索引構成表 • 索引のキー列だけでなく、その他の列(非キー列)もリーフブロックに格納して

    いる索引

    • 索引にアクセスするだけでデータが取得できるため、より高速な検索が可能

    81

  • Copyright© 2012, Oracle. All rights reserved.

    まとめ

    • Bツリー索引の構造

    • オプティマイザによる索引走査/全表走査の判断 • ヒストグラムによる索引利用の効率化

    • 索引チューニングのポイント • 索引を使用する事で速くなる処理か?

    • 索引を利用できるSQL文か?

    • オプティマイザが索引利用を選択しているか?

    • 索引のメンテナンスをしているか?

    • さまざまな索引の種類

    82

  • Copyright© 2012, Oracle. All rights reserved. 83

    Appendix

  • Copyright© 2012, Oracle. All rights reserved.

    パーティション表とパーティション索引

    • パーティション表にも索引を作成できる • 索引で少数の行を特定することももちろん可能

    • だからオンライン・トランザクション処理にも使用できる

    • 索引もパーティション化できる • パーティション・キーの概念をもう一度考える

    • パーティション索引の種類

    • ローカル索引 ローカル同一キー索引

    ローカル非同一キー索引

    • グローバル索引 グローバル同一キー索引

    84

  • Copyright© 2012, Oracle. All rights reserved.

    ローカル索引とグローバル索引

    85

    各パーティションと同じキーで索引 パーティション化

    各パーティションとは 別のキーで索引を パーティション化

    ローカル索引 グローバル索引 パーティション表

    P1

    P2

    P3

    P4

    P5

    P1

    P2

    P3

    P4

    P5

    P6

    Partition1

    Partition2

    Partition3

    Partition4

    Partition5

    Partition6

  • Copyright© 2012, Oracle. All rights reserved.

    ローカル同一キー索引

    • 索引のキー列が表パーティションのキーと同一である索引

    86

    索引 (orderkey)

    Order表

    orderkey 1~999

    orderkey 1000~1999

    orderkey 2000~2999

    orderkey 3000~3999

    orderkey 800の

    データを見たい

    パーティションプルーニング 索引にアクセス

    orderkey 1000~1999

    orderkey 2000~2999

    orderkey 3000~3999

    orderkey 1~999

  • Copyright© 2012, Oracle. All rights reserved.

    ローカル非同一キー索引(1)

    • 索引のキー列が、表パーティションのキー列と同一でない索引

    87

    Order表 orderkey 1~999

    orderkey 1000~1999

    orderkey 3000~3999

    orderkey 2000~2999

    索引 (cust_id)

    cust_id 1 cust_id 21

    ・・・

    cust_id 7 cust_id 12

    ・・・

    cust_id 21 cust_id 97

    ・・・

    cust_id 2 cust_id 81

    ・・・

    索引にアクセス

    Orderkey2000~2999の間の

    顧客ID21のデータを見たい パーティションプルーニング

    パーティションプルーニングが 使用される例

  • Copyright© 2012, Oracle. All rights reserved.

    ローカル非同一キー索引(2)

    • 索引のキー列が、表パーティションのキー列と同一でない索引 • 検索条件によっては、パーティションプルーニングが使用されない

    • グローバル索引の方がパフォーマンスが高い場合もある

    88

    索引 (cust_id)

    Order表

    cust_id 7 cust_id 12

    ・・・

    cust_id 21 cust_id 97

    ・・・

    cust_id 2 cust_id 81

    ・・・

    ①索引にアクセス ②索引全体を検索

    cust_id 1

    cust_id 21

    ・・・

    cust_id 21 cust_id 97

    ・・・

    cust_id 1

    cust_id 21

    ・・・

    orderkey 1~999

    orderkey 1000~1999

    orderkey 3000~3999

    orderkey 2000~2999

    顧客ID21のデータを見たい

    パーティションプルーニングが 使用されない例

  • Copyright© 2012, Oracle. All rights reserved.

    ローカル索引の特徴

    • パーティション表のメンテナンスに合わせて索引も自動的にメンテナンスされるので、管理負荷が軽減する

    • ある表パーティションが使用できなくなっても、対応する検索パーティション以外は影響を受けない

    • ある表パーティションのメンテナンス操作にあわせて、 メンテナンスが必要になる索引パーティションが限定されるため、メンテナンス時間が短縮できる

    89

  • Copyright© 2012, Oracle. All rights reserved.

    グローバル索引

    • グローバル同一キー索引 • 表パーティションとは別のキーでパーティション化する索引

    • 例:索引をCUST_IDで、表をORDER_DATEでパーティション化

    90

    ※ グローバル非同一キー索引を作成することはできません。(エラーが返されます。)

    索引 (cust_id)

    Order表 (Order_date)

    cust_id

    1000 ~ 1999

    cust_id

    2000以上

    cust_id

    1 ~ 999

    顧客ID2100の

    データを見たい

    パーティションプルーニング

    Q1 Q2 Q3 Q4

  • Copyright© 2012, Oracle. All rights reserved.

    グローバル索引

    91

    レンジパーティション化されたグローバル索引

    ハッシュパーティション化されたグローバル索引

    CREATE INDEX month_ix ON ORDER(cust_id)

    GLOBAL PARTITION BY RANGE(cust_id)

    (PARTITION pm1_ix VALUES LESS THAN (1000),

    PARTITION pm2_ix VALUES LESS THAN (2000),

    PARTITION pm3_ix VALUES LESS THAN (MAXVALUE));

    CREATE INDEX month_ix ON ORDER(cust_id)

    GLOBAL PARTITION BY HASH(cust_id)

    (PARTITION p1 TABLESPACE USERS1,

    PARTITION p2 TABLESPACE USERS2,

    PARTITION p3 TABLESPACE USERS3,

    PARTITION p4 TABLESPACE USERS4);

    レンジパーティションの場合、最後のパーティションにMAXVALUEキーワードを指定する

    VALUES LESS THANキーワードによって、パーティションに格納されるデータを限定

    レンジパーティション化

    ハッシュパーティション化

    表領域を指定

  • Copyright© 2012, Oracle. All rights reserved.

    グローバル索引の特徴

    • パーティション化された表に関係なく、自由に索引を パーティション化することが可能

    • パーティションメンテナンスの影響を受ける • TRUNCATE PARTITION等を行うと索引が壊れ、該当パーティションは無効(UNUSABLE)になってしまう ⇒ 関連アプリケーション(プロシージャなど)にも影響

    • 一部の表パーティションにデータを投入しても索引全体を再作成するため時間がかかる

    92

    UPDATE GROBAL INDEXES句をつけた場合は

    自動更新される索引の再構築も不要

    ALTER TABLE T1 DROP PARTITION P1 UPDATE GLOBAL INDEXES;

  • Copyright© 2012, Oracle. All rights reserved. 93