[Rails] 分辨 size vs length vs count

搞懂 size / length / count 之間的差別

stackoverflow

stackoverflow 上有這麼一段最佳留言
在每次遇到都很疑惑下,就實際測試並做個筆記

在必然觸發 query 的情境下,比較三者差別

測試情境 User table 分別調用三種方法
1
2
3
4
5
6
7
8
9
> User.all.length
User Load (70.3ms) SELECT "users".* FROM "users"
20
> User.all.size
(1.4ms) SELECT COUNT(*) FROM "users"
20
> User.all.count
(0.9ms) SELECT COUNT(*) FROM "users"
20
  1. 調用 length

    • select * from users 撈取所有的 user 數據
    • 最後返回數據筆數
  2. 調用 countsize

    • 一樣的 query 語句 select count(*) from users
    • 都不是撈出所有數據,而是直接調用計算筆數的語句 count
    • 效能顯而易見略勝

疑惑:那 count 跟 size 有什麼差別呢?

在確定不會觸發 query 的情境下,比較三者差別

測試情境 User instance 的 relations 分別調用三種方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
> user = User.find(72)
> user.topics.build()
#<Topic:0x00007fccd3df7198> {
:id => nil,
:coments_count => 0,
..
..
..
}
> user.topics.length
1
> user.topics.size
1
> user.topics.count
(1.2ms) SELECT COUNT(*) FROM "topics" WHERE "topics"."user)id" = $1 [["user_id", 72]]
0
  1. sizelength
    • 都因為先前 relations build 而返回 1 筆數據。
    • 但兩者都沒有 query 的語句,等於是在該實例中直接計算筆數。
  1. count
    • 仍然 touch DB,有著一條 query 語句。
    • 實例變量情境下 count 仍產生了一條 query 的效能。

總結

應該根據各種情境使用對應的方法
至於 length 就可以不用,因為 size 可以符合大部分的情境
不過瞭解後可以更精確的使用 count
像是確實要 DB 重新獲取真實數據的筆數,也就是 query 的效能已是不可避免
可以用兩種方式:

1
2
> user.topics.reload.size
Topic Load (0.4ms) SELECT "topics".* FROM "topics" WHERE "topics"."user_id" = $1 [["user_id", 72]]

又或者使用 count

1
2
> user.topics.count
(0.5ms) SELECT COUNT(*) FROM "topics" WHERE "topics"."user_id" = $1 [["user_id", 72]]

當我們寫測試時 context "User will create and receive notifications"
預期得到一筆數據,假設預期數據不一樣,使用 reload 後,可以得到正確的數據

1
expect(subject).to eql(user.topics.reload.size)

可以避免寫 reload 寫法,看起來符合語意也很漂亮

1
expect(subject).to eql(user.topics.count)

Comments

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×