ActiveRecord select vs pluck

selectpluck 都可以从数据库读取指定的字段,但两者存在不小的差别。

1
2
3
4
5
6
7
Product.select(:id).to_a
# Product Load (0.5ms) SELECT `products`.`id` FROM `products`
# [#<Product id: 2>, #<Product id: 1>]

Product.pluck(:id)
# Product Load (0.4ms) SELECT `products`.`id` FROM `products`
# [2, 1]

select 返回的是仅含有 id 的 Product Model 数组,而 pluck 返回的是 id 的数组。
两者相比较,pluck 省却了构造 ActiveRecord 的过程,效率更优。我们可以通过 Benchmark.measure 来验证下。

1
2
puts Benchmark.measure {Product.select(:id).to_a}
puts Benchmark.measure {Product.pluck(:id)}

- user CPU time system CPU time sum CPU time elapsed real time
select 0.050000 0.020000 0.070000 0.095440
pluck 0.000000 0.000000 0.000000 0.001845

除此之外,两者还有一个区别,即查询时机的不同。

1
2
3
4
5
6
ProductOrder.where.not(id: SubOrder.where(sub_order_no: '001').pluck(:order_id))
# SELECT `orders`.* FROM `orders` WHERE `orders`.`type` IN ('ProductOrder') AND (`orders`.`id` NOT IN (SELECT `sub_orders`.`order_id` FROM `sub_orders` WHERE `sub_orders`.`sub_order_no` = '001'))

ProductOrder.where.not(id: SubOrder.where(sub_order_no: '001').pluck(:order_id))
# SELECT `sub_orders`.`order_id` FROM `sub_orders` WHERE `sub_orders`.`sub_order_no` = '001'
# SELECT `orders`.* FROM `orders` WHERE `orders`.`type` IN ('ProductOrder') AND (`orders`.`id` != 3)

在上面这个例子中,通过 pluck 的调用进行了两次查询,而 select 只进行了一次查询。可见调用 pluck 会立即进行数据库查询。

参考