web-dev-qa-db-fra.com

ActiveRecord: taille vs nombre

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!

189
Andrew

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

326
apneadiving

Comme l'indiquent les autres réponses:

  • count effectuera une requête SQL COUNT
  • length calculera la longueur du tableau résultant
  • size essaiera de choisir le plus approprié des deux pour éviter les requêtes excessives

Mais il y a encore une chose. Nous avons remarqué un cas où size agit différemment de count/lengthautrui, 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é.

79
lime

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.

7
jvalanen

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.

3
Dennis

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.

1
manthan andharia

tl; dr

  • Si vous savez que vous n’avez pas besoin des données, utilisez count.
  • Si vous savez que vous allez utiliser ou avez utilisé les données, utilisez length.
  • Si vous ne savez pas ce que vous faites, utilisez size...

compter

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.

longueur

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.

taille

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).

0
estani