Voici un défi auquel je suis confronté, en utilisant Rails 5 (J'utilise le service Skylight qui rapporte N + 1 requêtes, et leur solution recommandée est here, mais ce n'est pas assez dans mon cas).Rails: Optimiser la requête N + 1 avec la même table one_to_many et les conditions de portée
J'ai une table nodes
et un seul Node
peut avoir plusieurs nodes
qui s'y rapporte (il y a une colonne appelée parent_node_id
) qui me donne la possibilité de relier un à plusieurs.
class Node < ApplicationRecord
...
belongs_to :parent_node, foreign_key: :parent_node_id, class_name: 'Node', optional: true, inverse_of: :nodes
has_many :nodes, foreign_key: :parent_node_id, class_name: 'Node'
...
end
Important Le niveau de la hiérarchie est maximale 1. Cela signifie qu'un node.nodes.first.node
ne se produit pas. Un node
qui a un parent_node
n'a plus de nodes
.
Le problème est que je suis confronté à des problèmes de performance avec N + 1 car il ne suffit pas d'inclure le nodes
dans la requête d'origine, car dans la boucle j'interroge chaque enregistrement avec une portée différente. Voici un exemple de code qui expose le problème:
# In a controller, including nodes so it does not query inside
nds = Node.some_scope.include(:nodes)
nds.each do |nd|
...
# In a model
# If I loop inside, there's no extra SQL queries, all good
nd.nodes.each do |nd2|
...
end
...
# In a model
# Here's the N+1 issue
nd.nodes.another_scope.each do |nd3|
...
end
# Returns a value to the controller
...
end
qui déclenche de toute façon les requêtes SQL pour chaque variable nd3
car il y a another_scope
qui modifie les valeurs nds
d'origine, et je ne peux pas comprendre la condition dans les nds
valeurs parce que la nodes
qui ne répondent pas aux critères another_scope
sont requis pour nd2
.
Existe-t-il un moyen d'optimiser cela?
vous pouvez ajouter une autre association 'has_many: what_nodes, -> {les conditions d'un autre scope écrites ici}, foreign_key:: parent_node_id, class_name: 'Node'' maintenant vous pouvez le faire 'nds = Node.some_scope.include (: nodes,: whatever_nodes)'. –
Je pense que @DennisKrupelnik a suggéré une réponse appropriée. Juste pour clarifier, vous devriez utiliser la méthode '# includes 'au lieu de' # include' pour le traitement par lots de requêtes –
@helperhelperov Oui, il l'a fait. Je signale simplement que cela peut être amélioré. Merci. – unmultimedio