ActiveRecords select(:id).collect vs. pluck(:id) 方法:为什么纯 AR "pluck" 更慢?
ActiveRecords select(:id).collect vs. pluck(:id) methods: Why is pure AR "pluck" slower?
我正在尝试从我的文章模型中获取所有 ID。我可以通过两种方式做到这一点:
Article.select(:id).collect{|a| a.id}
Article Load (2.6ms) SELECT "articles"."id" FROM "articles"
或
2.2.1 :006 > Article.pluck(:id)
(4.3ms) SELECT "articles"."id" FROM "articles"
什么给了?为什么 AR 比 Ruby 版本慢?
即使我对 Ruby 方法进行基准测试,它似乎也更快:
Benchmark.measure{Article.select(:id).collect{|a| a.id}}
Article Load (1.9ms) SELECT "articles"."id" FROM "articles"
=> #<Benchmark::Tms:0x007feb12060658 @label="", @real=0.026455502957105637, @cstime=0.0, @cutime=0.0, @stime=0.0, @utime=0.020000000000000018, @total=0.020000000000000018>
您的基准不准确。首先,如你所见,数据库端的两次执行都触发了相同的查询
SELECT "articles"."id" FROM "articles"
因此,数据库时间应该被认为是无关紧要的。很明显,控制台显示这两个查询的执行时间不同,但这是正常的,就好像你 运行 相同的查询 100 次执行时间每次都可能不同,因为它取决于各种变量,例如机器负载、数据库状态等
由于数据库执行时间可以被认为是等效的,因此与基准测试无关。
因此,您需要比较的是Ruby执行时间和分配。与 collect
相比,Pluck 应该更快、更轻便,它不分配 ActiveRecord 对象,而 returns 仅分配选定的值。
如果你真的想对这些方法进行基准测试,你应该模拟数据库时间(这显然是可变的但与这个基准测试无关)并且只模拟基准分配和两个不同的 Ruby 方法。
长话短说,pluck
通常效率更高。
select
用于获取具有特定属性的记录。它 returns 一个 ActiveRecord::Relation
对象。
pluck
的使用方式与 select
的使用方式相同,但是它 returns 一个选定属性的数组。
你可以通过 this article.
你不应该关注控制台记录的时间,而是做一个适当的benchmark
。这是在嵌套查询中使用时 select
的速度(大约快 30 倍!)
[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)
如前所述,这是因为在第一种情况下,查询作为嵌套 select 合并到主查询中,而 pluck
则执行第一个查询以获取 ID ,然后用于 运行 主查询。
请记住,此类基准始终取决于您的数据库、索引、您正在处理的行数等。如有疑问,请始终 运行 一个快速基准来确认此类假设!
郑重声明,这里有一个类似的“简单”查询基准,它确实表明 pluck
更快,尽管差距不大:
[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)
我正在尝试从我的文章模型中获取所有 ID。我可以通过两种方式做到这一点:
Article.select(:id).collect{|a| a.id}
Article Load (2.6ms) SELECT "articles"."id" FROM "articles"
或
2.2.1 :006 > Article.pluck(:id)
(4.3ms) SELECT "articles"."id" FROM "articles"
什么给了?为什么 AR 比 Ruby 版本慢?
即使我对 Ruby 方法进行基准测试,它似乎也更快:
Benchmark.measure{Article.select(:id).collect{|a| a.id}}
Article Load (1.9ms) SELECT "articles"."id" FROM "articles"
=> #<Benchmark::Tms:0x007feb12060658 @label="", @real=0.026455502957105637, @cstime=0.0, @cutime=0.0, @stime=0.0, @utime=0.020000000000000018, @total=0.020000000000000018>
您的基准不准确。首先,如你所见,数据库端的两次执行都触发了相同的查询
SELECT "articles"."id" FROM "articles"
因此,数据库时间应该被认为是无关紧要的。很明显,控制台显示这两个查询的执行时间不同,但这是正常的,就好像你 运行 相同的查询 100 次执行时间每次都可能不同,因为它取决于各种变量,例如机器负载、数据库状态等
由于数据库执行时间可以被认为是等效的,因此与基准测试无关。
因此,您需要比较的是Ruby执行时间和分配。与 collect
相比,Pluck 应该更快、更轻便,它不分配 ActiveRecord 对象,而 returns 仅分配选定的值。
如果你真的想对这些方法进行基准测试,你应该模拟数据库时间(这显然是可变的但与这个基准测试无关)并且只模拟基准分配和两个不同的 Ruby 方法。
长话短说,pluck
通常效率更高。
select
用于获取具有特定属性的记录。它 returns 一个 ActiveRecord::Relation
对象。
pluck
的使用方式与 select
的使用方式相同,但是它 returns 一个选定属性的数组。
你可以通过 this article.
你不应该关注控制台记录的时间,而是做一个适当的benchmark
。这是在嵌套查询中使用时 select
的速度(大约快 30 倍!)
[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)
如前所述,这是因为在第一种情况下,查询作为嵌套 select 合并到主查询中,而 pluck
则执行第一个查询以获取 ID ,然后用于 运行 主查询。
请记住,此类基准始终取决于您的数据库、索引、您正在处理的行数等。如有疑问,请始终 运行 一个快速基准来确认此类假设!
郑重声明,这里有一个类似的“简单”查询基准,它确实表明 pluck
更快,尽管差距不大:
[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)