ActiveRecord: boyut ve sayı


202

Raylar, her iki kullanarak kayıt sayısını bulabilirsiniz Model.sizeve Model.count. Daha karmaşık sorgularla uğraşıyorsanız, bir yöntemi diğerine göre kullanmanın bir avantajı var mı? Nasıl farklılar?

Örneğin, fotoğraflı kullanıcılara sahibim. Bir kullanıcı tablosu ve kaç tane fotoğrafı olduğunu göstermek istersem, birçok örneği çalıştırmak user.photos.sizedaha hızlı mı yoksa daha yavaş user.photos.countmı olur ?

Teşekkürler!

Yanıtlar:


347

Sen okumalısınız o hâlâ geçerli olduğundan,.

Kullandığınız işlevi ihtiyaçlarınıza göre uyarlayacaksınız.

Temelde:

  • zaten tüm girişleri yüklerseniz, diyelim User.all, o zaman lengthbaşka bir db sorgusu önlemek için kullanmalısınız

  • Yüklü bir şey yoksa count, db'nizde bir sayım sorgusu yapmak için kullanın

  • Bu hususlar ile rahatsız etmek istemiyorsanız, kullanım sizeadapte olacaktır


35
Eğer sizeyine de duruma uyum sağlar, o zaman ne gerek için vardır lengthve counthiç?
sscirrus

27
@sscirus - Böylece size, aramayı yaptığınızda size(hangisini arayacağınızı belirledikten sonra) bunlara çağrı yapabilirsiniz .
Batkins

35
Bununla birlikte, yalnızca boyut varsayılanına dikkat edin. Örneğin, yani ilişki geçmeden yeni bir kayıt oluşturmak eğer Comment.create(post_id: post.id)senin, post.comments.sizeise irade, güncel olmayabilir post.comments.countirade. Bu yüzden dikkatli ol.
mrbrdo

14
Eğer bir ilişki aracılığıyla birkaç nesne inşa Ayrıca,: company.devices.build(:name => "device1"); company.devices.build(:name => "device2"), o zaman company.devices.sizeve .length, sen inşa ettik ama kaydetmediyseniz nesne sayısını içerecektir .countveritabanından sadece sayımını bildirir.
Shawn J. Goff

6
@sscirrus, otomatikleştirildiğinden boyut tehlikeli bir komuttur, bazen db'yi tekrar sorgulamak istersiniz.
Alex C

80

Diğer cevapların belirttiği gibi:

  • countSQL COUNTsorgusu gerçekleştirecek
  • length elde edilen dizinin uzunluğunu hesaplar
  • size aşırı sorguları önlemek için en uygun olanı seçmeye çalışacak

Ama bir şey daha var. Hep sizebirlikte count/ lengthtamamen farklı davrandığı bir durumu fark ettik ve göz ardı edilebilecek kadar nadir olduğu için paylaşacağımı düşündüm.

  • Eğer bir kullanırsanız :counter_cachebir üzerinde has_manydernek, sizedoğrudan saymak önbelleğe alınmış ve tüm ekstra bir sorgu yapmaz.

    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

Bu davranış Raylar Kılavuzlarında belgelenmiştir , ancak ya ilk kez kaçırdım ya da unuttum.


Aslında, 5.0.0.beta1 raylarından önce, bir _countsütun olsa bile ( counter_cache: truedernek üzerinde direktif olmadan) bu davranış tetiklenir . Bu, github.com/rails/rails/commit/e0cb21f5f7
cbliard

8

Bazen size"yanlış olanı alır" ve bir karma döndürür (bu ne countolurdu)

Bu durumda, karma yerine lengthbir tamsayı almak için kullanın .


Bir has_many örneğindeki bir Koleksiyonda '.size' kullandım ve koleksiyonda bir kayıt olmasına rağmen, boyut bir '0' döndürüyordu. .Count kullanıldığında doğru '1' değeri döndürülür.
admazzola

4

tl; Dr.

  • Eğer veri kullanımına ihtiyacınız olmayacağını biliyorsanız count.
  • Veri kullanımını kullanacağınızı veya kullandığınızı biliyorsanız length.
  • Ne yaptığınızı bilmiyorsanız, kullanın size...

Miktar

Select count(*)...DB'ye bir sorgu gönderme ile ilgilidir . Verilere ihtiyacınız yoksa sadece sayım için gidilecek yol.

Örnek: yeni mesaj sayısı, yalnızca bir sayfa görüntülenecek toplam öğe vb.

uzunluk

Gerekli verileri, yani sorguyu gerektiği gibi yükler ve sonra sayar. Verileri kullanıyorsanız gidilecek yol.

Örnek: Tam olarak yüklenmiş bir tablonun özeti, görüntülenen verilerin başlıkları, vb.

boyut

Verilerin yüklenmiş olup olmadığını (yani zaten raylarda) kontrol eder, sonra sayın, aksi takdirde sayı çağırır. (artı diğer kayıtlarda belirtilen tuzaklar).

def size
  loaded? ? @records.length : count(:all)
end

Sorun ne?

Doğru sırada yapmazsanız DB'ye iki kez vuruyor olabilirsiniz (örneğin, oluşturulan tablonun üstündeki bir tablodaki öğe sayısını oluşturursanız, DB'ye etkili bir şekilde 2 çağrı gönderilir).


3

Aşağıdaki stratejilerin tümü, bir COUNT(*)sorgu gerçekleştirmek için veritabanına çağrı yapar .

Model.count

Model.all.size

records = Model.all
records.count

Aşağıdakiler, veritabanındaki tüm kayıtları Ruby'ye yükleyeceği kadar verimli değildir, bu da koleksiyonun boyutunu sayar.

records = Model.all
records.size

Modellerinizde ilişkilendirmeler varsa ve ait olan nesnelerin sayısını (örn. @customer.orders.size) Bulmak istiyorsanız, veritabanı sorgularından (disk okumaları) kaçınabilirsiniz. Bir sayaç önbellek kullanın ve Rails önbellek değerini güncel tutacak ve sizeyönteme yanıt olarak bu değeri döndürecektir .


2
Her ikisi de Model.all.size ve Model.all.countbir oluşturmak countRaylar 4 ve üstü sorgu. Asıl avantajı size, ilişkilendirme zaten yüklüyse sayım sorgusu oluşturmamasıdır. Rails 3 ve önceki sürümlerde, Model.allbir ilişki olmadığını düşünüyorum , bu nedenle tüm kayıtlar zaten yüklü. Bu yanıt eski olabilir ve silmenizi öneririm.
Damon Aw

1

Boyut işlevini kullanmanızı tavsiye ettim.

class Customer < ActiveRecord::Base
  has_many :customer_activities
end

class CustomerActivity < ActiveRecord::Base
  belongs_to :customer, counter_cache: true
end

Bu iki modeli düşünün. Müşterinin birçok müşteri faaliyeti vardır.

Has_many ilişkilendirmesinde: counter_cache kullanırsanız, boyut doğrudan önbelleğe alınan sayımı kullanır ve fazladan bir sorgu oluşturmaz.

Bir örneği ele alalım: Veri tabanımda bir müşterinin 20.000 müşteri faaliyeti var ve bu müşterinin müşteri faaliyeti kayıtlarının sayısını her biri sayım, uzunluk ve boyut yöntemiyle saymaya çalışıyorum. burada tüm bu yöntemlerin karşılaştırmalı raporunun altında.

            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)

Bu yüzden kullanarak: counter_cache Boyutu kayıt sayısını hesaplamak için en iyi seçenek olduğunu.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.