S-JIS[2008-04-15/2010-07-29] 変更履歴

インデックス(索引)

Oracleのインデックス(索引)の超簡易メモ。


インデックスの作成

create index インデックス名 on テーブル名
(項目名, 項目名…);

デフォルトではB-Tree(二分探索の改良版らしい)の索引が作られる。


降順の索引を作成すると、自動的にファンクション索引となる。[2010-07-29]
(ファンクション索引を作成する場合にはquery rewrite権限が必要だが、降順索引の場合は不要)

SQL> create index IX_EMP_SAL_D on EMP (SAL desc);

ビットマップインデックスの作成

ビットマップインデックスは、カーディナリー(値の種類数)が低い場合に有効なインデックス。

例えば性別は男・女の2種類しか値を持たないので、カーディナリーが低い。
フラグも0と1しか持たないのでカーディナリーが低い。
ステータスで限定的な値をとるのも低い方だろう。

ビットマップインデックスを張っておけば、その項目を条件に使った全件検索に効果的だと思われる。

select * from テーブル where フラグ='0';

(そうは言っても、検索結果がテーブル全体の大多数を占めるようならあまり意味は無いが…)

ビットマップインデックスの構造上、更新には不利らしいが、以下のような更新ならそれほどでもないんじゃないかと期待。

update テーブル set フラグ='1' where フラグ='0';

(未処理のレコードを全て処理済に変える、という感じ)

あと、範囲指定(「ステータス between 1 and 3」とか)も不向きらしい。


ビットマップインデックスを作るには、通常の索引作成のSQLに対し、以下のように「bitmap」を加えるだけ。

create bitmap index インデックス名 on テーブル名
(項目名, 項目名…);

ただし、ビットマップインデックスはEnterprise Editionでないと作れないらしい。

ORA-00439: 機能は使用可能ではありせん: Bit-mapped indexes

SQL> select * from v$option where parameter ='Bit-mapped indexes';
PARAMETER           VALUE
------------------- ------
Bit-mapped indexes  FALSE

ファンクション索引の作成

create index文において、項目名を指定する箇所に演算(式)を書くと、ファンクション索引となる。[2010-07-29]

SQL> create index IX_EMP_DEPT on EMP (substr(DEPTNO,1,1));
create index IX_EMP_DEPT on EMP (substr(DEPTNO,1,1))
                                                 *
行1でエラーが発生しました。:
ORA-01031: 権限が不足しています。

ファンクション索引を作成するには、query rewriteの権限が必要なんだそうだ。

SYSユーザー(as sysdba)にて
SQL> grant query rewrite to scott;
SQL> create index IX_EMP_DEPT on EMP (substr(DEPTNO,1,1));
索引が作成されました。

ファンクション索引の定義(式)の確認方法

なお、ファンクション索引は通常のインデックス作成より時間がかかるんだそうだ。(複雑な計算式になればなるほど、時間がかかる)

参考: おら! オラ! Oracleの新インデックスの検証 その6


SQLのWHERE条件にファンクション索引で指定した計算式を使うと、定義したファンクション索引が使用される。

SQL> set autot trace exp

SQL> select ENAME,DEPTNO from EMP where substr(DEPTNO, 1, 1) = '2';

実行計画
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE (Cost=1 Card=1 Bytes=9)
   1    0   TABLE ACCESS (BY INDEX ROWID) OF 'EMP' (Cost=1 Card=1 Bytes=9)
   2    1     INDEX (RANGE SCAN) OF 'IX_EMP_DEPT' (NON-UNIQUE) (Cost=1 Card=1)

インデックス名の変更

インデックス名の変更方法。[2010-02-19]

alter index インデックス名 rename to 新インデックス名;

インデックスがプライマリキーの場合、制約の方の名前はこのSQL文では変わらない。別途制約名も変更する必要がある。


インデックスの定義の確認

テーブルに付けられているインデックスを知るにはuser_indexesビューを使用する。

テーブルに付いているインデックスの項目を知るには、以下のようなSQLを実行すればよい。[2007-12-13]
(user_系で見つからない場合は、all_系で挑戦)

col table_name  format a16 trunc
col index_name  format a24
col uniqueness  format a4  trunc
col column_name format a24
select i.table_name, i.index_name, i.uniqueness, c.column_name
from user_indexes i, user_ind_columns c
where i.index_name = c.index_name
  and i.table_name = 'テーブル名'
order by index_name,table_name,column_position
;
ビュー名 項目 内容 更新日
user_indexes INDEX_TYPE インデックスの種類。
NORMAL 通常の(B-Tree)インデックス
FUNCTION-BASED NORMAL ファンクション索引
BITMAP ビットマップ索引
2010-07-29
UNIQUENESS ユニーク(一意)かどうか。 2010-07-29
LAST_ANALYZED 最後に分析(統計情報が取得)された日時。 2010-07-29
PARTITIONED パーティション化されているかどうか。 2010-07-29
user_ind_columns DESCEND 昇順・降順のどちらか。 2010-07-29
user_ind_expressions COLUMN_EXPRESSION ファンクション索引の式。 2010-07-29

DBMS_METADATA.GET_DDL
整合性制約の項目を知る方法


ファンクション索引の定義の確認

ファンクション索引でどのような式になっているかを確認するにはuser_ind_expressionsビューを使用する。[2010-07-29]
ファンクション索引でない項目については、このビューにはレコードは存在しない。

select INDEX_NAME, COLUMN_EXPRESSION, COLUMN_POSITION
from user_ind_expressions
where TABLE_NAME = 'テーブル名'
order by INDEX_NAME,COLUMN_POSITION
;
パターン 式の例 説明
降順の場合
"SAL"
降順を指定した項目の場合はファンクション索引となるが、項目名だけが登録されている。
式(演算)の場合
SUBSTR(TO_CHAR("DEPTNO"),1,1)
作成時に「substr(DEPTNO,1,1)」と指定した。
DEPTNOはnumber型だからto_char()が補足されている。

インデックスの状態の確認

インデックスの状態はindex_statsビューで確認できる。[2010-02-04]
ただし、参照する前に分析を実行しておく必要がある。

SQL> analyze index インデックス名 validate structure;

索引が分析されました。

SQL> select NAME,USED_SPACE from index_stats;

NAME                           USED_SPACE
------------------------------ ----------
PK_EMP                                335

参考: @ITのBツリーインデックスに最高のパフォーマンスを(1/4)


Oracle9i以降では、インデックスが使用されたかどうかをモニタリングすることが出来る。[2010-02-04]

alter index monitoring usageでモニタリングを開始する。終了するにはnomonitoring。
モニタリングしている間に指定したインデックスが使用されると、v$object_usageビューのUSEDが「YES」になる。

SQL> alter index PK_EMP monitoring usage; --インデックスのモニタリングを開始

索引が変更されました。

SQL> select * from v$object_usage;

INDEX_NAME                     TABLE_NAME                     MON USE START_MONITORING    END_MONITORING
------------------------------ ------------------------------ --- --- ------------------- -------------------
PK_EMP                         EMP                            YES NO  02/04/2010 20:58:37

SQL> select count(*) from emp; --テーブルフルスキャンなので、インデックスは使われない

  COUNT(*)
----------
        24

SQL> select * from v$object_usage;

INDEX_NAME                     TABLE_NAME                     MON USE START_MONITORING    END_MONITORING
------------------------------ ------------------------------ --- --- ------------------- -------------------
PK_EMP                         EMP                            YES NO  02/04/2010 20:58:37

SQL> select * from emp where empno=123; --インデックスを使用

レコードが選択されませんでした。

SQL> select * from v$object_usage;

INDEX_NAME                     TABLE_NAME                     MON USE START_MONITORING    END_MONITORING
------------------------------ ------------------------------ --- --- ------------------- -------------------
PK_EMP                         EMP                            YES YES 02/04/2010 20:58:37

SQL> alter index PK_EMP nomonitoring usage; --インデックスのモニタリングを終了

索引が変更されました。

SQL> select * from v$object_usage;

INDEX_NAME                     TABLE_NAME                     MON USE START_MONITORING    END_MONITORING
------------------------------ ------------------------------ --- --- ------------------- -------------------
PK_EMP                         EMP                            NO  YES 02/04/2010 20:58:37 02/04/2010 21:03:03

インデックスの無効化・有効化

インデックスを一時的に無効化することが出来る。[2009-12-24]
大量データをINSERTする前に無効化し、終わった後で有効化すると効率が良いらしい。
(無効化・有効化と言っても、意味合いはインデックスのDROP・CREATEと同様らしい? 無効化するとuser_indexes等で照会できなくなる)

alter table テーブル disable constraint インデックス名;
alter table テーブル disable primary key;
alter table テーブル disable unique(項目名, …);	←ユニークキーが存在する場合
alter table テーブル enable 〜;	←有効化

…この構文は、「索引の無効化・有効化」と言うより、「制約の無効化・有効化」だなぁ。


インデックスの再作成・結合

テーブルにデータを追加したり削除したりしていると、インデックスが断片化してくるらしい。[2009-12-24]
再作成(再構築)とか結合とかするといいらしい。

alter index インデックス名 rebuild; 	←再作成
alter index インデックス名 coalesce;	←結合

インデックスを再構築すると、テーブルロックがかかるらしい。[2010-02-19]
しかし「rebuild online」という指定(Oracle8i以降)にすれば、テーブルロックでなく行ロックになるらしい。


「結合:COALESCE」は、散在する空き領域の結合(断片化の解消)をすることらしい。[2010-02-19]

なお、「結合」はEnterprise Editionでないと使えないらしい。[2009-12-24]

SQL> alter index PK_EMP coalesce;
alter index PK_EMP coalesce
*
行1でエラーが発生しました。:
ORA-00439: 機能は使用可能ではありせん: Coalesce Index

SQL> select * from v$option where parameter ='Coalesce Index';
PARAMETER       VALUE
--------------- ------
Coalesce Index  FALSE

インデックスの不可視化

Oracle11gから、不可視索引というものが導入されたらしい。[2009-12-24]
インデックスとしては存在しているけれども、オプティマイザーが使用しない状態になるんだそうだ。
インデックスの有無による動作確認に使用する想定らしい。

alter index インデックス名 invisible;	←不可視化
alter index インデックス名 visible;  	←可視化
select index_name, visibility from user_indexes
where index_name='インデックス名';

SQLメモへ戻る / 情報照会へ戻る / Oracle目次へ戻る / 新機能へ戻る / 技術メモへ戻る
メールの送信先:ひしだま