[RUBY] Zeichnen Sie SQL in Ihren Kopf, wenn Sie ActiveRecord verwenden

Haben Sie SQL im Sinn, wenn Sie ActiveRecord verwenden?

ActiveRecord ist sehr praktisch und Sie können auf die Datenbank zugreifen, um Daten abzurufen und zu aktualisieren, ohne SQL zu kennen. Daher kann es geschrieben werden, ohne dass SQL zum Zeitpunkt der Implementierung bekannt ist.

Zum Zeitpunkt der Implementierung müssen Sie sich mit ActiveRecord nicht mit einfachem SQL vertraut machen. Wenn Sie es jedoch endgültig ausführen, wird SQL ausgeführt. Wenn Sie sich also das tatsächlich ausgegebene SQL ansehen, werden Sie möglicherweise überrascht sein, dass ein solches SQL ausgegeben wird.

Hier sind einige Implementierungsbeispiele, die vermieden werden können, wenn Sie schreiben, während Sie an SQL denken.

Treten Sie einem nutzlosen Tisch bei

Angenommen, Sie haben das folgende Modell.

def User < ApplicationRecord
  has_many :user_organizations
end

def UserOrganization < ApplicationRecord
  belongs_to :user
  belongs_to :organization
end

def Organization < ApplicationRecord
  has_many :user_organizations
end

"Lassen Sie das Benutzermodell durch organisation_id eingrenzen. Wie setzen Sie es um, wenn Sie informiert werden?

target_organization_id = 1
users = User.join(user_organizations: :organization)
  .where(user_organizations: { organization: { id: target_organization_id }})

Diese Implementierung funktioniert ordnungsgemäß wie angegeben. Die ausgegebene SQL ist wie folgt

SELECT `users`.*
FROM `users`
  INNER JOIN `user_organizations` ON `user_organizations`.`user_id` = `users`.`id`
  INNER JOIN `organizations` ON `organizations`.`id` = `user_organizations`.`organization_id`
WHERE `organization`.`id` = 1

Was halten Sie von diesem SQL? Wenn Sie darüber nachdenken, werden Sie feststellen, dass Sie sich nicht der Organisationstabelle anschließen müssen. Das verbesserte SQL ist wie folgt.

SELECT `users`.*
FROM `users`
  INNER JOIN `user_organizations` ON `user_organizations`.`user_id` = `users`.`id`
WHERE `user_organizations`.`organization_id` = 1

Der aktive Datensatz, der dies erkennt, lautet wie folgt.

target_organization_id = 1
users = User.join(:user_organizations)
  .where(user_organizations: { organization_id: target_organization_id })

In Anbetracht der Implementierung, die sich auf das ActiveRecord-Modell konzentriert, ist es einfach, auch das Modell mit der angegebenen ID wie bei der ersten Implementierung zu verbinden. Selbst wenn Sie tatsächlich eine Codeüberprüfung durchführen, werden Sie häufig solche Implementierungen sehen. Je kleiner der JOIN ist, desto besser ist die Leistung von SQL. Beachten Sie daher, dass Sie ActiveRecord mit möglichst wenigen JOINs implementieren sollten.

eifrig_load LINKS AUSSEN VERBINDEN

Wie zuvor: "Lassen Sie das Benutzermodell durch organisation_id eingrenzen. ] Wie implementieren Sie es außerdem, wenn Sie später "user.exam_organization" verwenden und zwischenspeichern möchten?

Bei der vorherigen Implementierung werden Exam_Organisationen nicht zwischengespeichert. Jedes Mal, wenn Sie Exam_Organisation erhalten, wird SQL ausgegeben, was zu N + 1 führt. Daher wird es zwischengespeichert, indem Verknüpfungen wie unten gezeigt in eifriges Laden (oder Einschließen) geändert werden.

target_organization_id = 1
users = User.eager_load(:user_organizations)
  .where(user_organizations: { organization_id: target_organization_id })

Es wird sicher zwischengespeichert, aber wenn Sie sich die ausgegebene SQL ansehen, werden Sie feststellen, dass INNER JOIN in LEFT OUTER JOIN geändert wurde.

SELECT `users`.id AS t0_r0, ...(Alle Spalten werden aufgelistet. Weggelassen, weil es lang ist)
FROM `users`
  LEFT OUTER JOIN `user_organizations` ON `user_organizations`.`user_id` = `users`.`id`
WHERE `user_organizations`.`organization_id` = 1

Wenn Sie Rails schreiben, ohne an SQL zu denken, ist es mir oft egal, ob INNER JOIN wie in diesem Beispiel LEFT OUTER JOIN ist. Wenn ich jedoch an SQL denke, kann ich LEFT OUTER JOIN nicht auswählen, obwohl es sich um eine Verknüpfung mit Daten handelt. Daher fühlt es sich seltsam an. In einem solchen Fall können Sie die Daten während des Beitritts mit INNER JOIN zwischenspeichern, indem Sie Verknüpfungen wie unten gezeigt hinzufügen.

target_organization_id = 1
users = User.eager_load(:user_organizations).joins(:user_organizations)
  .where(user_organizations: { organization_id: target_organization_id })

Schließlich

Ich habe einige Beispiele gegeben, aber beide sind leicht zu vermeiden, wenn Sie mit SQL schreiben. Selbst wenn Sie etwas ineffizientes tun, funktioniert es normalerweise einwandfrei und Sie bemerken es oft nicht. Da es jedoch einen Unterschied in der Leistung aufgrund des Stapelns gibt, war mir SQL bei der Verwendung von ActiveRecord bisher nicht bekannt. Ich denke, es ist gut für die Leute, sich der ausgegebenen SQL bewusst zu sein.

Recommended Posts

Zeichnen Sie SQL in Ihren Kopf, wenn Sie ActiveRecord verwenden
Dinge, die Sie bei der Verwendung der if-Anweisung beachten sollten
Unterschiede im Code bei Verwendung des Längensystems in Java