Railsのテーブルにどのインデックスを追加するか


131

Railsデータベースについて質問があります。

  • 「xxx_id」のようなすべての外部キーに「インデックス」を追加する必要がありますか?
  • 自動的に作成された「id」列に「index」を追加する必要がありますか?
  • 自動的に作成される「id」列に「index(unique)」を追加する必要がありますか?

  • 一度に2つの外部キーにインデックスを追加すると(add_index (:users, [:category, :state_id])、どうなりますか?これは、各キーにインデックスを追加するのとどう違うのですか?

    class CreateUsers < ActiveRecord::Migration
      def self.up
        create_table :users do |t|
          t.string :name
          t.integer :category_id 
          t.integer :state_id
          t.string :email
          t.boolean :activated
          t.timestamps
        end
      # Do I need this? Is it meaningless to add the index to the primary key?
      # If so, do I need :unique => true ?
      add_index :users, :id 
      # I don't think I need ":unique => true here", right?
      add_index :users, :category_id # Should I need this?
      add_index :users, :state_id # Should I need this?
      # Are the above the same as the following?
      add_index (:users, [:category, :state_id])
      end
    end
    

これまでのところ素晴らしい回答です。追加の質問。

  • xxx_idに「一意のインデックス」を追加する必要がありますよね?

回答:


175

「xxx_id」のようなすべての外部キーに「インデックス」を追加する必要がありますか?

この列での並べ替えの検索を高速化するため、より良い方法です。そして、外部キーはたくさん検索されます。

Railsのバージョン5以降、インデックスは自動的に作成されます。詳細については、こちらを参照してください

自動的に作成された「id」列に「index」を追加する必要がありますか?

いいえ、これはすでにレールによって行われています

自動的に作成される「id」列に「index(unique)」を追加する必要がありますか?

いいえ、上記と同じ

一度に2つの外部キーにインデックスを追加すると(add_index (:users, [:category_id, :state_id])、どうなりますか?これは、各キーにインデックスを追加するのとどう違うのですか?

次に、インデックスは2つの列の結合インデックスです。あなたがいずれかのすべてのエントリ場合を除き、それは、どんな意味がないcategory_id 1をstate_id(それがあるべきcategory_idではないcategoryと同時に)。

このようなインデックスは、次のリクエストを高速化します。

# rails 2
User.find(:all, :conditions => { :state_id => some_id, :category_id => some_other_id })

# rails 3
User.where(:state_id => some_id, :category_id => some_other_id)

どこ

add_index :users, :category_id
add_index :users, :state_id

これらのリクエストを高速化します:

# rails 2+3
User.find_by_category_id(some_id)
User.find_by_state_id(some_other_id)

# or
# rails 2
User.find(:all, :conditions => {:category_id => some_id})
User.find(:all, :conditions => {:state_id => some_other_id})

# rails 3
User.where(:category_id => some_id)
User.where(:state_id => some_other_id)

xxx_idに「一意のインデックス」を追加する必要がありますよね?

いいえ、これを行うと、1人のユーザーのみが1つのカテゴリーに属することができますが、カテゴリーの意味は、より多くのユーザーを1つのカテゴリーに入れることができるということです。あなたにUserモデルあなたはこのような何か持っているbelongs_to :categoryなど、あなたのカテゴリーのモデル何かでをhas_many :usershas_many関係がある場合、foreign_keyフィールドは一意であってはなりません!

これに関するより詳細な情報については、tadmanの素晴らしい答えを見てください


3
すばらしい答えです。追加の質問。xxx_idに「一意のインデックス」を追加する必要がありますよね?
TK。

質問、そのフィールドが明示的にほとんど検索されない場合、外部キーにインデックスを付けますか?
Noz

@Cyleこれには明確に答えることはできません。それは、マシン、データベースのサイズ、およびクエリの性質によって異なります。クエリがWebからのものである場合、バックグラウンドジョブのためであり、ディスク領域を節約する必要がある場合は常に設定する必要はありませんが、ディスク領域がとにかくインデックスを追加する問題ではありません。
jigfox 2013年

111

インデックス付けは、トリッキーで微妙なことですが、適用する一般的なルールによって、どれを使用するかを非常に簡単に決定できます。

最初に覚えておかなければならないのは、インデックスは複数の方法で機能できるということです。A、B、CのインデックスはA、B、および単にAでも機能するので、正しく順序付けすると、インデックスをより用途が広くなるように設計できます。電話帳は姓、名で索引付けされているため、姓、または姓と名の組み合わせで簡単に人を検索できます。ただし、名で直接検索することはできません。そのためには別のインデックスが必要です。同じことが電話番号にも当てはまり、電話番号もインデックスに登録する必要があります。

このことを念頭に置いて、インデックスの作成方法を決定する多くの事項があります。

  • belongs_to- has_many関係のペアがある場合は、使用する外部キーのインデックスが必要です。
  • レコードを注文し、ページ番号が付けられるレコードが多数ある場合は、その注文列をインデックスの最後に追加する必要があります。
  • あなたが持っている場合はhas_many :through関係を、あなたの結合テーブルは、複合キーとして加入に関わる両方の特性に一意のインデックスを持つ必要があります。
  • ユーザー名や電子メールなどの一意の識別子を使用してレコードを直接フェッチする場合、それは一意のインデックスである必要があります。
  • has_manyスコープを使用して関係からレコードのセットをフェッチする場合は、has_many外部キーとスコープ列をこの順序で含むインデックスがあることを確認してください。

インデックスの目的は、データのインデックスが適切に作成されていないときに発生する恐ろしい「テーブルスキャン」または「ファイルソート」操作を排除することです。

簡単に言うと、アプリケーションによって生成されるクエリを見て、参照される列WHEREまたはHAVING条件とORDER BY句がその順序で表現されていることを確認します。


1
すべての外部キーに常にインデックスを使用したいのに、なぜRailsがインデックスを意味しないのか、私は興味があります。インデックスを作成するのが適切でない状況はありますか?
2014年

1
@trip index: true単純なケースの列定義に追加するのは非常に簡単ですが、それをより詳細に制御したい場合もあります。外部キーにデフォルトでインデックスを設定することは、それほどひどいデフォルトではありませんが、人々を驚かせるかもしれません。
tadman 2014年

13
  • 常に外部キーにインデックスを付ける
  • 常に順序付けする列にインデックスを付けます
  • (データベース・レベルで一意性を保証するために例の移行。:すべてのユニークなフィールドadd_index :users, :email, unique: true
  • あなたは二つのことで注文、または二つで検索する場合は、例えば: order by [a, b]またはfind where( a and b )、あなたは二重のインデックスが必要になります。

具体例:

あなたが持っている場合:

default_scope :order => 'photos.created_at DESC, photos.version DESC'

追加する必要があります:

add_index :photos, [:created_at, :version]

注:インデックスは、各インデックスを再構築する必要があるため、ディスク上の余分なスペースを占有し、各レコードの作成と更新に時間がかかります。

クレジット:

https://tomafro.net/2009/08/using-indexes-in-rails-choosing-additional-indexesレール-発注のためのcreated_atユーザー、万一あなたがテーブルにインデックスを追加しますか?、および上記の答え。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.