iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 22
0
Modern Web

Ruby on Rails面試題挑戰系列 第 22

Ruby on Rails面試題挑戰 Day22 - count、length和size的差異?

  • 分享至 

  • xImage
  •  

What is the difference between count, length, and size?
count、length和size的差異?


在ActiveRecord中有許多方法可以去找到關連性的總數,以下就來解析這些方法的差異

count

s2 = Song.find(2)

s2.comments.count
SELECT COUNT(*) FROM "comments" WHERE "comments"."song_id" = $1  [["song_id", 2]]
# => 76

s2.comments.count
SELECT COUNT(*) FROM "comments" WHERE "comments"."song_id" = $1  [["song_id", 2]]
# => 76

上面這個例子想對二號歌曲找到他所有的留言總數,count的特性就是每次使用都一定會觸發SQL COUNT的查詢,所以效能上不是太好,但因為每次執行都是老老實實的去資料庫查詢,所以是最為精準的。

length

同樣的例子來對比length方法

s2 = Song.find(2)

s2.comments.length
SELECT "comments".* FROM "comments" WHERE "comments"."song_id" = $1  [["song_id", 2]]
#=> 76

s2.comments.length
#=> 76

length方法會將所有關聯性的內容全部都撈出來存在記憶體當中,然後回傳有多少元素被載入,在只要計算總數目的來看效能上是最差的。

但可以看到我們第二次執行length方法的時候,並不會再去撈一次資料庫,畢竟前面都已經將所有的內容都撈過一次了,所以第二次只會再去數一次。所以在前面已經load過這些資料,可以使用length來避免資料庫的重複查詢。

size

size這個方法就是countlength的綜合體,為什麼會這麼說呢?
來看原始碼就知道了

# File activerecord/lib/active_record/relation.rb, line 210
# Returns size of the records.
def size
  loaded? ? @records.length : count(:all)
end

如果關係已經被載入(load),我們就對已經載入的Array執行length方法,而如果資料ActiveRecord::Relation沒有被載入,我們就觸發count的查詢。

使用時機整理

使用時機可以總結為以下幾點

  • 如果已經載入過所需資料,那用length可以避免再一次的資料庫查詢
  • 如果還沒有載入過相關資料,使用count方法查詢資料庫
  • 如果不想要考慮太多情況,使用size方法會是個好選擇

你可以這樣回答:

  • count方法每次執行時都會對資料庫進行COUNT查詢,只有當我們當下真的要去算總數時才會使用count方法
  • length方法在資料還沒載入時,會將所有關聯資料內容拉出來存在記憶體當中,回傳被載入的個數,以計算總數的效能上是最不好的。不過當資料已經在前面被載入時,使用length方法能讓我們減少資料庫的查詢次數。
  • size方法是countlength的總和,當資料已經被載入過,使用size就等同於使用length方法,如果沒有的話,會幫我們使用count查詢。

參考資料

1.ActiveRecord: size vs count vs length

2.count vs length vs size

3.3 ActiveRecord Mistakes That Slow Down Rails Apps: Count, Where and Present


上一篇
Ruby on Rails面試題挑戰 Day21 - 什麼是scope?
下一篇
Ruby on Rails面試題挑戰 Day23 - Fat models, Skinny controllers和 Skinny controllers, Skinny models的意思為何?
系列文
Ruby on Rails面試題挑戰30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言