Indizes für has_many: durch
-
03-07-2019 - |
Frage
Angenommen, Sie haben zwei Modelle, Benutzer und Stadt, durch ein drittes Modell CityPermission verbunden:
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
Derzeit erstelle ich den Tisch kommen, und den Index für die Tabelle, den folgenden Migration Codeausschnitt mit:
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)
Sind diese die optimalen Indizes zu erstellen? Werden diese Indizes ermöglichen den schnellen Zugriff hin und her durch den Tisch kommen, sowie schnelle Lookups in der Tabelle selbst, oder gibt es eine andere Art und Weise besser? Neu zu formulieren anders dieses ein wenig, werden diese Indizes gegeben city
und user
sind Instanzvariablen der Klasse City und Benutzer erlauben city.users
, city.city_permissions
, user.cities
und user.city_permissions
allen gleichermaßen gut durchführen?
Lösung
Sieht gut aus für mich.
Das schließt sich gerade erzeugte sollte entweder der PK-IDs der Einheit Tabellen oder auf dem FK-IDs in der Join-Tabelle auf sein -., Die beide Indizes
Wahrscheinlich an der generierten SQL Active aussehen würde gut sein, und vergleichen Sie sie gegen die Indizes.
Abhängig davon, welche Datenbank Sie sind auf Sie dann, dass SQL über einen Plan ausführen könnte erklären (oder was auch immer Werkzeug vorhanden ist, ich denke, Oracle hier)
Ihr Code zu vereinfachen, können Sie mit Blick has_and_belongs_to_many
als auch. Das würde man loswerden der CityPermission Objekt erhalten lassen
Andere Tipps
Hier ist die SQL, die Activerecord für user.cities
erzeugt:
SELECT `cities`.* FROM `cities` INNER JOIN city_permissions ON (cities.id = city_permissions.city_id) WHERE (city_permissions.user_id = 1 )
EXPLAIN Ergebnisse unter:
+----+-------------+------------------+--------+---------------------------------------------------------------------+-----------------------------------+---------+-------------------------------------------------+------+-------------+
| 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 | |
+----+-------------+------------------+--------+---------------------------------------------------------------------+-----------------------------------+---------+-------------------------------------------------+------+-------------+
Und hier ist die SQL, die Activerecord für user.city_permissions
erzeugt:
SELECT * FROM `city_permissions` WHERE (`city_permissions`.user_id = 1)
Mit den EXPLAIN Ergebnisse für die Abfrage:
+----+-------------+------------------+------+-----------------------------------+-----------------------------------+---------+-------+------+-------------+
| 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 |
+----+-------------+------------------+------+-----------------------------------+-----------------------------------+---------+-------+------+-------------+
Sieht aus wie es in der Tat richtig funktioniert . Aus dem MySQL-Handbuch:
eq_ref
Eine Zeile aus dieser Tabelle für jede Kombination von Zeilen aus den vorherigen Tabellen lesen. Anders als das System und const Typen ist dies die bestmögliche Art verbinden. Es wird verwendet, wenn alle Teile eines Index durch die Verknüpfung verwendet werden und der Index ein Primärschlüssel oder eindeutiger Index.
ref
Alle Zeilen mit passenden Indexwerten werden aus dieser Tabelle für jede Kombination von Zeilen aus den vorherigen Tabellen lesen. ref verwendet wird, der nur einen linken Präfix des Schlüssels oder wenn der Schlüssel nicht ein PRIMARY KEY oder ein eindeutiger Index, wenn Join verwendet (in anderen Worten, wenn die Verbindung nicht eine einzige Zeile auf dem Grundlage des Schlüsselwert auswählen). Wenn der Schlüssel, der nur ein paar Zeilen Spiele verwendet wird, ist dies ein guter Typ verbinden.