Pergunta

Suponha que você tem dois modelos, Usuário e City, unidas por uma terceira CityPermission modelo:

class CityPermission < ActiveRecord::Base
  belongs_to :city
  belongs_to :user
end

class City < ActiveRecord::Base
  has_many :city_permissions
  has_many :users, :through => :city_permissions
end

class User < ActiveRecord::Base
  has_many :city_permissions
  has_many :cities, :through => :city_permissions
end

Atualmente, eu criar a tabela de junção, eo índice para a tabela, usando o seguinte trecho de código de migração:

create_table :city_permissions do |t|
      t.integer :user_id, :city_id
      t.other_fields ...
end

add_index(:city_permissions, :user_id)
add_index(:city_permissions, :city_id)

São estes os índices ideais para criar? Será que esses índices permitem voltar rápido acesso e para trás através da tabela de junção, bem como pesquisas rápidas dentro da tabela em si, ou se há alguma outra maneira melhor? Para enfatizar este um pouco diferente, será que estes índices, dada city e user são variáveis ??de instância de classe City e usuário, permitem city.users, city.city_permissions, user.cities e user.city_permissions a todos executar igualmente bem?

Foi útil?

Solução

Parece bom para mim.

A junta gerado deve ser apenas em ambos os IDs PK das tabelas entidade ou no FK IDs na tabela de junção -. Que são ambos os índices

Provavelmente seria bom para olhar para o ActiveRecord SQL gerado e compará-la com os índices.

Dependendo do que banco de dados você está em você poderia então executar esse SQL através de um plano Explique (ou o que existe ferramenta, eu estou pensando a Oracle aqui)

Para simplificar o seu código, você pode olhar para usando has_and_belongs_to_many também. Que iria deixá-lo a se livrar do objeto CityPermission (a menos que você quiser usá-lo para armazenar dados em si)

Outras dicas

Aqui está o SQL que ActiveRecord gera para user.cities:

SELECT `cities`.* FROM `cities` INNER JOIN city_permissions ON (cities.id = city_permissions.city_id) WHERE (city_permissions.user_id = 1 )

explicar os resultados abaixo:

+----+-------------+------------------+--------+---------------------------------------------------------------------+-----------------------------------+---------+-------------------------------------------------+------+-------------+
| id | select_type | table            | type   | possible_keys                                                       | key                               | key_len | ref                                             | rows | Extra       |
+----+-------------+------------------+--------+---------------------------------------------------------------------+-----------------------------------+---------+-------------------------------------------------+------+-------------+
|  1 | SIMPLE      | city_permissions | ref    | index_city_permissions_on_user_id,index_city_permissions_on_city_id | index_city_permissions_on_user_id | 5       | const                                           |    1 | Using where |
|  1 | SIMPLE      | cities           | eq_ref | PRIMARY                                                             | PRIMARY                           | 4       | barhopolis_development.city_permissions.city_id |    1 |             |
+----+-------------+------------------+--------+---------------------------------------------------------------------+-----------------------------------+---------+-------------------------------------------------+------+-------------+

E aqui está o SQL que ActiveRecord gera para user.city_permissions:

SELECT * FROM `city_permissions` WHERE (`city_permissions`.user_id = 1)

Com os resultados para essa consulta EXPLICAR:

+----+-------------+------------------+------+-----------------------------------+-----------------------------------+---------+-------+------+-------------+
| id | select_type | table            | type | possible_keys                     | key                               | key_len | ref   | rows | Extra       |
+----+-------------+------------------+------+-----------------------------------+-----------------------------------+---------+-------+------+-------------+
|  1 | SIMPLE      | city_permissions | ref  | index_city_permissions_on_user_id | index_city_permissions_on_user_id | 5       | const |    1 | Using where |
+----+-------------+------------------+------+-----------------------------------+-----------------------------------+---------+-------+------+-------------+

Parece que ele é realmente funcionando corretamente . A partir do MySQL manual:

eq_ref

Uma linha é lida desta tabela para cada combinação de linhas das tabelas anteriores. Diferente do sistema e tipos const, este é o melhor tipo de join. É usado quando todas as partes do índice são usados ??pela join eo índice é uma chave primária ou índice exclusivo.

ref

Todas as linhas com correspondentes valores de índice são lidos a partir desta tabela para cada combinação de linhas das tabelas anteriores. ref é usado se a juntar-se usa apenas um mais à esquerda do prefixo da chave ou se a chave não é uma chave primária ou índice exclusivo (em outras palavras, se a junção não pode selecionar uma única linha com base no valor de chave). Se a chave que é jogos usados ??apenas algumas linhas, este é um bom tipo de junção.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top