Quando aggiungere gli indici in una tabella in Rails


131

Ho una domanda sul database Rails.

  • Devo aggiungere "index" a tutte le chiavi esterne come "xxx_id"?
  • Devo aggiungere "indice" alla colonna "id" creata automaticamente?
  • Devo aggiungere "index (unico)" alla colonna "id" creata automaticamente?

  • Se aggiungo l'indice a due chiavi esterne contemporaneamente ( add_index (:users, [:category, :state_id])cosa succede? In cosa differisce dall'aggiungere l'indice per ciascuna chiave?

    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

Ottima risposta finora. Domanda aggiuntiva.

  • Dovrei aggiungere "index with unique" per xxx_id, giusto?

Risposte:


175

Devo aggiungere "index" a tutte le chiavi esterne come "xxx_id"?

Sarebbe meglio, perché accelera la ricerca nell'ordinamento in questa colonna. E le chiavi esterne sono molto ricercate.

Dalla versione 5 dei binari l'indice verrà creato automaticamente, per ulteriori informazioni consultare qui .

Devo aggiungere "indice" alla colonna "id" creata automaticamente?

No, questo è già stato fatto dalle rotaie

Devo aggiungere "index (unico)" alla colonna "id" creata automaticamente?

No, come sopra

Se aggiungo l'indice a due chiavi esterne contemporaneamente ( add_index (:users, [:category_id, :state_id])cosa succede? In cosa differisce dall'aggiungere l'indice per ciascuna chiave?

Quindi l'indice è un indice combinato delle due colonne. Questo non ha alcun senso, a meno che non si desidera che tutte le voci per uno category_id e uno state_id(dovrebbe essere category_idnon category) allo stesso tempo.

Un indice come questo accelererebbe la seguente richiesta:

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

Dove

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

accelererà queste richieste:

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

Dovrei aggiungere "index with unique" per xxx_id, giusto?

No, perché se fate questo, solo un utente può essere in una categoria, ma il significato di categoria è che si può mettere più molti utenti in una categoria. Nel tuo Usermodello hai qualcosa di simile belongs_to :categorye nel tuo modello di Categoria qualcosa di simile has_many :users. Se hai una has_manyrelazione, il foreign_keycampo non deve essere unico!

Per informazioni più dettagliate a riguardo, dai un'occhiata alla grande risposta di Tadman .


3
Bella risposta. Domanda aggiuntiva. Dovrei aggiungere "index with unique" per xxx_id, giusto?
TK.

Domanda, indicizzeresti una chiave esterna se quel campo viene cercato molto raramente in modo esplicito?
Noz,

@Cyle Non posso rispondere in modo definitivo, dipende dalla tua macchina, dalle dimensioni del database e dalla natura della tua query. Se la query proviene dal Web, probabilmente direi SÌ, perché è sempre meglio ottenere risposte rapide, se è per un lavoro in background e è necessario risparmiare spazio su disco, non è necessario impostarlo, ma se lo spazio su disco non è un problema aggiungerei comunque un indice.
jigfox,

111

L'indicizzazione può essere una cosa delicata e delicata, ma ci sono regole generali che possono rendere più facile la determinazione di quale usare.

La prima cosa da ricordare è che gli indici possono funzionare in più di un modo. Un indice su A, B, C funziona anche per A, B e semplicemente A, quindi puoi progettare i tuoi indici in modo che siano più versatili se li ordini correttamente. La rubrica è indicizzata su Cognome, Nome, in modo da poter cercare facilmente le persone con il loro cognome o una combinazione di cognome e nome. Non puoi, tuttavia, cercarli direttamente con il loro nome. Avresti bisogno di un indice separato per quello. Lo stesso vale per il numero di telefono, che dovresti anche indicizzare.

Con questo in mente, ci sono molte cose che determineranno il modo in cui crei gli indici:

  • Se hai un belongs_to-has_many rapporto di abbinamento, è necessario disporre di un indice sulla chiave esterna utilizzata.
  • Se ordini i tuoi record e ce ne sono molti che verranno impaginati, dovresti aggiungere quella colonna di ordine alla fine dell'indice.
  • Se si dispone di una has_many :throughrelazione, la tabella dei join deve avere un indice univoco su entrambe le proprietà coinvolte nel join come chiave composta.
  • Se recuperi un record direttamente utilizzando un identificatore univoco come nome utente o e-mail, dovrebbe essere un indice univoco.
  • Se recuperi set di record da una has_manyrelazione utilizzando un ambito, assicurati che esista un indice che includa la has_manychiave esterna e la colonna ambito in quell'ordine.

L'obiettivo con gli indici è quello di eliminare le temute operazioni di "scansione della tabella" o "ordinamento dei file" che si verificano quando i dati non vengono indicizzati correttamente.

In termini semplici, guarda le query generate dalla tua applicazione e assicurati che le colonne a cui fanno riferimento WHEREo le HAVINGcondizioni e le ORDER BYclausole siano rappresentate in quell'ordine.


1
Sono curioso di sapere perché Rails non implica indici se si desidera sempre utilizzarli per ogni chiave esterna. Esiste una situazione in cui non è una buona idea indicizzarla?
Viaggio

1
@trip È abbastanza facile aggiungere index: truealla definizione della colonna per casi semplici, ma a volte potresti volere un maggiore controllo su di essa. Avere indici di default su chiavi esterne non è un terribile default, ma potrebbe sorprendere le persone.
Tadman,

13
  • Indicizza sempre le chiavi esterne
  • Indicizza sempre le colonne in base alle quali ordinerai
  • Tutti i campi unici (per garantire l'unicità a livello database di migrazione Esempio:. add_index :users, :email, unique: true)
  • Se ordini per due cose o cerchi per due cose, ad esempio: order by [a, b]oppure find where( a and b ), hai bisogno di un doppio indice:

Esempio concreto:

Se hai:

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

È necessario aggiungere:

add_index :photos, [:created_at, :version]

Nota: un indice occupa più spazio sul disco e rende più lento la creazione e l'aggiornamento di ogni record, poiché deve ricostruire ciascun indice.

Credito:

https://tomafro.net/2009/08/using-indexes-in-rails-choosing-additional-indexes , rails - create_at quando l'utente per l'ordinazione, è necessario aggiungere un indice alla tabella? e le risposte sopra.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.