web-dev-qa-db-ja.com

ActiveRecordの複数の列のインデックス

ActiveRecordでは、複数の列のインデックスを宣言する2つの方法があります。

add_index:classifications、[:species、:family、:trivial_names]
add_index:classifications、:species 
 add_index:classifications、:family 
 add_index:classifications、:trivial_names

最初のアプローチと2番目のアプローチに違いはありますか?もしそうなら、私はいつ最初と2番目を使うべきですか?

45
collimarco

複合インデックスを一連の独立したインデックスと比較しています。彼らはただ違う。

このように考えてください。複合インデックスを使用すると、ネストされたフィールドセット内の最初のフィールドをすばやく検索した後、2番目のフィールドをすばやく検索できます最初のフィールドで既に選択されているレコードのみ内、続いて3番目のフィールドの迅速な検索-これも、前の2つのインデックスで選択されたレコード内でのみ行われます。

例を見てみましょう。データベースエンジンは、1,000,000レコード内の一意の値を見つけるために20ステップ以内で実行します(メモリが機能する場合)ifインデックスを使用しています。これは、複合インデックスを使用している場合でも、独立したインデックスを使用している場合でも当てはまりますが、最初のフィールド(例では「種」)にのみ当てはまりますが、ファミリー、種、次に一般名が必要だと思います)。

ここで、この最初のフィールド値に一致するレコードが100,000個あるとします。インデックスが1つしかない場合、これらのレコード内のルックアップには100,000ステップが必要です。最初のインデックスによって取得されたレコードごとに1つです。これは、2番目のインデックスが使用されないため(ほとんどのデータベースでは、これは少し単純化されています)、ブルートフォースマッチを使用する必要があります。

複合インデックスの場合、2番目のフィールド検索にはインデックスwithin最初の値のセットがあるため、検索ははるかに高速になります。この場合、フィールド1の100,000回の一致(100,000の対数基数2)内でフィールド2の最初の一致値に到達するために必要なステップは17ステップ以下です。

つまり、3つのネストされたフィールドの複合インデックスを使用して1,000,000レコードのデータベースから一意のレコードを見つけるために必要なステップで、最初のフィールドは100,000を取得し、2番目のステップは10,000 = 20 + 17 + 14 = 51ステップを取得します。

独立したインデックスのみを使用した同じ条件下で必要なステップ= 20 + 100,000 + 10,000 = 110,020ステップ。

大きな違いですね

さて、do n't複合インデックスをいたるところに置いてください。まず、挿入と更新に費用がかかります。次に、ネストされたデータを本当に検索している場合にのみ、それらが有効になります(別の例として、特定の日付範囲でクライアントのログイン用にデータをプルするときに使用します)。また、比較的小さなデータセットで作業している場合は、その価値はありません。

最後に、データベースのドキュメントを確認してください。最近、データベースはインデックスを展開する機能が非常に洗練されており、上記のDatabase 101シナリオは一部の人には当てはまらない可能性があります(ただし、私は常に、何が得られているかを知っているかのように開発しています)。

89

2つのアプローチは異なります。 1つ目は3つの属性に単一のインデックスを作成し、2つ目は3つの単一属性インデックスを作成します。ストレージ要件は異なりますが、ディストリビューションがないと、どちらが大きくなるかを判断することはできません。

3つの列[A、B、C]のインデックス付けは、A、A + B、およびA + B + Cの値にアクセスする必要がある場合に適切に機能します。クエリ(または条件の検索など)がAを参照していない場合は、何の役にも立ちません。

A、B、およびCに個別にインデックスが付けられている場合、一部のDBMSクエリオプティマイザは、2つ以上のインデックスを組み合わせて(オプティマイザの効率の見積もりに従って)、単一の複数列のインデックスに同様の結果を与えることを検討します。

あなたがいくつかのeコマースシステムを持っているとしましょう。 Purchase_date、customer_id、場合によってはその両方で注文をクエリしたいとします。まず、属性ごとに1つずつ、合計2つのインデックスを作成します。

一方、purchase_date and customer_idを常に指定する場合は、両方の列の単一のインデックスがおそらく最も効率的です。注文は重要です。顧客のすべての日付の注文もクエリする場合は、customer_idをインデックスの最初の列にします。

10
Mike Woodhouse

ドキュメントから:

複数の列にインデックスを作成する場合、最初の列がインデックスの名前として使用されます。たとえば、2つの列[:first、:last]にインデックスを指定すると、DBMSは両方の列のインデックスと最初の列:firstのインデックスを作成します。この名前で単一のインデックスを作成する必要がないため、このインデックスに名だけを使用することは理にかなっています。

複合インデックスを作成する場合は最初の方法を使用し、単一の属性にインデックスを作成する場合は2番目の方法を使用します。

いくつかの良い点があります ここでは複合インデックスを使用する場合 ですが、要点は、複数の属性のwhereを使用する場合に良いということです。それらは他のインデックスと一緒に使用する必要があることに注意してください(常に外部キーにインデックスを付けます)-代わりとしてではありません。

1
Codebeef