Rails - 急切加载关联记录的数量,但不加载记录本身

时间:2010-05-12 11:42:02

标签: ruby-on-rails find eager-loading

我有一个需要很长时间才能呈现的页面。一半的时间(3秒)花费在.find调用上,该调用具有一堆渴望加载的关联。我真正需要的是每种情况下相关记录的数量,以显示在表格中:我不需要实际的记录本身。有没有办法急于加载计数?这是一个简化的例子:

@subjects = Subject.find(:all, :include => [:questions])

在我的表格中,对于每一行(即每个主题),我只显示主题字段的值和每个主题的相关问题的数量。我可以优化上述查找呼叫以满足这些要求吗?

我考虑使用组字段,但我的完整调用包含一些不同的关联,有一些二阶关联,所以我认为group by不会起作用。

@subjects = Subject.find(:all, :include => [{:questions => :tags}, {:quizzes => :tags}], :order => "subjects.name")

:在这种情况下,标签是通过标签的二阶关联。这是我的关联,以防不清楚发生了什么。

Subject
  has_many :questions
  has_many :quizzes

Question
  belongs_to :subject
  has_many :taggings
  has_many :tags, :through => :taggings

Quiz
  belongs_to :subject
  has_many :taggings
  has_many :tags, :through => :taggings

感谢任何建议 - 最多

3 个答案:

答案 0 :(得分:3)

我认为最好在:counter_cache关联上使用belongs_to

class Subject < ActiveRecord::Base
  has_many :questions
end

class Question < ActiveRecord::Base
  belongs_to :subject, :counter_cache => true
end

要使用counter_cache,您还需要在questions_count表格中添加subjects列。

来自railsapi.com

  

<强>:counter_cache
  缓存所属对象的数量   在关联类上通过使用   increment_counter和   decrement_counter。计数器缓存   当一个对象时,它会递增   class是在创建和递减时   它被摧毁了[...]

答案 1 :(得分:1)

您可以为此目的实现计数器缓存。我在Albums模型上维护一个计数器,该模型跟踪与其相关的照片数量。我的过程看起来有点像这样(我相信我在某个博客上发现了这种方法,所以我对原始代码不予理睬):

在照片模型上:

after_save :update_counter_caches
after_destroy :update_counter_caches

def update_counter_caches
  self.albums.each { |a| a.update_count } unless self.albums.empty?
end

在相册模型上:

def update_count
  update_attribute(:photographs_count, self.photographs.length)
end

相册中您需要的迁移:

class AddCounterCacheColumnToModels < ActiveRecord::Migration
  def self.up
    add_column :albums, :photographs_count, :integer, :default => 0
  end

  def self.down
    remove_column :albums, :photographs_count
  end
end

除非我误解了你的问题,否则这应该是达到你想要的一种非常巧妙的方式。它在我目前的项目中运作良好。 :)


编辑:作为一个注释,我使用此设置而不是默认值:counter_cache方法的原因是因为我需要在一个模型上为多个关联维护多个计数器。据我所知,你无法实现:counter_cache。

答案 2 :(得分:0)

我认为最快的方式:

@subjects = Subject.count(:joins => :questions, :select => 'DISTINCT(questions.id)')

我不确定更复杂的查询(未经测试):

@subjects = Subject.count(:joins => [{:questions => :tags}, {:quizzes => :tags}], :select => 'DISTINCT(tags.id)'