Rails - стремятся загрузить количество связанных записей, но не сами записи - PullRequest
2 голосов
/ 12 мая 2010

У меня есть страница, на которую уходят целую вечность. Половина времени (3 секунды) тратится на вызов .find, который имеет множество загруженных ассоциаций. Все, что мне действительно нужно, это количество связанных записей в каждом случае, чтобы отобразить их в таблице: мне не нужны сами записи. Есть ли способ просто загрузить счет? Вот упрощенный пример:

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

В моей таблице для каждой строки (то есть для каждого предмета) я просто показываю значения полей предмета и количество связанных вопросов для каждого предмета. Могу ли я оптимизировать вышеуказанный поиск вызова в соответствии с этими требованиями?

Я думал об использовании поля группы, но в мой полный вызов включено несколько различных ассоциаций, с некоторыми ассоциациями второго порядка, поэтому я не думаю, что сработает группа по.

@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 ]

3 голосов
/ 12 мая 2010

Я считаю, что лучше всего использовать :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. Кеш счетчика увеличивается, когда объект этого класс создается и уменьшается, когда он разрушен [...]

1 голос
/ 12 мая 2010

Вы можете реализовать счетчик кэша для этой цели. Я веду счетчик на модели альбомов, который отслеживает, сколько фотографий связано с ней. Мой процесс выглядит примерно так (мне кажется, я где-то нашел этот метод в блоге, поэтому я не возражаю против оригинального кода):

На фотографии фотографии:

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.

0 голосов
/ 12 мая 2010

самый быстрый способ, которым я думаю:

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

И я не уверен в более сложном запросе (не проверен):

@subjects = Subject.count(:joins => [{:questions => :tags}, {:quizzes => :tags}], :select => 'DISTINCT(tags.id)'
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...