Active Record verfügt über eine leistungsstarke Funktion, die als Zuordnungsfunktion bezeichnet wird. In diesem Artikel haben wir zusammengefasst, wie die Zuordnungscache-Steuerung verwendet wird, um unnötiges SQL zu unterdrücken.
Es wird im Rails-Handbuch wie folgt beschrieben. [Active Record Association-3.1-Cache-Steuerung](https://railsguides.jp/association_basics.html#%E3%82%AD%E3%83%A3%E3%83%83%E3%82%B7%E3% 83% A5% E5% 88% B6% E5% BE% A1)
Das Ergebnis der zuletzt ausgeführten Abfrage bleibt im Cache erhalten und kann in nachfolgenden Operationen verwendet werden.
Verschieben Sie es tatsächlich und prüfen Sie, ob es zwischengespeichert ist. Verwenden Sie das folgende Modell.
class User < ApplicationRecord
has_many :reviews
end
class Review < ApplicationRecord
belongs_to :user
end
Wenn Sie "user.reviews" wie unten gezeigt ausführen, wird SQL bei der zweiten Ausführung nicht ausgegeben. Dies liegt daran, dass ActiveRecord das Ergebnis der ersten Ausführung zwischenspeichert und zurückgibt.
irb(main):004:0> user = User.first
User Load (5.8ms) SELECT `users`.* FROM `users` ORDER BY `users`.`id` ASC LIMIT 1
=> #<User:0x000056307ae3aca0
irb(main):005:0> user.reviews
Review Load (2.7ms) SELECT `reviews`.* FROM `reviews` WHERE `reviews`.`user_id` = 1
=> [#<Review:0x000056307b1a77d0
irb(main):007:0> user.reviews
=> [#<Review:0x000056307b1a77d0
In diesem Beispiel sehen Sie, dass die Ausführung von SQL 2,7 ms dauert, um die Überprüfungen abzurufen. Da der Cache das zweite Mal verwendet wird, bedeutet dies, dass der gleiche Prozess 2,7 ms spart.
Es ist nicht sehr vorteilhaft, wenn nur ein SQL-Problem wie dieses Mal verkürzt wird. Wenn dies 100-mal und 1000-mal akkumuliert wird, beträgt der Unterschied einige Sekunden, und Sie können den Unterschied spüren.
Verwenden Sie dasselbe Modell wie im vorherigen Beispiel. Wenn Sie das Benutzerobjekt bereits abgerufen haben, wie erhalten Sie die Bewertungen, die der Benutzer hat?
#Benutzerobjekt erfasst
user
#Holen Sie sich die Bewertungen, die der Benutzer hat
# 1
reviews = Review.where(user_id: user.id)
# 2
reviews = Review.where(user: user)
# 3
reviews = user.reviews
Die SQL, die beim Abrufen von Überprüfungen ausgegeben wird, ist für 1-3 gleich, es gibt jedoch einen Unterschied. Der Unterschied besteht darin, ob die überprüfungsbezogenen Daten "Benutzer" zwischengespeichert werden. Holen Sie sich Bewertungen mit den oben genannten Methoden 1 bis 3 mit irb und überprüfen Sie, ob die zugehörigen Daten "Benutzer" der Bewertungen zwischengespeichert sind.
#1
irb(main):009:0> reviews = Review.where(user_id: user.id)
Review Load (1.2ms) SELECT `reviews`.* FROM `reviews` WHERE `reviews`.`user_id` = 1
=> [#<Review:0x000055fc149bca10
irb(main):010:0> reviews.first.user
User Load (0.7ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 1 LIMIT 1
=> #<User:0x000055fc14b75d20
#2
irb(main):011:0> reviews = Review.where(user: user)
Review Load (0.8ms) SELECT `reviews`.* FROM `reviews` WHERE `reviews`.`user_id` = 1
=> [#<Review:0x000055fc14b83ab0
irb(main):012:0> reviews.first.user
User Load (0.7ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 1 LIMIT 1
=> #<User:0x000055fc14fca880
#3
irb(main):015:0> reviews = user.reviews
Review Load (0.6ms) SELECT `reviews`.* FROM `reviews` WHERE `reviews`.`user_id` = 1
=> [#<Review:0x000055fc1504c0b0
irb(main):016:0> reviews.first.user
=> #<User:0x000055fc14873f78
Nur im Fall von 3 wird SQL nicht ausgegeben, um Benutzer beim Ausführen von "reviews.first.user" zu erhalten. Es scheint, dass die ursprünglichen verwandten Daten zwischengespeichert werden, wenn sie durch Zuordnung erfasst werden.
Bevor ich den Vorgang tatsächlich überprüfte, hatte ich erwartet, dass die zugehörigen Daten zwischengespeichert werden, da die Methode zum Übergeben des Objekts an die Stelle wie in 2 auch das Objekt übergibt, aber es wurde so implementiert. Es scheint nicht so zu sein.
Wenn Sie verwandte Daten abrufen, ist es besser, die Zuordnung zu verwenden, um den Cache abzurufen. Verwenden Sie sie also aktiv.
Verwenden Sie dasselbe Modell wie im vorherigen Beispiel. Wie erstellen Sie das Benutzerobjekt, wenn Sie es bereits abgerufen haben und diesem Benutzer eine Bewertung hinzufügen möchten?
#Benutzerobjekt erfasst
user
#Erstellen Sie eine neue Bewertung für den Benutzer
# 1
review = Review.create!(content: 'hogehoge', user_id: user.id)
# 2
review = Review.create!(content: 'hogehoge', user: user)
# 3
review = user.reviews.create!(content: 'hogehoge')
Das Einfügen von SQL ist für 1-3 identisch, es gibt jedoch einen Unterschied zwischen dem SQL vor der Erstellung und dem Cache-Status nach der Erstellung. Lassen Sie uns mit irb überprüfen.
#1
#Anzahl der Bewertungen vor der Erstellung
irb(main):051:0> user.reviews.size
=> 19
#Benutzer wurde vor der Erstellung ausgewählt!
irb(main):054:0> review = Review.create!(content: 'hogehoge', user_id: user.id)
(0.4ms) BEGIN
User Load (0.5ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 1 LIMIT 1
Review Create (0.7ms) INSERT INTO `reviews` (`content`, `user_id`, `created_at`, `updated_at`) VALUES ('hogehoge', 1, '2020-06-15 14:46:13.461715', '2020-06-15 14:46:13.461715')
(2.0ms) COMMIT
=> #<Review:0x000055fc16072188
id: 20,
#Der Benutzer wird in der zurückgegebenen Bewertung zwischengespeichert
#→ Wird der Benutzer zum Zeitpunkt der Erstellung für diesen Cache gewonnen?
irb(main):055:0> review.user
=> #<User:0x000055fc16076c60
#Ursprünglicher Benutzer.Die Anzahl der Überprüfungen wurde nicht erhöht, da sie mit dem Cache vor der Erstellung identisch sind
irb(main):056:0> user.reviews.size
=> 19
#Zum Aktualisieren ist ein erneutes Laden erforderlich
irb(main):057:0> user.reviews.reload.size
Review Load (0.9ms) SELECT `reviews`.* FROM `reviews` WHERE `reviews`.`user_id` = 1
=> 20
#2
#Anzahl der Bewertungen vor der Erstellung
irb(main):058:0> user.reviews.size
=> 20
#Keine Auswahl vor der Erstellung
irb(main):059:0> review = Review.create!(content: 'hogehoge', user: user)
(0.4ms) BEGIN
Review Create (0.6ms) INSERT INTO `reviews` (`content`, `user_id`, `created_at`, `updated_at`) VALUES ('hogehoge', 1, '2020-06-15 14:53:06.510290', '2020-06-15 14:53:06.510290')
(3.4ms) COMMIT
=> #<Review:0x000055fc16fa6690
id: 21,
#Der Benutzer wird in der zurückgegebenen Bewertung zwischengespeichert
#→ Es scheint, dass das zum Erstellen übergebene Benutzerobjekt zwischengespeichert ist
irb(main):060:0> review.user
=> #<User:0x000055fc16b28b40
id: 1,
#Ursprünglicher Benutzer.Die Anzahl der Überprüfungen wurde nicht erhöht, da sie mit dem Cache vor der Erstellung identisch sind
irb(main):061:0> user.reviews.size
=> 20
#Zum Aktualisieren ist ein erneutes Laden erforderlich
irb(main):062:0> user.reviews.reload.size
Review Load (0.8ms) SELECT `reviews`.* FROM `reviews` WHERE `reviews`.`user_id` = 1
=> 21
#3
#Anzahl der Bewertungen vor der Erstellung
irb(main):063:0> user.reviews.size
=> 21
#Keine Auswahl vor der Erstellung
irb(main):064:0> review = user.reviews.create!(content: 'hogehoge')
(0.6ms) BEGIN
Review Create (0.6ms) INSERT INTO `reviews` (`content`, `user_id`, `created_at`, `updated_at`) VALUES ('hogehoge', 1, '2020-06-15 14:55:45.393655', '2020-06-15 14:55:45.393655')
(1.8ms) COMMIT
=> #<Review:0x000055fc15fd6120
id: 22,
#Der Benutzer wird in der zurückgegebenen Bewertung zwischengespeichert
irb(main):065:0> review.user
=> #<User:0x000055fc16b28b40
id: 1,
# user.Auch zu Bewertungen hinzugefügt
irb(main):066:0> user.reviews.size
=> 22
In allen Mustern hat das von create zurückgegebene Überprüfungsobjekt das Benutzerobjekt zwischengespeichert. Im Fall von 1 wurde die select-Anweisung jedoch vor der Erstellung ausgegeben. Wenn Sie ein Zuordnungsobjekt haben, scheint es effizienter zu sein, das Objekt zu übergeben. Außerdem wird nur im Fall von 3 die erstellte Überprüfung zu "user.reviews" hinzugefügt.
Beim Aktualisieren verwandter Daten ist es besser, die Zuordnung zu verwenden, da diese zu den Originaldaten hinzugefügt wird und effizienter verarbeitet werden kann. Selbst wenn Sie die Zuordnung nicht verwenden, scheint es effizienter zu sein, die Zuordnung als Objekt wie in 2 zu übergeben, da die select-Anweisung nicht unnötig ausgegeben wird.
Ich dachte, ich wüsste etwas über den Cache, aber bis jetzt hatte ich das Verhalten, das select vor dem 1. und 2. Erstellen in [Zum Zeitpunkt der Erstellung] geschrieben hatte, nicht bemerkt ... Es scheint, dass es viele Dinge gibt, die Sie nicht bemerkt haben, wenn Sie es nicht bewusst versuchen.
Recommended Posts