Quand ajouter quels index dans une table dans Rails

131

J'ai une question sur la base de données Rails.

  • Dois-je ajouter "index" à toutes les clés étrangères comme "xxx_id"?
  • Dois-je ajouter "index" à la colonne "id" créée automatiquement?
  • Dois-je ajouter "index (unique)" à la colonne "id" créée automatiquement?

  • Si j'ajoute un index à deux clés étrangères à la fois ( add_index (:users, [:category, :state_id]), que se passe-t-il? En quoi est-ce différent de l'ajout de l'index pour chaque clé?

    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

Excellente réponse jusqu'à présent. Question supplémentaire.

  • Je devrais ajouter "index avec unique" pour xxx_id, non?
TK.
la source

Réponses:

175

Dois-je ajouter "index" à toutes les clés étrangères comme "xxx_id"?

Ce serait mieux, car cela accélère la recherche en tri dans cette colonne. Et les clés étrangères sont souvent recherchées.

Depuis la version 5 des rails, l'index sera créé automatiquement, pour plus d'informations, cliquez ici .

Dois-je ajouter "index" à la colonne "id" créée automatiquement?

Non, cela se fait déjà par rails

Dois-je ajouter "index (unique)" à la colonne "id" créée automatiquement?

Non, comme ci-dessus

Si j'ajoute un index à deux clés étrangères à la fois ( add_index (:users, [:category_id, :state_id]), que se passe-t-il? En quoi est-ce différent de l'ajout de l'index pour chaque clé?

Ensuite, l'index est un index combiné des deux colonnes. Cela n'a aucun sens, sauf si vous voulez toutes les entrées pour un category_id ET un state_id(cela ne devrait category_idpas être category) en même temps.

Un index comme celui-ci accélérerait la requête suivante:

# 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

accélérera ces demandes:

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

Je devrais ajouter "index avec unique" pour xxx_id, non?

Non, car si vous faites cela, un seul utilisateur peut être dans une catégorie, mais la signification de la catégorie est que vous pouvez mettre plus d' utilisateurs dans une seule catégorie. Dans votre Usermodèle, vous avez quelque chose comme ça belongs_to :categoryet dans votre modèle de catégorie quelque chose comme has_many :users. Si vous avez une has_manyrelation, le foreign_keychamp ne doit pas être unique!

Pour des informations plus détaillées à ce sujet, vous devriez jeter un œil à la grande réponse de tadman .

jigfox
la source
3
Très bonne réponse. Question supplémentaire. Je devrais ajouter "index avec unique" pour xxx_id, non?
TK.
Question, indexeriez-vous une clé étrangère si ce champ est très rarement recherché explicitement?
Noz
@Cyle Je ne peux pas répondre définitivement à cela, cela dépend de votre machine, de la taille de la base de données et de la nature de votre requête. Si la requête provient du Web, je dirais probablement OUI, car il est toujours préférable d'obtenir des réponses rapides, s'il s'agit d'un travail en arrière-plan et que vous devez économiser de l'espace disque, vous n'avez pas besoin de le définir, mais si l'espace disque n'est pas un problème, j'ajouterais quand même un index
jigfox
111

L'indexation peut être une chose délicate et subtile, mais il existe des règles générales qui s'appliquent qui peuvent faciliter la détermination des éléments à utiliser.

La première chose à retenir est que les index peuvent fonctionner de plusieurs manières. Un index sur A, B, C fonctionne également pour A, B et simplement A, vous pouvez donc concevoir vos index pour qu'ils soient plus polyvalents si vous les commandez correctement. L'annuaire téléphonique est indexé sur le nom, le prénom, de sorte que vous pouvez rechercher facilement les personnes par leur nom de famille ou une combinaison de nom et prénom. Cependant, vous ne pouvez pas les rechercher directement par leur prénom. Vous auriez besoin d'un index séparé pour cela. Il en va de même pour le numéro de téléphone, que vous devrez également indexer.

Dans cet esprit, il y a beaucoup de choses qui dicteront comment vous créez des index:

  • Si vous avez une paire de relations belongs_to- has_many, vous devez avoir un index sur la clé étrangère utilisée.
  • Si vous commandez vos enregistrements et qu'il y en a un grand nombre qui seront paginés, vous devez ajouter cette colonne d'ordre à la fin de l'index.
  • Si tu as un has_many :through relation, votre table de jointure doit avoir un index unique sur les deux propriétés impliquées dans la jointure en tant que clé composée.
  • Si vous récupérez un enregistrement directement à l'aide d'un identifiant unique tel qu'un nom d'utilisateur ou une adresse e-mail, il doit s'agir d'un index unique.
  • Si vous récupérez des ensembles d'enregistrements à partir d'une has_manyrelation à l'aide d'une étendue, assurez-vous qu'il existe un index qui inclut la has_manyclé étrangère et la colonne d'étendue dans cet ordre.

Le but des index est d'éliminer les redoutables opérations de «balayage de table» ou de «tri de fichiers» qui se produisent lorsque vos données ne sont pas indexées correctement.

En termes simples, examinez les requêtes générées par votre application et assurez-vous que les colonnes référencées dans WHEREou les HAVINGconditions et ORDER BYclauses sont représentées dans cet ordre.

tadman
la source
1
Je suis curieux de savoir pourquoi Rails n'implique pas d'index si vous voulez toujours les utiliser pour chaque clé étrangère. Y a-t-il une situation où ce n'est pas une bonne idée de l'indexer?
Voyage du
1
@trip Il est assez facile d'ajouter index: trueà votre définition de colonne pour les cas simples, mais parfois vous voudrez peut-être plus de contrôle sur elle. Avoir des index par défaut sur des clés étrangères n'est pas un terrible défaut à avoir, mais cela pourrait surprendre les gens.
tadman
13
  • Toujours indexer les clés étrangères
  • Indexez toujours les colonnes que vous classerez
  • Tous les champs uniques (pour garantir l' unicité à un niveau de base de données migration Exemple:. add_index :users, :email, unique: true)
  • Si vous commandez par deux choses, ou effectuez une recherche par deux choses, par exemple: order by [a, b]ou find where( a and b ), alors vous avez besoin d'un double index:

Exemple concret:

Si tu as:

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

Vous devez ajouter:

add_index :photos, [:created_at, :version]

Remarque: un index occupe de l'espace supplémentaire sur le disque et ralentit la création et la mise à jour de chaque enregistrement, car il doit reconstruire chaque index.

Crédit:

https://tomafro.net/2009/08/using-indexes-in-rails-choosing-additional-indexes , rails - created_at lorsque l'utilisateur pour la commande, devez-vous ajouter un index à la table? , et les réponses ci-dessus.

Will Taylor
la source