如何编写高效的活动记录查询

时间:2016-12-21 00:37:36

标签: ruby activerecord rails-activerecord

我对ActiveRecord比较新,我和Sinatra一起使用。目前,我正在建立小规模的网站。我没有遇到任何问题花了太长时间,但我想知道如何最好地优化搜索,所以我的网站是可扩展的。

这是我一直想知道的事情。 ActiveRecord是否将分解为多个函数的查询视为一个函数?

# Single
BlogPost.last(5)

# Broken Down
BlogPost.all.limit(5)

这是一个概念性问题:ActiveRecord如何运行搜索?添加更多功能会降低搜索效率吗?当您将查询分解为多个函数BlogPost.where(publish: true)时 - 假设where(publish: true)返回50个结果,limit将其限制为5个。它是否首先找到所有五十publish: true然后在五点之后切断所有内容,或者它是否足够智能以在找到前五个后停止搜索?

1 个答案:

答案 0 :(得分:2)

你的预感是正确的。将ActiveRecord查询链接起来是一种很好的做法。

说你的BlogPost表有一百万行。

然后说BlogPost.all会很慢,但说BlogPost.all.limit(1)会很快。

alllimit都是ActiveRecord的一部分。返回值响应Array方法但不是数组。这有一些例外。例如,find_by / find返回模型实例,但您可以将它们作为链中的最后一个查询方法。 pluck返回一个普通的ruby数组。

BlogPost.all[1]BlogPost.all一样慢,因为[ ]是一个数组方法,而不是ActiveRecord。

当您将ActiveRecord方法链接在一起时,在将方法转换为数组或尝试读取某些数据之前,不会执行查询。

所以query = BlogPost.all.order(id: :desc).reorder(id: :asc).limit(1)实际上没有从数据库加载任何数据。另请阅读preloading data),它可以解决慢N+1次查询问题。

如果您随后说query.to_aquery.reduce等,那么Arel(构建ActiveRecord的内容),最终确定查询并执行它。

您可以致电<query>.to_sql查看基础查询:

class Foo < ActiveRecord::Base
end

Foo.all.to_sql
#=> "SELECT \"foos\".* FROM \"foos\""
Foo.all.limit(1).to_sql
#=> "SELECT  \"foos\".* FROM \"foos\" LIMIT 1"