パフォーマンスの向上を念頭に置いて、結合テーブルでどのインデックスが役立つか、そしてどのインデックスが役立つのか疑問に思いました(特に、Rails 3 has_and_belongs_to_manyコンテキストで使用されます)。
私のモデルはFoo
とBar
であり、Rails規則に従って、_bars_foos
_という結合テーブルがあります。主キーやタイムスタンプは作成されていません。このテーブルの古いフィールド_bar_id:integer
_および_foo_id:integer
_。次のインデックスのどれが最適で、重複がないかを知りたいです。
add_index :bars_foos, [:bar_id, :foo_id]
_add_index :bars_foos, :bar_id
_add_index :bars_foos, :foo_id
_基本的に、最初から役立つと仮定すると、複合インデックスで十分かどうかはわかりません。複合インデックスは最初の項目の単一のインデックスとして使用できると思います。そのため、私はpretty 3行すべてを使用すると、不必要な重複が確実に発生することを確信しています。
最も一般的な使用法は、モデルFoo
のインスタンスが与えられ、_foo.bars
_のRoR構文を使用して関連するbars
を要求し、_bar.foos
_でその逆を要求します。モデルBar
のインスタンスの場合。
これらは、それぞれタイプ_SELECT * FROM bars_foos WHERE foo_id = ?
_および_SELECT * FROM bars_foos WHERE bar_id = ?
_のクエリを生成し、それらの結果のIDをSELECT * FROM bars WHERE ID in (?)
およびSELECT * FROM foos WHERE ID in (?)
に使用します。
私が間違っている場合はコメントで訂正してください。ただし、Railsアプリケーションのコンテキストでは、両方のIDを指定するクエリを実行しようとすることはないと思います。 _SELECT * FROM bars_foos where bar_id = ? AND foo_id = ?
_のように。
データベース固有の最適化手法がある場合は、PostgreSQLを使用する可能性があります。ただし、このコードを使用している他の人は、Rails構成に応じて、MySQLまたはSQLiteで使用したい場合があるため、すべての回答を歓迎します。
よく繰り返される答えは、常にそうなる傾向がありますが、「状況によって異なります」です。より具体的には、それはあなたのデータが何であるか、そしてそれがどのように使われるかによります。
私の特定のケース(および将来のすべてのベースをカバーする)の短いtl; drの答えは、選択肢#2であり、これは私が疑ったものです。ただし、データの使用法によっては、複合インデックスの作成に使用される余分な時間とスペースによって、将来のクエリルックアップが減少する可能性があるため、選択肢3は問題なく機能します。
この理由は、データベースは、プログラマーの入力に関係なく、スマートになり、可能な限り高速に処理しようとするためです。インデックスを追加するときに考慮すべき最も基本的な項目は、このオブジェクトがこのキーによって検索されるかどうかです。はいの場合、インデックスはそれをスピードアップするのに役立つ可能性があります。ただし、このインデックスが使用されるかどうかは、すべて選択性とフィールドのカーディナリティに依存します。
通常、外部キーは別のARクラスのIDであるため、カーディナリティは通常高くなります。しかし、繰り返しますが、これはデータによって異なります。私の例では、Foo
sが多く、Bar
sが少ない場合、結合テーブルのエントリの多くは同様のbar_id
sを持ちます。カーディナリティが低いbar_id
sの場合、bar_id
のインデックスは使用されない可能性があり、データベースに新しいbars_foos
エントリが作成されます。同じことが、多くのBar
sと少数のFoo
s、および両方の少数にも当てはまります。
一般的な教訓は、テーブルのインデックスを検討するときに、エントリがこのフィールドによって検索されるかどうか、およびこのフィールドのカーディナリティが高いかどうかを判断することです。つまり、このフィールドには多くの異なる値がありますか?ほとんどの結合テーブルの場合、「依存する」ため、データが何を表しているのか、および関係自体についてより慎重に考える必要があります。私の場合、両方の多くのFoo
sとBar
sがあり、関連するFoo
sによってbar
sを検索します。その逆も同様です。
私がオフィスで得たもう1つの良い答えは、「なぜインデックスについて心配しているのですか?アプリを作成してください!」でした。
*同様の質問で STIのインデックスについて インデックスのコストが非常に低いことが指摘されたので、疑問がある場合は追加してください。
データをクエリする方法によって異なります。
これらすべてを検索したいとします...
WHERE bar_id = ?
WHERE foo_id = ?
WHERE bar_id = ? AND foo_id = ?
...次に、{bar_id, foo_id}
のインデックスと{foo_id}
のインデックスを使用する必要があります。
couldも{bar_id}
に3番目のインデックスを作成できますが、追加のインデックスを維持することの価格は、おそらくより良い クラスタリング の利点を上回ります。小さいインデックス。
また、どのように cover インデックスを使用したクエリを計画していますか?次のようないくつかの選択肢...
{foo_id, bar_id}
および{bar_id}
{foo_id, bar_id}
および{bar_id, foo_id}
...特定の種類のクエリをより適切にカバーする可能性があります。
カバーすることはバランスをとる行為です-カバーする目的のためだけにフィールドをインデックスに追加することが正当化される場合もあれば、そうでない場合もあります。現実的な量のデータを測定するまでわかりません。
(免責事項:私はRubyに精通していません。この回答は純粋にデータベースの観点からのものです。)