ActiveRecords select(:id).collect vs. pluck(:id) methods: Why is pure AR "pluck" slower?

Your benchmark is inaccurate. First of all, as you can see, both executions on the database side triggers the same query

SELECT "articles"."id" FROM "articles"

Therefore, the database time should be considered irrelevant. Clearly the two queries had different execution time as shown by the console, but this is normal as if you run the same query 100 times the execution time can be different each time as it depends by a variety of variables such as the machine load, the database state, etc.

Since the database execution time can be considered equivalent, it's irrelevant for the benchmark.

Therefore, what you need to compare is the Ruby execution time and allocation. Pluck is supposed to be faster and more lightweight as compared to collect it doesn't allocate ActiveRecord objects, rather it returns only the selected values.

If you really want to benchmark the methods, you should mock the database time (which is clearly variable but irrelevant for this benchmark) and only benchmark allocation and the two different Ruby methods.

Long story short, pluck is generally more efficient.


select is used to fetch records with specific attributes. It returns an ActiveRecord::Relation object.

pluck can be used the same way select is used, however it returns an array of selected attributes.

You can go through this article.


You shouldn't pay attention to the times recorded in the console and do a proper benchmark instead. Here's how much faster select can be when used in a nested query (about 30 times faster!)

[25] pry(main)> ActiveRecord::Base.logger = nil
[25] pry(main)> Benchmark.bmbm do |bm|
[25] pry(main)*   bm.report('select') do
[25] pry(main)*     2000.times do
[25] pry(main)*       ActiveRecord::Base.uncached do
[25] pry(main)*         Agenda.where(organization_id: Organization.limit(2).select(:id))
[25] pry(main)*       end
[25] pry(main)*     end
[25] pry(main)*   end
[25] pry(main)*   bm.report('pluck') do
[25] pry(main)*     2000.times do
[25] pry(main)*       ActiveRecord::Base.uncached do
[25] pry(main)*         Agenda.where(organization_id: Organization.limit(2).pluck(:id))
[25] pry(main)*       end
[25] pry(main)*     end
[25] pry(main)*   end
[25] pry(main)* end
Rehearsal ------------------------------------------
select   0.147064   0.001408   0.148472 (  0.149976)
pluck    1.494075   0.077501   1.571576 (  4.175919)
--------------------------------- total: 1.720048sec

             user     system      total        real
select   0.140494   0.000301   0.140795 (  0.140956)
pluck    1.200006   0.070174   1.270180 (  3.958814)

As has been explained, this is because in the first case the query is merged into the main query as a nested select, while with pluck a first query is executed to get the ids, which are then used to run the main query.

Bear in mind that this kinds of benchmarks always depend on your database, indexes, amount of rows you're dealing with, etc. When in doubt always run a quick benchmark to confirm this kind hypothesis!

For the record, here's a similar benchmark for your kind of "simple" query, which indeed shows pluck is faster, albeit not by a huge margin:

[27] pry(main)> Benchmark.bmbm do |bm|
[27] pry(main)*   bm.report('select') do
[27] pry(main)*     2000.times do
[27] pry(main)*       ActiveRecord::Base.uncached do
[27] pry(main)*         Organization.select(:id).collect(&:id)
[27] pry(main)*       end
[27] pry(main)*     end
[27] pry(main)*   end
[27] pry(main)*   bm.report('pluck') do
[27] pry(main)*     2000.times do
[27] pry(main)*       ActiveRecord::Base.uncached do
[27] pry(main)*         Organization.pluck(:id)
[27] pry(main)*       end
[27] pry(main)*     end
[27] pry(main)*   end
[27] pry(main)* end
Rehearsal ------------------------------------------
select   1.669422   0.080951   1.750373 (  4.318759)
pluck    1.081312   0.064770   1.146082 (  3.797270)
--------------------------------- total: 2.896455sec

             user     system      total        real
select   1.601772   0.069176   1.670948 (  4.298829)
pluck    1.094950   0.064165   1.159115 (  3.811094)