15

「foo」と「bar」という 2 つのフィールドを持つデータベース テーブルがあるとします。どちらも一意ではありませんが、それぞれにインデックスが付けられています。ただし、一緒に索引付けされるのではなく、それぞれに別個の索引があります。

SELECT * FROM sometable WHERE foo='hello' AND bar='world'; ここで、foo が「hello」である膨大な数の行と、bar が「world」である少数の行の My tableなどのクエリを実行するとします。

したがって、データベース サーバーが内部で行う最も効率的な方法は、bar インデックスを使用して、bar が「world」であるすべてのフィールドを検索し、foo が「hello」である行のみを返すことです。ここでO(n)、n はバーが「世界」である行の数です。

ただし、fo インデックスを使用して結果を検索するという逆のプロセスが発生する可能性があると思います。ここで、m は fooがO(m)「hello」である行の数です。

では、オラクルはここで効率的に検索できるほど賢いのでしょうか? 他のデータベースはどうですか?または、クエリで適切な順序で検索するように指示できる方法はありますか? おそらく、句bar='world'の最初に置くことによって?WHERE

4

9 に答える 9

12

オラクルはほぼ確実に、最も選択的なインデックスを使用してクエリを実行します。これは、実行計画で確認できます。

さらに、Oracle は 2 つの方法で両方のインデックスの使用を組み合わせることができます。つまり、btree インデックスをビットマップに変換し、それらに対してビットマップ AND 操作を実行したり、2 つのインデックスによって返された行 ID に対してハッシュ結合を実行したりできます。

ここで重要な考慮事項の 1 つは、照会される値間の相関関係です。foo='hello' がテーブルの値の 80% を占め、bar='world' が 10% を占める場合、Oracle はクエリがテーブル行の 0.8*0.1= 8% を返すと推定します。ただし、これは正しくない可能性があります。クエリは、値の相関関係に応じて、実際には行の 10% または 0% を返す場合があります。現在、テーブル全体のこれらの行の分布によっては、インデックスを使用してそれらを見つけるのが効率的でない場合があります。必要な行を取得するために (たとえば) 70% またはテーブル ブロックにアクセスする必要がある場合があります (「クラスタリング ファクター」の場合は google)。その場合、推定が正しい場合、Oracle はフル テーブル スキャンを実行します。

11g では、複数列の統計を収集して、この状況に役立つと思います。9i および 10g では、動的サンプリングを使用して、取得する行数を正確に見積もることができます。

実行計画を取得するには、次のようにします。

explain plan for
SELECT *
FROM   sometable
WHERE  foo='hello' AND bar='world'
/
select * from table(dbms_xplan.display)
/

それを次のように対比してください。

explain plan for
SELECT /*+ dynamic_sampling(4) */
       *
FROM   sometable
WHERE  foo='hello' AND bar='world'
/
select * from table(dbms_xplan.display)
/
于 2008-09-29T15:26:03.207 に答える
4

エリ、

あなたが書いたコメントで:

残念ながら、それぞれに独自のインデックスを持つ多数の列を持つテーブルがあります。ユーザーはフィールドの任意の組み合わせに対してクエリを実行できるため、フィールドの組み合わせごとにインデックスを効率的に作成することはできません。しかし、インデックスが必要なフィールドが 2 つしかない場合は、2 つのインデックスを使用するという提案に完全に同意します。– イーライ・コートライト (9 月 29 日 15:51)

これは実際にはかなり重要な情報です。プログラマーは、質問をするときに自分の裏をかくことがあります。彼らは質問を重要なポイントに絞り込もうとしますが、非常に多くの場合、単純化しすぎて最良の回答を得ることを逃します。

このシナリオこそが、ビットマップ インデックスが発明された理由です。未知の列グループが where 句で使用される場合に対処するためです。

BMI はカーディナリティの低い列専用であり、あなたのケースには当てはまらない可能性があると誰かが言った場合に備えて。Low は、おそらくあなたが思っているほど小さくはありません。唯一の実際の問題は、テーブルへの DML の同時実行性です。これが機能するには、シングル スレッドまたはまれである必要があります。

于 2008-10-07T18:48:15.257 に答える
3

まず、あなたが話しているのは、適切で通常の標準的な b* ツリー インデックスについてだと仮定します。ビットマップ インデックスの答えは根本的に異なります。また、Oracle にはさまざまな種類のインデックスのオプションが多数あり、答えが変わる場合と変わらない場合があります。

少なくとも、オプティマイザーが特定の条件の選択性を判断できる場合は、より選択的なインデックス (つまり、バーのインデックス) を使用します。ただし、データが歪んでいる場合 (列バーに N 個の値がありますが、特定の値の選択性がデータの 1/N より大幅に多いか少ない場合)、それを伝えるために列にヒストグラムを表示する必要があります。値が多かれ少なかれ可能性があるオプティマイザー。また、バインド変数を使用している場合 (すべての優れた OLTP 開発者がすべきこと)、Oracle のバージョンによっては、バインド変数のピークに問題が発生する可能性があります。

潜在的に、Oracle は 2 つの b* ツリー インデックスをビットマップにその場で変換し、ビットマップを結合して、両方のインデックスを使用して取得する必要がある行を見つけることさえできます。しかし、これはかなり珍しいクエリ プランです。特に、1 つの列が非常に選択的であるのに 2 つの列しかない場合はそうです。

于 2008-09-29T15:29:19.673 に答える
3

はい、Oracle へのクエリで「ヒント」を与えることができます。これらのヒントは、データベースへのコメント ("/* HINT */") に偽装され、主にベンダー固有のものです。したがって、あるデータベースの 1 つのヒントは、他のデータベースでは機能しません。

ここでは、小さなテーブルの最初のヒントであるインデックス ヒントを使用します。ここを参照してください。

一方、この 2 つのフィールドを頻繁に検索する場合は、この 2 つのフィールドにインデックスを作成してみませんか? 正しい構文はありませんが、次のようなものになります

CREATE INDEX IX_BAR_AND_FOO on sometable(bar,foo);

このようにして、データの取得はかなり高速になります。連結が一意の場合は、超高速の一意のインデックスを作成するだけです。

于 2008-09-29T15:14:06.327 に答える
2

では、オラクルはここで効率的に検索できるほど賢いのでしょうか?

簡単な答えは「おそらく」です。各データベース ベンダーには、クエリ オプティマイザーの最適化に取り組んでいる非常に優秀な人がたくさんいます。統計を更新すれば、おそらくさらに多くのことができるでしょう。

于 2008-09-29T15:15:32.983 に答える
1

Oracle にクエリ プランを表示させることもできるので、どのインデックスが最初に使用されるかを正確に確認できます。

于 2008-09-29T15:16:23.870 に答える
1

最善の方法は、foo を bar のインデックスに追加するか、bar を foo のインデックスに追加すること (またはその両方) です。foo のインデックスにも bar のインデックスが含まれている場合、その追加のインデックス作成レベルは、そのインデックスの現在の使用における foo インデックスのユーティリティには影響しません。また、そのインデックスを維持するパフォーマンスにも目に見える影響はありませんが、データベースに追加の例のようにクエリを最適化する際に使用する情報。

于 2008-09-29T15:20:32.440 に答える
1

それよりも良いです。

インデックス シークは、完全なテーブル スキャンよりも常に高速です。そのため、舞台裏でOracle(およびSQLサーバー)は最初に両方のインデックスで行の範囲を見つけます。次に、どちらの範囲が短いかを調べ (内部結合であることを確認)、短い範囲を反復して、2 つのうち大きい方と一致するものを見つけます。

于 2008-09-29T15:24:42.137 に答える
0

使用するインデックスに関するヒントを提供できます。私は Oracle に詳しくありませんが、Mysql では USE|IGNORE|FORCE_INDEX を使用できます (詳細については、こちらを参照してください)。ただし、最高のパフォーマンスを得るには、複合インデックスを使用する必要があります。

于 2008-09-29T15:17:20.687 に答える