Domanda

Supponi di avere due modelli, Utente e Città, uniti da un CityPermission di terzo modello:

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

Attualmente, creo la tabella di join e l'indice per la tabella, utilizzando il seguente frammento di codice di migrazione:

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)

Sono questi gli indici ottimali da creare? Questi indici consentiranno un accesso rapido avanti e indietro attraverso la tabella di join, nonché ricerche rapide all'interno della tabella stessa o esiste un altro modo migliore? Per ribadirlo in modo leggermente diverso, questi indici, dati city e user sono variabili di istanza della classe City e User, consentono city.users , city.city_permissions , user.cities e user.city_permissions si comportano allo stesso modo?

È stato utile?

Soluzione

Mi sembra bello.

I join generati dovrebbero essere solo sugli ID PK delle tabelle delle entità o sugli ID FK nella tabella dei join, che sono entrambi indici.

Probabilmente sarebbe bene guardare l'SQL ActiveRecord generato e confrontarlo con gli indici.

A seconda del database su cui ti trovi potresti quindi eseguire quell'SQL attraverso un piano Explain (o qualunque strumento esista, sto pensando Oracle qui)

Per semplificare il tuo codice, puoi utilizzare has_and_belongs_to_many pure. Ciò ti consentirebbe di eliminare l'oggetto CityPermission (a meno che tu non voglia utilizzarlo per archiviare i dati in sé)

Altri suggerimenti

Ecco l'SQL che ActiveRecord genera per user.cities :

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

ESPLORA i risultati di seguito:

+----+-------------+------------------+--------+---------------------------------------------------------------------+-----------------------------------+---------+-------------------------------------------------+------+-------------+
| 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 |             |
+----+-------------+------------------+--------+---------------------------------------------------------------------+-----------------------------------+---------+-------------------------------------------------+------+-------------+

Ed ecco l'SQL che ActiveRecord genera per user.city_permissions :

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

Con i risultati EXPLAIN per quella query:

+----+-------------+------------------+------+-----------------------------------+-----------------------------------+---------+-------+------+-------------+
| 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 |
+----+-------------+------------------+------+-----------------------------------+-----------------------------------+---------+-------+------+-------------+

Sembra che funzioni davvero correttamente . Dal manuale di MySQL:

eq_ref

Una riga viene letta da questa tabella per ogni combinazione di righe delle tabelle precedenti. Oltre al tipo di sistema e const, questo è il miglior tipo di join possibile. Viene utilizzato quando tutte le parti di un indice vengono utilizzate dal join e l'indice è un PRIMARY KEY o un indice UNIQUE.

ref

Tutte le righe con valori di indice corrispondenti vengono lette da questa tabella per ogni combinazione di righe delle tabelle precedenti. ref viene utilizzato se il join utilizza solo un prefisso più a sinistra della chiave o se la chiave non è un PRIMARY KEY o un indice UNIQUE (in altre parole, se il join non può selezionare una singola riga in base al valore della chiave). Se la chiave utilizzata corrisponde solo a poche righe, questo è un buon tipo di join.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top