Cuándo agregar qué índices en una tabla en Rails

131

Tengo una pregunta sobre la base de datos Rails.

  • ¿Debo agregar "índice" a todas las claves externas como "xxx_id"?
  • ¿Debo agregar "índice" a la columna "id" creada automáticamente?
  • ¿Debo agregar "index (unique)" a la columna "id" creada automáticamente?

  • Si agrego índice a dos claves externas a la vez ( add_index (:users, [:category, :state_id])¿qué sucede? ¿En qué se diferencia esto de agregar el índice para cada clave?

    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

Gran respuesta hasta ahora. Pregunta adicional

  • Debo agregar "index with unique" para xxx_id, ¿verdad?
TK
fuente

Respuestas:

175

¿Debo agregar "índice" a todas las claves externas como "xxx_id"?

Sería mejor, porque acelera la búsqueda al ordenar en esta columna. Y las claves externas son algo que se busca mucho.

Desde la versión 5 de rails, el índice se creará automáticamente, para obtener más información, consulte aquí .

¿Debo agregar "índice" a la columna "id" creada automáticamente?

No, esto ya se hace por rieles.

¿Debo agregar "index (unique)" a la columna "id" creada automáticamente?

No, igual que el anterior

Si agrego índice a dos claves externas a la vez ( add_index (:users, [:category_id, :state_id])¿qué sucede? ¿En qué se diferencia esto de agregar el índice para cada clave?

Entonces el índice es un índice combinado de las dos columnas. Eso no tiene ningún sentido, a menos que desee todas las entradas para uno category_id Y uno state_id( category_idno debería ser category) al mismo tiempo.

Un índice como este aceleraría la siguiente solicitud:

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

Dónde

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

acelerará estas solicitudes:

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

Debo agregar "index with unique" para xxx_id, ¿verdad?

No, porque si lo hace, sólo un usuario puede estar en una categoría, pero el significado de la categoría es que se puede poner más muchos usuarios en una sola categoría. En su Usermodelo tiene algo como esto belongs_to :categoryy en su modelo de categoría algo así has_many :users. Si tiene una has_manyrelación, el foreign_keycampo no debe ser único.

Para obtener información más detallada sobre esto, debe echar un vistazo a la excelente respuesta de tadman .

jigfox
fuente
3
Gran respuesta. Pregunta adicional Debo agregar "index with unique" para xxx_id, ¿verdad?
TK.
Pregunta, ¿indexaría una clave externa si rara vez se busca explícitamente ese campo?
Noz
@Cyle No puedo responder esto definitivamente, depende de su máquina, el tamaño de la base de datos y la naturaleza de su consulta. Si la consulta proviene de la web, probablemente diría SÍ, porque siempre es mejor obtener respuestas rápidas, si es para un trabajo en segundo plano y necesita ahorrar espacio en el disco, no necesita configurarlo, pero si el espacio en el disco no es un problema, de todos modos agregaría un índice.
jigfox
111

La indexación puede ser algo sutil y complicado, pero hay reglas generales que se aplican que pueden hacer que determinar cuál usar sea mucho más fácil.

Lo primero que debe recordar es que los índices pueden funcionar en más de una forma. Un índice en A, B, C también funciona para A, B y simplemente A, por lo que puede diseñar sus índices para que sean más versátiles si los ordena correctamente. La guía telefónica está indexada en Apellido, Nombre, por lo que puede buscar personas fácilmente por su apellido o una combinación de apellido y nombre. Sin embargo, no puede buscarlos directamente por su nombre de pila. Necesitarías un índice separado para eso. Lo mismo ocurre con el número de teléfono, que también debería indexar.

Con eso en mente, hay muchas cosas que dictarán cómo crear índices:

  • Si usted tiene un belongs_to- has_manyregistrar su teléfono móvil, es necesario tener un índice en la clave externa utilizada.
  • Si ordena sus registros y hay una gran cantidad de ellos que se paginarán, debe agregar esa columna de orden al final del índice.
  • Si tiene una has_many :throughrelación, su tabla de unión debe tener un índice único en ambas propiedades involucradas en la unión como una clave compuesta.
  • Si obtiene un registro directamente utilizando un identificador único, como nombre de usuario o correo electrónico, ese debería ser un índice único.
  • Si obtiene conjuntos de registros de una has_manyrelación utilizando un ámbito, asegúrese de que haya un índice que incluya la has_manyclave externa y la columna de ámbito en ese orden.

El objetivo con los índices es eliminar las temidas operaciones de "escaneo de tablas" u "clasificación de archivos" que se producen cuando sus datos no se indexan correctamente.

En términos simples, observe las consultas que genera su aplicación y asegúrese de que las columnas a las que se hace referencia WHEREo las HAVINGcondiciones y ORDER BYcláusulas estén representadas en ese orden.

tadman
fuente
1
Tengo curiosidad por qué Rails no implica índices si siempre desea usarlos para cada clave externa. ¿Hay alguna situación en la que no sea una buena idea indexarlo?
Viaje del
1
@trip Es bastante fácil agregar index: truea su definición de columna para casos simples, pero a veces es posible que desee tener más control sobre ella. Tener índices por defecto en las claves externas no es un terrible defecto, pero puede sorprender a las personas.
tadman
13
  • Siempre indexe claves foráneas
  • Siempre indexe las columnas que ordenará por
  • Todos los campos únicos (para garantizar la unicidad en un nivel de base de datos Ejemplo migración:. add_index :users, :email, unique: true)
  • Si ordena por dos cosas, o busca por dos cosas, por ejemplo: order by [a, b]o find where( a and b ), entonces necesita un índice doble:

Ejemplo concreto:

Si usted tiene:

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

Deberías agregar:

add_index :photos, [:created_at, :version]

Nota: Un índice ocupa espacio adicional en el disco y hace que sea más lento crear y actualizar cada registro, ya que tiene que reconstruir cada índice.

Crédito:

https://tomafro.net/2009/08/using-indexes-in-rails-choosing-additional-indexes , rails - created_at cuando el usuario solicita, ¿debe agregar un índice a la tabla? , y las respuestas anteriores.

Will Taylor
fuente