Wussten Sie, dass die SELECT-Anweisung ausgeführt wird, wenn Sie ein Modell mit Gehäusen erstellen, das in Rails definiert ist?
Angenommen, Sie haben das folgende Modell.
def User < ApplicationRecord
has_many :reviews
end
def Review < ApplicationRecord
belongs_to :user
belongs_to :book
end
def Book < ApplicationRecord
has_many :reviews
end
Wenn Sie zu diesem Zeitpunkt eine Überprüfung erstellen, wird SQL wie unten gezeigt ausgegeben.
# id=1 Benutzer und Buch existieren
irb(main):001:0> Review.create!(user_id: 1, book_id: 1)
(0.5ms) BEGIN
User Load (0.5ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 1 LIMIT 1
Book Load (0.5ms) SELECT `books`.* FROM `books` WHERE `books`.`id` = 1 LIMIT 1
Review Create (0.6ms) INSERT INTO `reviews` (`user_id`, `book_id`, `created_at`, `updated_at`) VALUES (1, 1, '2020-06-30 14:31:27.343637', '2020-06-30 14:31:27.343637')
(2.0ms) COMMIT
Es wird für Benutzer und Bücher AUSGEWÄHLT, in denen Gehör_zu definiert ist.
Der Grund für die Auswahl ist einfach. Gehört zu, erfordert standardmäßig das Vorhandensein verwandter Modelle. Was ist also mit den erforderlichen Bestätigungen? Kurz bevor es wie zuvor erstellt wird, wird es AUSGEWÄHLT und auf Existenz überprüft.
Übrigens, wenn die Existenz des verwandten Modells willkürlich ist, schreiben Sie "Gehört zu: Benutzer, optional: Wahr". Wenn Sie es so schreiben, wird SELECT nicht ausgeführt. Siehe auch Rails Guide https://railsguides.jp/association_basics.html#optional
Um das SELECT im Titel zu vermeiden, setzen Sie "optional: true"! ... nicht! !!
Sicher, SELECT wird nicht mehr ausgegeben, aber die Einstellung "optional: true" ist nicht geeignet, wenn das zugehörige Modell erforderlich ist.
Wie vermeidet man SELECT, ohne "optional: true" zu setzen? Sie müssen lediglich das zu erstellende Objekt übergeben.
irb(main):002:0> user = User.first
User Load (0.8ms) SELECT `users`.* FROM `users` ORDER BY `users`.`id` ASC LIMIT 1
=> #<User id: 1, name: "1234567890", created_at: "2019-12-12 05:43:52", updated_at: "2019-12-12 05:43:52">
irb(main):003:0> book = Book.first
Book Load (0.6ms) SELECT `books`.* FROM `books` ORDER BY `books`.`id` ASC LIMIT 1
=> #<Book id: 1, title: "book1", created_at: "2020-06-15 14:21:15", updated_at: "2020-06-15 14:21:15">
irb(main):004:0> review = Review.create!(user: user, book: book)
(0.4ms) BEGIN
Review Create (0.6ms) INSERT INTO `reviews` (`user_id`, `book_id`, `created_at`, `updated_at`) VALUES (1, 1, '2020-06-30 14:32:14.911478', '2020-06-30 14:32:14.911478')
(2.0ms) COMMIT
Durch Übergeben des Objekts kann die Existenz bestätigt werden, ohne SELECT auszuführen, sodass die SELECT-Anweisung nicht ausgegeben wird. In diesem Beispiel ist die Anzahl der SQLs jedoch gleich, da jedes Modell kurz zuvor separat ausgewählt wird !! Die Anzahl der SQLs ist jedoch völlig unterschiedlich, z. B. wenn mehrere Überprüfungen für denselben Benutzer erstellt werden.
Unten finden Sie den Code zum Erstellen einer Überprüfung der Bücher 1-5 für Benutzer1 (teilweise weggelassen, um die Lesbarkeit zu verbessern). Die erste besteht darin, die ID anzugeben und zu erstellen.
irb(main):039:0> user = User.first
irb(main):040:0> books = Book.where(id: [1, 2, 3, 4, 5])
irb(main):042:0> books.each do |book|
irb(main):043:1* Review.create!(user_id: user.id, book_id: book.id)
irb(main):044:1> end
Book Load (0.8ms) SELECT `books`.* FROM `books` WHERE `books`.`id` IN (1, 2, 3, 4, 5)
(0.3ms) BEGIN
User Load (0.5ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 1 LIMIT 1
Book Load (0.4ms) SELECT `books`.* FROM `books` WHERE `books`.`id` = 1 LIMIT 1
Review Create (0.8ms) INSERT INTO `reviews` (`user_id`, `book_id`, `created_at`, `updated_at`) VALUES (1, 1, '2020-06-30 15:10:00.009569', '2020-06-30 15:10:00.009569')
(3.6ms) COMMIT
(0.3ms) BEGIN
User Load (0.4ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 1 LIMIT 1
Book Load (0.4ms) SELECT `books`.* FROM `books` WHERE `books`.`id` = 2 LIMIT 1
Review Create (0.4ms) INSERT INTO `reviews` (`user_id`, `book_id`, `created_at`, `updated_at`) VALUES (1, 2, '2020-06-30 15:10:00.020722', '2020-06-30 15:10:00.020722')
(1.8ms) COMMIT
(0.4ms) BEGIN
User Load (0.6ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 1 LIMIT 1
Book Load (0.4ms) SELECT `books`.* FROM `books` WHERE `books`.`id` = 3 LIMIT 1
Review Create (0.4ms) INSERT INTO `reviews` (`user_id`, `book_id`, `created_at`, `updated_at`) VALUES (1, 3, '2020-06-30 15:10:00.029827', '2020-06-30 15:10:00.029827')
(1.9ms) COMMIT
(0.3ms) BEGIN
User Load (0.4ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 1 LIMIT 1
Book Load (0.3ms) SELECT `books`.* FROM `books` WHERE `books`.`id` = 4 LIMIT 1
Review Create (0.3ms) INSERT INTO `reviews` (`user_id`, `book_id`, `created_at`, `updated_at`) VALUES (1, 4, '2020-06-30 15:10:00.037725', '2020-06-30 15:10:00.037725')
(1.7ms) COMMIT
(0.3ms) BEGIN
User Load (0.5ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 1 LIMIT 1
Book Load (0.3ms) SELECT `books`.* FROM `books` WHERE `books`.`id` = 5 LIMIT 1
Review Create (0.4ms) INSERT INTO `reviews` (`user_id`, `book_id`, `created_at`, `updated_at`) VALUES (1, 5, '2020-06-30 15:10:00.045389', '2020-06-30 15:10:00.045389')
(1.6ms) COMMIT
Übergeben Sie dann das Objekt und erstellen Sie es.
irb(main):045:0> user = User.first
irb(main):046:0> books = Book.where(id: [1, 2, 3, 4, 5])
irb(main):047:0> books.each do |book|
irb(main):048:1* Review.create!(user: user, book: book)
irb(main):049:1> end
Book Load (0.8ms) SELECT `books`.* FROM `books` WHERE `books`.`id` IN (1, 2, 3, 4, 5)
(0.5ms) BEGIN
Review Create (0.5ms) INSERT INTO `reviews` (`user_id`, `book_id`, `created_at`, `updated_at`) VALUES (1, 1, '2020-06-30 15:12:05.610003', '2020-06-30 15:12:05.610003')
(2.8ms) COMMIT
(0.4ms) BEGIN
Review Create (0.4ms) INSERT INTO `reviews` (`user_id`, `book_id`, `created_at`, `updated_at`) VALUES (1, 2, '2020-06-30 15:12:05.617125', '2020-06-30 15:12:05.617125')
(1.7ms) COMMIT
(0.3ms) BEGIN
Review Create (0.5ms) INSERT INTO `reviews` (`user_id`, `book_id`, `created_at`, `updated_at`) VALUES (1, 3, '2020-06-30 15:12:05.622432', '2020-06-30 15:12:05.622432')
(1.8ms) COMMIT
(0.4ms) BEGIN
Review Create (0.5ms) INSERT INTO `reviews` (`user_id`, `book_id`, `created_at`, `updated_at`) VALUES (1, 4, '2020-06-30 15:12:05.627957', '2020-06-30 15:12:05.627957')
(2.0ms) COMMIT
(0.4ms) BEGIN
Review Create (0.6ms) INSERT INTO `reviews` (`user_id`, `book_id`, `created_at`, `updated_at`) VALUES (1, 5, '2020-06-30 15:12:05.634191', '2020-06-30 15:12:05.634191')
(1.8ms) COMMIT
Bei der zweiten Implementierung können 10 SELECTs weggelassen werden !! Beachten Sie, dass sich die ausgegebene SQL ändert, je nachdem, ob Sie dies wissen!
Wie oben erwähnt, wird die Existenz von Gehorsam_to beim Erstellen überprüft, aber es scheint, dass das von create übergebene Modell und das Ergebnis von SELECT kurz zuvor nicht nur für die Existenzprüfung verwendet, sondern auch ordnungsgemäß in der Zuordnung festgelegt werden.
SQL wird auch dann nicht ausgegeben, wenn Sie sich auf die Zuordnung des durch create erstellten Modells beziehen.
irb(main):051:0> review = Review.create!(user: user, book: book)
(2.3ms) BEGIN
Review Create (0.6ms) INSERT INTO `reviews` (`user_id`, `book_id`, `created_at`, `updated_at`) VALUES (1, 1, '2020-06-30 15:20:01.755647', '2020-06-30 15:20:01.755647')
(2.5ms) COMMIT
=> #<Review id: 36, content: "", user_id: 1, book_id: 1, status: "draft", created_at: "2020-06-30 15:20:01", updated_at: "2020-06-30 15:20:01">
#Da das zum Zeitpunkt der Erstellung übergebene Modell festgelegt ist, wird SELECT auch dann nicht ausgeführt, wenn auf die Zuordnung verwiesen wird.
irb(main):052:0> review.user
=> #<User id: 1, name: "1234567890", created_at: "2019-12-12 05:43:52", updated_at: "2019-12-12 05:43:52">
irb(main):053:0> review.book
=> #<Book id: 1, title: "book1", created_at: "2020-06-15 14:21:15", updated_at: "2020-06-15 14:21:15">
Recommended Posts