Cet article présente une petite astuce pour éviter les requêtes N+1 dues à l'utilisation de .count() dans ActiveRecord.

Commentaires

De façon générale, ActiveRecord est magique mais ce n'est il est toujours intéressant, en fin de dev. de regarder en détail le SQL exact généré et envoyé à la DB (pas seulement sur ce point).

En tweakant un peu, il y a des gains de performance très substanciels à faire (parfois du x100). C'est une chose à laquelle on ne s'attache pas forcément au début du cycle de vie de l'appli (deadlines + tables vides), mais j'ai un portail de données avec plus de 4 millions de records sous le coude, et là ça devient vraiment nécessaire !

Il y a presque 5 ans

Effectivement, après on trouve un certain nombre de gems qui aident dans ce process.

On trouve par exemple bullet pour les N+1 https://github.com/flyerhzm/bullet

Il y a également scrooge mais on dirait que ça n'a pas été mis à jour de puis un moment https://github.com/methodmissing/scrooge

Il y a presque 5 ans

Plutôt que de compter la taille d'un tableau, j'utiliserai plutôt un counter_cache sur article (http://guides.rubyonrails.org/association_basics.html#belongs_to-association-reference 4.1.2.4 :counter_cache ) ou alors un COUNT sur la jointure :

Article.joins(:comments).select('COUNT(DISTINCT comments.id) AS mon_super_count_de_comments').all.each {|a| puts a.mon_super_count_de_comments}

L'approche envisagée dans l'article n'est valide que si on a besoin d'instancier les commentaires pour en faire autre chose que le count et qu'on ne veut pas mettre en place de counter_cache. Ca me semble être une exception plutôt que la règle comme le laisse penser l'article.

Il y a presque 5 ans

Héhé le count réserve des surprises !

Autre petit point que je rencontre (mongoid) c'est quand je fais @articles = Article.all dans le contrôleur puis @articles.count (ça lance une requête de comptage) puis @articles.each {} (ça lance une requête pour récupérer les articles). Ce sont les joies du "late eval" de l'ORM. Du coup je force l'exécution de la requête en faisant @articles = Article.all.entries et le count se fera sur le tableau. Il y a bien des cas où c'est parfait.

Il y a presque 5 ans
Vous devez vous inscrire ou vous connecter pour poster un commentaire