3

初めてユーザー定義関数で関数ベースのインデックスを使用していますが、インデックスを使用できないときにパフォーマンスの問題に遭遇しました。

内部的には、関数ベースのインデックスは非表示のテーブル列 (関数が varchar2 を返すため、varchar2(4000) 型) を生成するように見え、それをインデックス化します。インデックスが使用されている場合は正常に機能しますが、関数をフィルターとして使用して完全なテーブルスキャンを実行する必要がある場合があり、その場合、パフォーマンスが 6 分の 1 に低下します。その場合、Oracle は使用しないようです非表示の列を削除しますが、行ごとに関数を再計算し、クエリを IO バウンドではなく CPU バウンドにします。

Oracle でその非表示の列をフィルタリングにも使用する方法はありますか? いくつかの書き換えオプションまたはそれらの線に沿った何かが欠けているのだろうか。

そうでない場合は、自分で列を定義し、トリガーを使用して最新の状態に保つ必要があります。透明性とメンテナンスの容易さのために、関数ベースのインデックスを使用することをお勧めします。

4

2 に答える 2

3

どのバージョンの Oracle を使用していますか? 11g の場合は、仮想列を使用してみてください。これは、値が式またはリテラルから導出される列です。これらはテーブルの一部として定義されているため、(関数ベースのインデックスとは異なり) テーブル DESC で可視性があります。仮想列に索引を作成できます。また、トリガーを必要とせずに自動的に維持されます。

したがって、関数ベースのインデックスと同じ式を使用して、テーブルに仮想列を追加できます。おそらく次のようになります。

create table t23
   (id number
    , col_a varchar2(10)
    , vcol_a as (upper(substr(col_a, 1, 1)))
  )
/

仮想列を挿入または更新できないことに注意してください。したがって、挿入ステートメントの射影を指定する必要があります。

insert into t23 (id, col_a) values (1, 'this is a test');

次に、仮想列に通常のインデックスを作成できます。

create index t23_vc_i on t23(vcol_a)
/

関数ベースのインデックスを削除することを忘れないでください!

于 2012-07-24T10:55:36.703 に答える
0

関数ベースのインデックスをテーブル スキャンで使用できる一般的な方法はありません。

私が質問で行った仮定、つまり「内部的に、関数ベースのインデックスは非表示のテーブル列を生成するようです...」は、単に間違っています。関数の結果はテーブルの列には保存され、索引。

したがって、スキャンを実行するときにインデックスにアクセスする方法がない限り (私が考えることができる唯一の方法は、キー列で始まる結合インデックスである場合です)、事前計算された関数の結果は使用できません。

11gの「仮想列」機能も役に立ちません。列は表に格納されず、ビューで関数を使用するのと同様にオンザフライで計算されるためです。

要約すると、テーブル スキャンを除外できず、関数呼び出しが高価な (遅い) 場合は、実際の列を「挿入または更新前」トリガーと組み合わせて使用​​します。関数ベースのインデックスは役に立ちません。

(注:この質問を未回答のままにしたくなかったため、この回答を追加しました。回答の功績は、コラムが決して実現しないことを指摘したthiloに属します)。

于 2012-07-25T13:53:01.113 に答える