Quando adicionar quais índices em uma tabela no Rails

131

Eu tenho uma pergunta sobre o banco de dados Rails.

  • Devo adicionar "index" a todas as chaves estrangeiras como "xxx_id"?
  • Devo adicionar "index" à coluna "id" criada automaticamente?
  • Devo adicionar "índice (exclusivo)" à coluna "id" criada automaticamente?

  • Se eu adicionar índice a duas chaves estrangeiras ao mesmo tempo ( add_index (:users, [:category, :state_id]), o que acontece? Como isso é diferente de adicionar o índice para cada chave?

    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

Ótima resposta até agora. Pergunta adicional.

  • Eu deveria adicionar "index with unique" para xxx_id, certo?
TK.
fonte

Respostas:

175

Devo adicionar "index" a todas as chaves estrangeiras como "xxx_id"?

Seria melhor, porque acelera a pesquisa na classificação nesta coluna. E chaves estrangeiras são algo procurado muito.

Desde a versão 5 dos trilhos, o índice será criado automaticamente, para obter mais informações, consulte aqui .

Devo adicionar "index" à coluna "id" criada automaticamente?

Não, isso já é feito por trilhos

Devo adicionar "índice (exclusivo)" à coluna "id" criada automaticamente?

Não, o mesmo que acima

Se eu adicionar índice a duas chaves estrangeiras ao mesmo tempo ( add_index (:users, [:category_id, :state_id]), o que acontece? Como isso é diferente de adicionar o índice para cada chave?

Então o índice é um índice combinado das duas colunas. Isso não faz nenhum sentido, a menos que você queira todas as entradas para um category_id E um state_id( category_idnão deve ser category) ao mesmo tempo.

Um índice como esse aceleraria a solicitação a seguir:

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

Onde

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

irá acelerar estes pedidos:

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

Eu deveria adicionar "index with unique" para xxx_id, certo?

Não, porque se você fizer isso, somente um usuário pode estar em uma categoria, mas o significado da categoria é que você pode colocar mais muitos usuários em uma única categoria. No seu Usermodelo, você tem algo assim belongs_to :categorye no seu modelo de Categoria, algo como has_many :users. Se você tem um has_manyrelacionamento, o foreign_keycampo não deve ser único!

Para informações mais detalhadas sobre isso, você deve dar uma olhada na excelente resposta de tadman .

jigfox
fonte
3
Ótima resposta. Pergunta adicional. Eu deveria adicionar "index with unique" para xxx_id, certo?
TK.
Pergunta, você indexaria uma chave estrangeira se esse campo raramente for pesquisado explicitamente?
Noz
@Yle Não posso responder isso definitivamente, depende da sua máquina, do tamanho do banco de dados e da natureza da sua consulta. Se a consulta vier da Web, eu provavelmente diria SIM, porque é sempre melhor obter respostas rápidas, se for para um trabalho em segundo plano e você precisar economizar espaço em disco, não precisa defini-lo, mas se o espaço em disco não é um problema, eu adicionaria um índice de qualquer maneira.
jigfox
111

A indexação pode ser uma coisa sutil e complicada, mas existem regras gerais que se aplicam que podem facilitar muito a determinação de qual usar.

A primeira coisa a lembrar é que os índices podem funcionar de mais de uma maneira. Um índice em A, B, C também funciona para A, B e simplesmente A, para que você possa projetar seus índices para serem mais versáteis se os solicitar corretamente. A lista telefônica é indexada em Sobrenome, Nome, para que você possa procurar facilmente as pessoas pelo sobrenome ou uma combinação de sobrenome e nome. Você não pode, no entanto, procurá-los diretamente pelo primeiro nome. Você precisaria de um índice separado para isso. O mesmo vale para o número de telefone, que você também precisará indexar.

Com isso em mente, há muitas coisas que ditarão como você cria índices:

  • Se você tem um belongs_to- has_manyrelação de pareamento, você precisa ter um índice na chave estrangeira usada.
  • Se você solicitar seus registros, e houver um grande número deles que serão paginados, adicione essa coluna de pedidos ao final do índice.
  • Se você tiver um has_many :throughrelacionamento, sua tabela de junção deverá ter um índice exclusivo nas duas propriedades envolvidas na junção como uma chave composta.
  • Se você buscar um registro diretamente usando um identificador exclusivo, como nome de usuário ou email, esse deverá ser um índice exclusivo.
  • Se você buscar conjuntos de registros de um has_manyrelacionamento usando um escopo, verifique se há um índice que inclua a has_manychave estrangeira e a coluna do escopo nessa ordem.

O objetivo dos índices é eliminar as temidas operações de "varredura de tabela" ou "classificação de arquivo" que ocorrem quando seus dados não são indexados corretamente.

Em termos simples, observe as consultas geradas pelo seu aplicativo e verifique se as colunas mencionadas WHEREou as HAVINGcondições e ORDER BYcláusulas estão representadas nessa ordem.

tadman
fonte
1
Estou curioso para saber por que o Rails não implica índices, se você sempre quiser usá-los para todas as chaves estrangeiras. Existe uma situação em que não é uma boa ideia indexá-lo?
Viagem
1
@ trip É muito fácil adicionar index: truesua definição de coluna para casos simples, mas às vezes você pode querer ter mais controle sobre ela. Ter índices por padrão em chaves estrangeiras não é um padrão terrível, mas pode surpreender as pessoas.
Tadman
13
  • Sempre indexar chaves estrangeiras
  • Sempre indexe as colunas que você ordenará
  • Todos os campos únicos (para assegurar a unicidade a um nível de base de dados Exemplo migração:. add_index :users, :email, unique: true)
  • Se você solicitar duas coisas ou pesquisar por duas coisas, por exemplo: order by [a, b]ou find where( a and b ), precisará de um índice duplo:

Exemplo concreto:

Se você tem:

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

Você deve adicionar:

add_index :photos, [:created_at, :version]

Nota: Um índice ocupa espaço extra no disco e torna mais lento a criação e a atualização de cada registro, porque é necessário reconstruir cada índice.

Crédito:

https://tomafro.net/2009/08/using-indexes-in-rails-choosing-additional-indexes , trilhos - created_at quando o usuário solicita, você deve adicionar um índice à tabela? e as respostas acima.

Will Taylor
fonte