Wann werden die Indizes in einer Tabelle in Rails hinzugefügt?

131

Ich habe eine Frage zur Rails-Datenbank.

  • Sollte ich allen Fremdschlüsseln wie "xxx_id" "index" hinzufügen?
  • Soll ich der automatisch erstellten Spalte "id" "index" hinzufügen?
  • Sollte ich der automatisch erstellten Spalte "id" "index (unique)" hinzufügen?

  • Wenn ich zwei Fremdschlüsseln gleichzeitig einen Index hinzufüge ( add_index (:users, [:category, :state_id])was passiert? Wie unterscheidet sich dies vom Hinzufügen des Index für jeden Schlüssel?

    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
    

Tolle Antwort bisher. Zusätzliche Frage.

  • Ich sollte "Index mit Eindeutigkeit" für xxx_id hinzufügen, oder?
TK.
quelle

Antworten:

175

Sollte ich allen Fremdschlüsseln wie "xxx_id" "index" hinzufügen?

Es wäre besser, weil es die Suche beim Sortieren in dieser Spalte beschleunigt. Und nach Fremdschlüsseln wird viel gesucht.

Seit Version 5 von Rails wird der Index automatisch erstellt. Weitere Informationen finden Sie hier .

Soll ich der automatisch erstellten Spalte "id" "index" hinzufügen?

Nein, das wird schon mit Schienen gemacht

Sollte ich der automatisch erstellten Spalte "id" "index (unique)" hinzufügen?

Nein, wie oben

Wenn ich zwei Fremdschlüsseln gleichzeitig einen Index hinzufüge ( add_index (:users, [:category_id, :state_id])was passiert? Wie unterscheidet sich dies vom Hinzufügen des Index für jeden Schlüssel?

Dann ist der Index ein kombinierter Index der beiden Spalten. Das macht keinen Sinn, es sei denn, Sie möchten alle Einträge für ein category_id UND eins state_id(sollte es category_idnicht sein category) gleichzeitig.

Ein Index wie dieser würde die folgende Anforderung beschleunigen:

# 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)

Wo

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

wird diese Anfragen beschleunigen:

# 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)

Ich sollte "Index mit Eindeutigkeit" für xxx_id hinzufügen, oder?

Nein, denn wenn Sie dies tun, nur ein Benutzer kann in einer Kategorie sein, aber die Bedeutung der Kategorie ist , dass Sie mehr setzen können viele Benutzer in eine Kategorie. In Ihrem UserModell haben Sie so etwas belongs_to :categoryund in Ihrem Kategoriemodell so etwas has_many :users. Wenn Sie eine has_manyBeziehung haben foreign_key, darf das Feld nicht eindeutig sein!

Für detailliertere Informationen sollten Sie sich die großartige Antwort von tadman ansehen .

Jigfox
quelle
3
Gute Antwort. Zusätzliche Frage. Ich sollte "Index mit eindeutigem" für xxx_id hinzufügen, oder?
TK.
Frage: Würden Sie einen Fremdschlüssel indizieren, wenn dieses Feld nur sehr selten explizit durchsucht wird?
Noz
@Cyle Ich kann das nicht definitiv beantworten, es hängt von Ihrem Computer, der Größe der Datenbank und der Art Ihrer Anfrage ab. Wenn die Abfrage aus dem Internet stammt, würde ich wahrscheinlich JA sagen, da es immer besser ist, schnelle Antworten zu erhalten. Wenn es sich um einen Hintergrundjob handelt und Sie Speicherplatz sparen müssen, müssen Sie ihn nicht festlegen, aber wenn der Speicherplatz ist kein Problem, ich würde sowieso einen Index hinzufügen.
Jigfox
111

Die Indizierung kann schwierig und subtil sein, es gelten jedoch allgemeine Regeln, die die Bestimmung der zu verwendenden Regeln erheblich vereinfachen können.

Das erste, woran Sie sich erinnern sollten, ist, dass Indizes auf mehrere Arten funktionieren können. Ein Index für A, B, C funktioniert auch für A, B und einfach für A, sodass Sie Ihre Indizes vielseitiger gestalten können, wenn Sie sie richtig bestellen. Das Telefonbuch ist nach Nachname, Vorname indiziert, sodass Sie Personen leicht nach ihrem Nachnamen oder einer Kombination aus Nachname und Vorname suchen können. Sie können sie jedoch nicht direkt beim Vornamen nachschlagen. Dafür benötigen Sie einen separaten Index. Gleiches gilt für die Telefonnummer, die Sie ebenfalls indizieren müssten.

In diesem Sinne gibt es viele Faktoren, die bestimmen, wie Sie Indizes erstellen:

  • Wenn Sie eine haben belongs_to- has_manyBeziehung Paarung, müssen Sie verwendet einen Index für die Fremdschlüssel haben.
  • Wenn Sie Ihre Datensätze bestellen und eine große Anzahl von ihnen paginiert wird, sollten Sie diese Bestellspalte am Ende des Index hinzufügen.
  • Wenn Sie eine has_many :throughBeziehung haben, sollte Ihre Join-Tabelle einen eindeutigen Index für beide am Join beteiligten Eigenschaften als zusammengesetzten Schlüssel haben.
  • Wenn Sie einen Datensatz direkt mit einer eindeutigen Kennung wie Benutzername oder E-Mail abrufen, sollte dies ein eindeutiger Index sein.
  • Wenn Sie Datensätze has_manymithilfe eines Bereichs aus einer Beziehung abrufen, stellen Sie sicher, dass ein Index vorhanden ist, der den has_manyFremdschlüssel und die Bereichsspalte in dieser Reihenfolge enthält.

Das Ziel bei Indizes besteht darin, die gefürchteten Operationen "Tabellenscan" oder "Dateisortierung" zu beseitigen, die auftreten, wenn Ihre Daten nicht ordnungsgemäß indiziert werden.

Schauen Sie sich in einfachen Worten die Abfragen an, die von Ihrer Anwendung generiert werden, und stellen Sie sicher, dass Spalten, auf die verwiesen wird, WHEREoder HAVINGBedingungen und ORDER BYKlauseln in dieser Reihenfolge dargestellt werden.

Tadman
quelle
1
Ich bin gespannt, warum Rails keine Indizes impliziert, wenn Sie sie immer für jeden Fremdschlüssel verwenden möchten. Gibt es eine Situation, in der es keine gute Idee ist, sie zu indizieren?
Reise
1
@trip Es ist ziemlich einfach, index: trueIhre Spaltendefinition für einfache Fälle hinzuzufügen , aber manchmal möchten Sie vielleicht mehr Kontrolle darüber. Indizes für Fremdschlüssel standardmäßig zu haben, ist keine schreckliche Standardeinstellung, kann aber die Leute überraschen.
Tadman
13
  • Indizieren Sie immer Fremdschlüssel
  • Indizieren Sie immer Spalten, nach denen Sie bestellen
  • Alle einzigartigen Felder (um sicherzustellen , auf Datenbankebene Einzigartigkeit Beispiel Migration:. add_index :users, :email, unique: true)
  • Wenn Sie nach zwei Dingen bestellen oder nach zwei Dingen suchen, zum Beispiel: order by [a, b]oder find where( a and b ), dann benötigen Sie einen Doppelindex:

Konkretes Beispiel:

Wenn Sie haben:

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

Sie sollten hinzufügen:

add_index :photos, [:created_at, :version]

Hinweis: Ein Index belegt zusätzlichen Speicherplatz auf der Festplatte und verlangsamt das Erstellen und Aktualisieren jedes Datensatzes, da jeder Index neu erstellt werden muss.

Anerkennung:

https://tomafro.net/2009/08/using-indexes-in-rails-choosing-additional-indexes , Rails - created_at beim Benutzer für die Bestellung, Sollten Sie der Tabelle einen Index hinzufügen? und die obigen Antworten.

Will Taylor
quelle