Ich kannte das "N + 1-Problem" bis jetzt, aber ich hatte noch nie eine so groß angelegte Entwicklung durchgeführt, also habe ich meine Zeit verbracht, ohne mir dessen bewusst zu sein. .. Als ich jedoch tatsächlich vor Ort arbeitete, stellte ich fest, dass es in der groß angelegten Entwicklung Zehntausende von Daten in Zara gibt, daher muss ich mich von nun an dessen bewusst sein (weinen). Ich denke, dass jeder Wissen braucht, das fast immer notwendig ist, wenn er die Site tatsächlich betritt. Bitte halten Sie es hier gedrückt! !!
Einfach ausgedrückt ist es ein Problem, dass SQL jedes Mal während der Schleifenverarbeitung ausgegeben wird und eine große Menge (mehr als erforderlich) von SQL ausgegeben wird, was zu einer schlechten Leistung führt. Lassen Sie mich Ihnen eine Analogie geben. Wenn Sie 10 Produkte des Benutzers mit dem Namen Mr. A erhalten und die Produktlistenseite von Mr. A anzeigen möchten,
Einmal, um die Benutzerdaten von Herrn A zu erhalten 10 Mal, um 10 Produktdaten zu erhalten Sie geben insgesamt 11 Abfragen aus, um die Daten abzurufen, die Sie anzeigen möchten.
Es ist keine große Sache mit ungefähr 11 Fällen, aber es ist schwierig, wenn dies 10.000 oder 20.000 sind. Angenommen, eine Abfrage dauert 0,001 Sekunden, dauert die Beantwortung von 10000 oder 20000 Abfragen 10 oder 20 Sekunden. Es ist mühsam, so weit zu warten, oder? Dieses Problem kann je nach Schreibweise des Codes gelöst werden. Wenn Sie es richtig schreiben, können Sie es mit zwei Abfragen erhalten, selbst wenn Sie 10.000 Produkte haben (lacht)
Nun wollen wir sehen, wie dieses Problem gelöst werden kann. Grundsätzlich können Sie die vier unten vorgestellten Methoden verwenden. Die Verwendung ist etwas anders, also machen wir es möglich, sie richtig zu verwenden.
Methode | Zwischenspeicher | Abfrage | Verwenden | Datenreferenz |
---|---|---|---|---|
joins | TU es nicht | INNER JOIN | Eingrenzen | es kann |
eager_load | Machen | LEFT JOIN | Bargeld und Raffinesse | es kann |
preload | Machen | WÄHLEN Sie jeweils ohne JOIN | Zwischenspeicher | Kann nicht |
includes | Machen | Je nach Fall | Bargeld, bei Bedarf eingrenzen | es kann |
joins INNER JOIN wird standardmäßig ausgeführt. Verwenden Sie left_joins, wenn Sie LEFT OUTER JOIN ausführen möchten. Diese Methode wird nicht zwischengespeichert, sodass der Speicher auf ein Minimum beschränkt werden kann. Sie können es auch verwenden, wenn Sie nur das Eingrenzungsergebnis benötigen, ohne auf die Daten des JOIN-Ziels zu verweisen.
User.joins(:products).where(products: { id: 1 })
# SELECT `users`.* FROM `users` INNER JOIN `products` ON `products`.`user_id` = `users`.`id` WHERE `products`.`id` = 1
eager_load Zeichnen Sie die angegebene Zuordnung mit LEFT OUTER JOIN und zwischenspeichern Sie sie. Eine schnelle Verarbeitung ist möglich, da nur eine Abfrage erforderlich ist. Sie können es verwenden, wenn Sie einer 1-zu-1- oder N-zu-1-Zuordnung beitreten möchten (Gehört zu, hat_one) oder wenn Sie auf die Informationen der Tabelle verweisen möchten, zu der Sie beigetreten sind (z. B. Eingrenzen nach Wo).
User.eager_load(:products)
# SELECT `users`.`id`, `users`.`name`, `users`.`created_at`, `users`.`updated_at`, `products`.`id`, `products`.`user_id`, `products`.`created_at`, `products`.`updated_at` FROM `users` LEFT OUTER JOIN `products` ON `products`.`user_id` = `users`.`id`
preload Die angegebene Zuordnung wird in mehrere Abfragen unterteilt und zum Zwischenspeichern abgezogen. Es ist jedoch nicht möglich, auf die Daten des Zuordnungsziels zu verweisen (z. B. Eingrenzen nach Wo). Verwenden Sie es für viele-zu-viele Assoziationen. Als Einschränkung: Wenn die Datenmenge groß ist, ist die IN-Klausel tendenziell groß, was Druck auf den Speicher ausüben kann.
User.preload(:products)
# SELECT `users`.* FROM `users`
# SELECT `products`.* FROM `products` WHERE `products`.`user_id` IN (1, 2, 3, ...)
includes Einfach ausgedrückt, es verwendet eifrig_load und Preload richtig. Es scheint jedoch besser, keine Includes zu verwenden. Weil enthält Sortierungen Preload und eifrige_load schön. Wenn Sie die Eigenschaften von Preload und Zeal_load verstehen, werden Sie selten Includes sehen. Es ist möglicherweise kein Problem, wenn Sie es einschließen, solange nur wenige Daten vorhanden sind. Mit zunehmender Datenmenge treten jedoch Falten und Probleme auf. Stellen Sie daher sicher, dass Sie das Verhalten von Includes korrekt kennen.
User.includes(:products)
# SELECT `users`.* FROM `users`
# SELECT `products`.* FROM `products` WHERE `products`.`user_id` IN (1, 2, 3, ...)
Egal wie vorsichtig Sie sind, die Menschen werden herauskommen. Bullet ist ein Juwel, das das abdeckt.
group :optimization do
gem 'bullet', '~> 6.1.0'
end
config/enviroments/optomization.rb
config.after_initialize do
#Ermöglicht die Optimierung.
Bullet.enable = true
#Es ist zulässig, das Problem mit JS Alert anzuzeigen.
Bullet.alert = true
#Ermöglicht die Protokollierung in einer Datei.
Bullet.bullet_logger = true
#N in der Browserkonsole+1 Ermöglicht das Anzeigen des Problems.
Bullet.console = true
#Ermöglicht Bullet, sich bei Rails anzumelden.
Bullet.rails_logger = true
#Ermöglicht die Anzeige des Problems in der Fußzeile.
Bullet.add_footer = true
end
webpacker.yml
optimization:
<<: *development
$ bundle exec rails server -e optimization
config/enviroments/test.rb
config.after_initialize do
Bullet.enable = true
Bullet.bullet_logger = true
Bullet.raise = false
end
spec/spec_helper.rb
if Bullet.enable?
config.before(:each) do
Bullet.start_request
end
config.after(:each) do
Bullet.perform_out_of_channel_notifications if Bullet.notification?
Bullet.end_request
end
end
Bisher haben wir gesehen, wie wir mit dem N + 1-Problem umgehen können. Ich denke, dass die Reaktion viel schneller sein wird, wenn man nur ein wenig das Bewusstsein ändert! Lassen Sie uns nun bewusst aus dieser Zeit entwickeln! !! !!
[Entdecken Sie N + 1-Abfrageprobleme, die im Ruby on Rails-Code mit Bullet gem verborgen sind, und optimieren Sie die Reaktion der Rails-Site](https://www.123ish.com/jp/entries/2236-ruby-on- Schienen% E3% 81% AE% E3% 82% B3% E3% 83% BC% E3% 83% 89% E3% 81% AB% E6% BD% 9C% E3% 82% 80n-1% E3% 82% AF% E3% 82% A8% E3% 83% AA% E5% 95% 8F% E9% A1% 8C% E3% 82% 92 Bullet-Gem-% E3% 81% A7% E7% 99% BA% E8% A6 % 8B% E3% 81% 97% E3% 81% A6% E3% 80% 81rail% E3% 82% B5% E3% 82% A4% E3% 83% 88% E3% 81% AE% E3% 83% AC % E3% 82% B9% E3% 83% 9D% E3% 83% B3% E3% 82% B9% E3% 82% 92% E6% 9C% 80% E9% 81% A9% E5% 8C% 96)
Bullet in Testumgebung ausführen
Grund für die ordnungsgemäße Verwendung von Preload und Zeal_load ohne Verwendung von ActiveRecord:
Der persönliche Gebrauch von ActiveRecord umfasst Preload, eifriges Laden
Unterschiede zwischen ActiveRecord-Joins, Preloads, Includes und eifrigem Laden
Recommended Posts