2 votes

Rails: Comment minimiser les appels à la base de données ici? Le chargement anticipé n'est pas applicable

Cette question est peut-être un peu spécifique, mais je pense qu'elle est également intéressante d'un point de vue général.

Dans une application Rails, les utilisateurs peuvent s'abonner à d'autres utilisateurs. Lorsque je montre une liste d'utilisateurs, je dois vérifier si l'utilisateur actuel s'est abonné aux utilisateurs de la liste. S'il s'est abonné, je montre le bouton de désabonnement et inversement.

Parce que tout dépend de l'utilisateur actuel, je ne peux pas utiliser le chargement anticipé. Donc quand je montre 20 utilisateurs dans la liste, je génère 20 requêtes supplémentaires à la base de données, ce qui me semble être une mauvaise pratique.

Je réfléchis à une bonne façon de résoudre ce problème. La meilleure solution à laquelle j'ai pensé jusqu'à présent est de charger les identifiants des utilisateurs auxquels le current_user s'est abonné dans la session lors de la connexion une fois et ensuite simplement vérifier chaque user.id par rapport aux identifiants dans la session. Mais cela pourrait peut-être entraîner d'autres problèmes lorsque l'utilisateur s'est abonné à beaucoup de personnes. De plus, je ne suis pas sûr que ce soit la meilleure façon de charger toutes les abonnements même si l'utilisateur ne regarde peut-être jamais la liste des utilisateurs pendant cette session.

La deuxième meilleure solution qui m'est venue à l'esprit serait de faire la même chose, mais pas lors de la connexion mais plutôt lorsque la liste d'utilisateurs est chargée.

Qu'en penses-tu?

4voto

Simone Carletti Points 77653

Vous devriez certainement commencer à travailler sur un système de cache. Il y a au moins 3 façons que vous pouvez suivre. Vous pouvez également les combiner pour plus d'efficacité.

Mise en cache de la base de données

Créez une table de relation pour contenir les relations ID entre l'utilisateur et les abonnés afin de ne pas avoir à les calculer à la volée.

Mise en cache du modèle

Les requêtes coûteuses peuvent être mises en cache.

def find_subscribers
  Rails.cache.fetch("find_subscribers_#{current_user}") do
    # run the query
  end

Mise en cache de la vue

Vous pouvez également mettre en cache des fragments de vue pour éviter des élaborations coûteuses.

Vous voudrez peut-être commencer par :

EDIT:

Votre requête peut être optimisée.

ActiveRecord::Base.connection.execute("SELECT count(*) as c FROM subscribers_users WHERE user_id = #{other_user.id} AND subscriber_id = #{self.id}") 

peut devenir

counters = SubscribersUser.count(:conditions => { :subscriber_id => self.id }, :group => "user_id")

La requête renverra un Hash où la clé est user_id et la valeur le résultat du comptage. Ensuite, vous pouvez itérer sur le hash au lieu d'exécuter une requête pour chaque enregistrement dans la vue.

2voto

crankharder Points 846

Il n'y a pas de règle contre le rechargement de l'utilisateur actuel s'il vous permet d'utiliser le chargement eager :

utilisateur = User.find(current_user.id, :include => :subscribers)

Sous réserve qu'il s'agisse d'une relation has_many simple, ce ne sont que 2 instructions SQL.

Maintenant, vous pouvez itérer sur les abonnés de l'utilisateur sans effectuer une autre requête en base de données.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X