【问题标题】:Avoiding db hits in ActiveRecord避免 ActiveRecord 中的数据库命中
【发布时间】:2012-09-28 17:24:30
【问题描述】:

当我将数据库查找分配给 Rails 中的实例变量时,为什么以后对该变量的请求也会访问数据库?可以避免吗?

例如,我有 3 个模型:User、Resource、Opinion,with has_many :through on Opinion

@opinions = current_user.opinions # pulls in all of the user's opinions, which include respective resource ids
1、直接调用resource_id并没有命中数据库:
@opinions.each do |opinion|
  opinion.resource_id  # does not hit the database (as expected)
end
2. 执行查询确实会命中数据库(即使已分配变量):
@opinions.find_by_resource_id(1) # DOES hit the database

为什么#2 会命中数据库?有没有办法在不访问数据库的情况下执行相同的查找?

该信息已包含在@opinions 变量中,因此似乎不需要调用数据库。

【问题讨论】:

  • 您在#2 中实际上想要做什么?您是否尝试从具有特定 ID 的集合中提取意见?
  • jstim:是的,这就是我想做的。我正在遍历 Resource 模型的一个子集,并希望显示用户对每个模型的意见。

标签: ruby-on-rails-3 activerecord instance-variables


【解决方案1】:

如果您不需要 @opinions 数组中的任何其他内容,我会将您的原始查询限定为仅包含与该 resource_id 相关的意见

@opinions = current_user.opinions.where("resource_id = ?", resource_id)

如果您已经拥有@opinions 并且只想创建一个新的对象数组来匹配特定的键/值:

@opinions_with_resource_id = @opinions.select { |opinion| opinion.resource_id == 1234 }

查看this other answer 以获得其他解释,或者如果您想将答案拆分为多个数组。

想法

评论你的最后一段代码

像您这样称为 find_by_* 的方法是动态查找器,它们使用 method_missing 来访问数据库并查看 * 指定的列的内部。

上一个答案的剩余 cmets

如果此对象需要访问 Resource 模型上的数据,请不要忘记 #includes() 方法,这将使您不必在以后运行其他查询。

@opinions = current_user.opinions.includes(:resources)

http://guides.rubyonrails.org/active_record_querying.html#eager-loading-associations

【讨论】:

  • "#1 所做的只是拉取 Opinions 数组,其中包含尚未加载的 Resources 的 foreign_key。
  • 啊,好吧,假设一个用户有 5 个意见,其中 3 个的 resource_id 等于 124。您希望查询拉回具有该值的 3 个意见。
  • 我有 1 个用户,有几个最喜欢的资源,我想找到每个资源的单一意见(包括评论、是否是最喜欢的等)。我已经在@opinions 变量中获得了所有用户的意见,我只想从这个变量中提取信息而不访问数据库。
  • include 方法不应该是复数吗:includes?
  • @BKSpureon 是的,我认为你是对的。已更新。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-03-09
  • 2010-09-07
  • 1970-01-01
  • 2021-11-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多