Dans Rails, vous pouvez trouver le nombre d'enregistrements en utilisant à la fois Model.size
et Model.count
. Si vous traitez des requêtes plus complexes, l'utilisation d'une méthode par rapport à une autre présente-t-elle un avantage? Comment sont-ils différents?
Par exemple, j'ai des utilisateurs avec des photos. Si je souhaite afficher un tableau d'utilisateurs et le nombre de photos qu'ils contiennent, l'exécution de nombreuses instances de user.photos.size
sera plus rapide ou plus lente que user.photos.count
?
Merci!
Vous devriez lire ça , c'est toujours valide.
Vous allez adapter la fonction que vous utilisez en fonction de vos besoins.
Fondamentalement:
si vous chargez déjà toutes les entrées, dites User.all
, vous devriez alors utiliser length
pour éviter une autre requête de base de données.
si vous n'avez rien chargé, utilisez count
pour effectuer une requête de comptage sur votre base de données
si vous ne voulez pas vous soucier de ces considérations, utilisez size
qui s'adaptera
Comme l'indiquent les autres réponses:
count
effectuera une requête SQL COUNT
length
calculera la longueur du tableau résultantsize
essaiera de choisir le plus approprié des deux pour éviter les requêtes excessivesMais il y a encore une chose. Nous avons remarqué un cas où size
agit différemment de count
/length
autrui, et j'ai pensé le partager car il est assez rare pour être négligé.
Si vous utilisez un :counter_cache
sur une association has_many
, size
utilisera directement le nombre mis en cache et ne fera aucune requête supplémentaire.
class Image < ActiveRecord::Base
belongs_to :product, counter_cache: true
end
class Product < ActiveRecord::Base
has_many :images
end
> product = Product.first # query, load product into memory
> product.images.size # no query, reads the :images_count column
> product.images.count # query, SQL COUNT
> product.images.length # query, loads images into memory
Ce comportement est documenté dans les Rails Guides , mais je l’ai manqué la première fois ou je l’ai oublié.
Parfois, size
"choisit le mauvais" et retourne un hash (ce que count
ferait)
Dans ce cas, utilisez length
pour obtenir un entier au lieu de dièse.
Les stratégies suivantes font toutes appel à la base de données pour effectuer une requête COUNT(*)
.
Model.count
Model.all.size
records = Model.all
records.count
Les éléments suivants ne sont pas aussi efficaces car ils chargeront tous les enregistrements de la base de données dans Ruby, qui compte alors la taille de la collection.
records = Model.all
records.size
Si vos modèles ont des associations et que vous souhaitez rechercher le nombre d'objets d'appartenance (par exemple, @customer.orders.size
), vous pouvez éviter les requêtes sur la base de données (lectures sur disque). Utilisez un compteur cache et Rails maintiendra la valeur du cache à jour et renverra cette valeur en réponse à la méthode size
.
J'ai recommandé d'utiliser la fonction de taille.
class Customer < ActiveRecord::Base
has_many :customer_activities
end
class CustomerActivity < ActiveRecord::Base
belongs_to :customer, counter_cache: true
end
Considérons ces deux modèles. Le client a de nombreuses activités client.
Si vous utilisez a: counter_cache sur une association has_many, size utilisera directement le nombre mis en cache, sans aucune requête supplémentaire.
Prenons un exemple: dans ma base de données, un client a 20 000 activités client et j’essaie de compter le nombre d’enregistrements d’activités client de ce client avec chacune des méthodes nombre, longueur et taille. ci-dessous le rapport de référence de toutes ces méthodes.
user system total real
Count: 0.000000 0.000000 0.000000 ( 0.006105)
Size: 0.010000 0.000000 0.010000 ( 0.003797)
Length: 0.030000 0.000000 0.030000 ( 0.026481)
j'ai donc trouvé que: counter_cache Size était la meilleure option pour calculer le nombre d'enregistrements.
count
.length
.size
...Résout l'envoi d'une requête Select count(*)...
à la base de données. Le chemin à parcourir si vous n'avez pas besoin des données, mais juste du compte.
Exemple: nombre de nouveaux messages, nombre total d'éléments quand seule une page va être affichée, etc.
Charge les données requises, c’est-à-dire la requête, puis les compte. La voie à suivre si vous utilisez les données.
Exemple: résumé d'un tableau entièrement chargé, des titres des données affichées, etc.
Il vérifie si les données ont été chargées (c'est-à-dire déjà dans Rails) si c'est le cas, puis il suffit de les compter, sinon les appels sont pris en compte. (plus les pièges déjà mentionnés dans d'autres entrées).
def size
loaded? ? @records.length : count(:all)
end
Quel est le problème?
Si vous ne frappez pas la base de données deux fois si vous ne le faites pas dans le bon ordre (par exemple, si vous restituez le nombre d'éléments d'une table au-dessus de la table rendue, 2 appels seront envoyés à la base de données).