web-dev-qa-db-ja.com

結合テーブルに最適なSQLインデックス

パフォーマンスの向上を念頭に置いて、結合テーブルでどのインデックスが役立つか、そしてどのインデックスが役立つのか疑問に思いました(特に、Rails 3 has_and_belongs_to_manyコンテキストで使用されます)。

モデルとテーブルの設定

私のモデルはFooBarであり、Rails規則に従って、_bars_foos_という結合テーブルがあります。主キーやタイムスタンプは作成されていません。このテーブルの古いフィールド_bar_id:integer_および_foo_id:integer_。次のインデックスのどれが最適で、重複がないかを知りたいです。

  1. 複合インデックス:_add_index :bars_foos, [:bar_id, :foo_id]_
    • 2つのインデックス
    • A. _add_index :bars_foos, :bar_id_
    • B. _add_index :bars_foos, :foo_id_
  2. 1と2-Bの両方の組み合わせ

基本的に、最初から役立つと仮定すると、複合インデックスで十分かどうかはわかりません。複合インデックスは最初の項目の単一のインデックスとして使用できると思います。そのため、私は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で使用したい場合があるため、すべての回答を歓迎します。

38
Aaron

答え

よく繰り返される答えは、常にそうなる傾向がありますが、「状況によって異なります」です。より具体的には、それはあなたのデータが何であるか、そしてそれがどのように使われるかによります。

tl; dr説明

私の特定のケース(および将来のすべてのベースをカバーする)の短いtl; drの答えは、選択肢#2であり、これは私が疑ったものです。ただし、データの使用法によっては、複合インデックスの作成に使用される余分な時間とスペースによって、将来のクエリルックアップが減少する可能性があるため、選択肢3は問題なく機能します。

完全な説明

この理由は、データベースは、プログラマーの入力に関係なく、スマートになり、可能な限り高速に処理しようとするためです。インデックスを追加するときに考慮すべき最も基本的な項目は、このオブジェクトがこのキーによって検索されるかどうかです。はいの場合、インデックスはそれをスピードアップするのに役立つ可能性があります。ただし、このインデックスが使用されるかどうかは、すべて選択性とフィールドのカーディナリティに依存します。

通常、外部キーは別のARクラスのIDであるため、カーディナリティは通常高くなります。しかし、繰り返しますが、これはデータによって異なります。私の例では、Foosが多く、Barsが少ない場合、結合テーブルのエントリの多くは同様のbar_idsを持ちます。カーディナリティが低いbar_idsの場合、bar_idのインデックスは使用されない可能性があり、データベースに新しいbars_foosエントリが作成されます。同じことが、多くのBarsと少数のFoos、および両方の少数にも当てはまります。

一般的な教訓は、テーブルのインデックスを検討するときに、エントリがこのフィールドによって検索されるかどうか、およびこのフィールドのカーディナリティが高いかどうかを判断することです。つまり、このフィールドには多くの異なる値がありますか?ほとんどの結合テーブルの場合、「依存する」ため、データが何を表しているのか、および関係自体についてより慎重に考える必要があります。私の場合、両方の多くのFoosとBarsがあり、関連するFoosによってbarsを検索します。その逆も同様です。

私がオフィスで得たもう1つの良い答えは、「なぜインデックスについて心配しているのですか?アプリを作成してください!」でした。

脚注

*同様の質問で STIのインデックスについて インデックスのコストが非常に低いことが指摘されたので、疑問がある場合は追加してください。

32
Aaron

データをクエリする方法によって異なります。

これらすべてを検索したいとします...

  • 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に精通していません。この回答は純粋にデータベースの観点からのものです。)

5