Tản mạn về select và pluck trong Rails
Bài đăng này đã không được cập nhật trong 8 năm
select
và pluck
là 2 method thuộc về ActiveRecord dùng cực nhiều trong quá trình làm việc với Rails. Hiểu rõ hơn về chúng sẽ giúp ta phần nào tăng hiệu suất của ứng dụng đang viết.
Đặt vấn đề
Đây là những khái niệm cơ bản, tuy nhiên nhiều new dev dùng nhưng không rõ bản chất của chúng, bài viết này không mang tính chất bổ sung kiến thức mà nó thiên về nhận xét, chia sẻ nhiều hơn.
Đầu tiên ta thí nghiệm với select
Npc.select :id
Npc Load (61.8ms) SELECT `npcs`.`id` FROM `npcs`
=> [#<Npc:0x007faabb082088 id: 1>,
#<Npc:0x007faabb0948a0 id: 31>,
#<Npc:0x007faabb0946e8 id: 61>,
...
select
sẽ trả về cho ta một mảng các Npc model chỉ chứa giá trị của id
Giờ sẽ thử với pluck
Npc.pluck :id
(63.3ms) SELECT `npcs`.`id` FROM `npcs`
=> [1,
31,
61,
91,
121,
151,
181,
...
pluck
sẽ trả trực tiếp cho ta một mảng số nguyên giá trị của id
thay vì Npc model.
Ta có thể thấy chúng có câu truy vấn giống nhau (Thời gian lệch một chút, không đáng kể). Vậy xét về hiệu năng thì 2 method này tương đương nhau ? Thật ra là không phải như vậy, ta đang chỉ nhìn thấy bên ngoài chúng như vậy, còn sâu xa bên trong thì sao ?
Tính toán cẩn thận hơn chút
Hãy sử dụng Benchmark để đo thời gian thực tế khi sử dụng select
và pluck
Đầu tiên là với select
puts Benchmark.measure {Npc.select(:id).to_a}
Npc Load (62.4ms) SELECT `npcs`.`id` FROM `npcs`
1.900000 0.590000 2.490000 ( 2.538390)
Giờ tới pluck
puts Benchmark.measure {Npc.pluck :id}
(63.8ms) SELECT `npcs`.`id` FROM `npcs`
0.250000 0.070000 0.320000 ( 0.367138)
Bạn có thể thấy thời gian chênh lệch thực sự là quá lớn, con số 62.4ms
hay 63.8ms
chỉ là thời gian truy vấn, nhưng Rails đã không cho ta thấy thời gian thật sự khi sử dụng chúng.
Nguyên nhân
Lý do dẫn tới thời gian chênh lệch nhau quá lớn như vậy là do sử dụng select
ta sẽ mất rất nhiều thời gian để build lại các ActiveRecord models. pluck
được sinh ra để phục vụ cho những nhu cầu cần số liệu cụ thể và ta cũng có thể thấy được hiệu suất khi sử dụng chúng rất khác biệt.
Phân biệt và ứng dụng
Việc sử dụng đúng nơi, đúng lúc chúng sẽ giúp chúng ta cải thiện được hiệu suất của ứng dụng. Những trường hợp điển hình ta dễ dàng phân biết chúng như select
sẽ dùng khi ta cần đầu ra là ActiveRecord model hay dùng để chain truy vấn, trong khi pluck
sẽ trả về thẳng cho chúng ta số liệu để phục vụ cho mục đích tính toán.
Ví dụ
Npc.where(npc_type_id: NpcType.select(:id))
Npc Load (721.7ms) SELECT `npcs`.* FROM `npcs` WHERE `npcs`.`npc_type_id` IN (SELECT `npc_types`.`id` FROM `npc_types`)
Npc.where(npc_type_id: NpcType.pluck(:id))
(0.3ms) SELECT `npc_types`.`id` FROM `npc_types`
Npc Load (511.2ms) SELECT `npcs`.* FROM `npcs` WHERE `npcs`.`npc_type_id` IN (1, 2, 3 ...)
Trên đây một ví dụ điển hình giúp ta phân biệt khi nào dùng select
hay pluck
. Với việc dùng select
để chain truy vấn, ta chỉ cần query một lần vào database trong khi với pluck
ta sẽ cần tới 2 query.
Kết luận
Trên đây là những kiến thức cơ bản, nhưng dễ dàng bị bỏ qua vì những quan niệm kiểu : Mình thích thì mình dùng thôi
hay Nó chạy ngon nhanh thì mình dùng thôi
. Qua bài tản mạn này, phần nào các bạn cũng biết được chúng nó khác nhau ở đâu, tại sao khác nhau , thời gian thực tế khi chạy cũng như sử dụng chúng đúng nơi đúng chỗ để đạt được hiệu suất tốt nhất.
Do kiến thức còn hạn chế nên bài viết tất sẽ có những sai sót, mong bạn đọc tích cực góp ý để mình hoàn thiện bài viết cũng như củng cố lại kiến thức.
All rights reserved