ActiveRecord: ukuran vs jumlah


201

Di Rails, Anda dapat menemukan jumlah catatan menggunakan keduanya Model.sizedan Model.count. Jika Anda berurusan dengan pertanyaan yang lebih kompleks, adakah keuntungan menggunakan satu metode di atas yang lain? Bagaimana mereka berbeda?

Misalnya, saya punya pengguna dengan foto. Jika saya ingin menunjukkan tabel pengguna dan berapa banyak foto yang mereka miliki, apakah menjalankan banyak contoh user.photos.sizelebih cepat atau lebih lambat daripada user.photos.count?

Terima kasih!

Jawaban:


344

Anda harus membaca bahwa , itu masih berlaku.

Anda akan menyesuaikan fungsi yang Anda gunakan tergantung pada kebutuhan Anda.

Pada dasarnya:

  • jika Anda sudah memuat semua entri, katakanlah User.all, maka Anda harus menggunakan lengthuntuk menghindari permintaan db lain

  • jika Anda belum memuat apa pun, gunakan countuntuk membuat kueri hitung pada db Anda

  • jika Anda tidak ingin repot dengan pertimbangan ini, gunakan sizeyang akan beradaptasi


35
Jika sizemenyesuaikan dengan situasi, maka untuk apa lengthdan countuntuk apa?
sscirrus

27
@ sscirus - Sehingga sizedapat membuat panggilan ke mereka saat Anda melakukan panggilan ke size(setelah itu menentukan yang akan dipanggil).
Batkins

35
Berhati-hatilah dengan hanya mengatur ukuran. Misalnya jika Anda membuat catatan baru tanpa melalui relasi, yaitu Comment.create(post_id: post.id), Anda post.comments.sizetidak akan up to date, sementara post.comments.countakan. Jadi berhati-hatilah.
mrbrdo

14
Juga, jika Anda membuat beberapa objek melalui relasi:, company.devices.build(:name => "device1"); company.devices.build(:name => "device2")lalu company.devices.sizedan .lengthakan menyertakan jumlah objek yang Anda buat tetapi belum disimpan, .countakan melaporkan hanya hitungan dari database.
Shawn J. Goff

6
@ sscirrus, ukuran adalah perintah berbahaya karena ini otomatis, kadang-kadang Anda ingin menanyakan db lagi.
Alex C

79

Seperti yang dinyatakan oleh jawaban lainnya:

  • countakan melakukan COUNTkueri SQL
  • length akan menghitung panjang array yang dihasilkan
  • size akan mencoba untuk memilih yang paling tepat dari keduanya untuk menghindari permintaan yang berlebihan

Tetapi ada satu hal lagi. Kami memerhatikan sebuah kasus di mana sizetindakannya berbeda untuk count/ secara lengthkeseluruhan, dan saya pikir saya akan membagikannya karena cukup jarang untuk diabaikan.

  • Jika Anda menggunakan :counter_cachepada has_manyasosiasi, sizeakan menggunakan jumlah cache secara langsung, dan tidak membuat kueri tambahan sama sekali.

    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

Perilaku ini didokumentasikan dalam Rails Guides , tetapi saya melewatkannya pertama kali atau melupakannya.


Bahkan, sebelum rel 5.0.0.beta1, perilaku ini akan dipicu bahkan jika ada _countkolom (tanpa counter_cache: truearahan pada asosiasi). Ini telah diperbaiki di github.com/rails/rails/commit/e0cb21f5f7
cbliard

8

Terkadang size"memilih yang salah" dan mengembalikan hash (yang countakan dilakukan)

Dalam hal ini, gunakan lengthuntuk mendapatkan bilangan bulat bukan hash .


Saya menggunakan '.size' pada Koleksi dari contoh has_many dan meskipun ada satu catatan dalam koleksi, ukuran mengembalikan '0'. Menggunakan .count mengembalikan nilai '1' yang benar.
admazzola

4

tl; dr

  • Jika Anda tahu Anda tidak perlu menggunakan data count.
  • Jika Anda tahu Anda akan menggunakan atau telah menggunakan data tersebut length.
  • Jika Anda tidak tahu apa yang Anda lakukan, gunakan size...

menghitung

Putuskan untuk mengirim Select count(*)...kueri ke DB. Cara untuk pergi jika Anda tidak membutuhkan data, tetapi hanya menghitung.

Contoh: jumlah pesan baru, elemen total saat hanya halaman yang akan ditampilkan, dll.

panjangnya

Memuat data yang diperlukan, yaitu permintaan seperti yang diperlukan, dan kemudian hanya menghitungnya. Cara untuk pergi jika Anda menggunakan data.

Contoh: Ringkasan tabel yang dimuat penuh, judul data yang ditampilkan, dll.

ukuran

Ia memeriksa apakah data dimuat (yaitu sudah ada di rel) jika demikian, maka hitung saja, kalau tidak panggilan akan dihitung. (ditambah jebakan, sudah disebutkan dalam entri lain).

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

Apa masalahnya?

Bahwa Anda mungkin memukul DB dua kali jika Anda tidak melakukannya dalam urutan yang benar (misalnya jika Anda merender jumlah elemen dalam tabel di atas tabel yang diberikan, akan ada 2 panggilan yang efektif dikirim ke DB).


3

Strategi berikut semuanya membuat panggilan ke database untuk melakukan COUNT(*)kueri.

Model.count

Model.all.size

records = Model.all
records.count

Berikut ini tidak seefisien karena akan memuat semua catatan dari database ke Ruby, yang kemudian menghitung ukuran koleksi.

records = Model.all
records.size

Jika model Anda memiliki asosiasi dan Anda ingin menemukan jumlah objek yang dimiliki (misalnya @customer.orders.size), Anda dapat menghindari permintaan basis data (disk membaca). Gunakan penghitung cache dan Rails akan membuat nilai cache up to date, dan mengembalikan nilai itu sebagai respons terhadap sizemetode.


2
Keduanya Model.all.sizedan Model.all.counthasilkan countkueri di Rails 4 dan di atasnya. Keuntungan sebenarnya sizeadalah ia tidak menghasilkan kueri hitung jika asosiasi sudah dimuat. Di Rails 3 dan di bawah, saya percaya Model.allbukan suatu hubungan, maka semua catatan sudah dimuat. Jawaban ini mungkin kedaluwarsa dan saya sarankan menghapusnya.
Damon Aw

1

Saya merekomendasikan menggunakan fungsi ukuran.

class Customer < ActiveRecord::Base
  has_many :customer_activities
end

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

Pertimbangkan dua model ini. Pelanggan memiliki banyak aktivitas pelanggan.

Jika Anda menggunakan: counter_cache pada asosiasi has_many, ukuran akan menggunakan jumlah cache secara langsung, dan tidak membuat kueri tambahan sama sekali.

Pertimbangkan satu contoh: dalam basis data saya, satu pelanggan memiliki 20.000 kegiatan pelanggan dan saya mencoba menghitung jumlah catatan kegiatan pelanggan dari pelanggan itu dengan masing-masing metode hitungan, panjang dan ukuran. di sini di bawah laporan patokan dari semua metode ini.

            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)

jadi saya menemukan bahwa menggunakan: Ukuran counter_cache adalah pilihan terbaik untuk menghitung jumlah catatan.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.