Rails эффективный SQL для «популярных» пользователей - PullRequest
3 голосов
/ 24 декабря 2010

Я создаю блог-сайт в Rails (3), где «Авторы» могут следовать за другими авторами, и для того, чтобы найти авторов с наибольшим количеством подписчиков, я написал эту область:

scope :popular, all.sort { |a, b| a.followers.count <=> b.followers.count }

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

class Author < ActiveRecord::Base

  has_many :relationships, :dependent => :destroy, :foreign_key => "follower_id"
  has_many :following, :through => :relationships, :source => :followed
  has_many :reverse_relationships, :dependent  => :destroy, :foreign_key => "followed_id",  :class_name => "Relationship"
  has_many :followers, :through => :reverse_relationships,  :source => :follower

  scope :popular, all.sort { |a, b| a.followers.count <=> b.followers.count }

end

"Последователи" реализованы в отдельной модели:

class Relationship < ActiveRecord::Base

  belongs_to :follower, :class_name => "Author"
  belongs_to :followed, :class_name => "Author"

end

И для поиска популярных авторов:

@popular_authors = Author.popular[0..9]

Мне бы хотелось иметь возможность писать что-то вроде Author.popular.limit(10), но я понимаю, что для того, чтобы это работало, Author.popular должен возвращать объект класса ActiveRecord::Relation, а не массив.

Как я уже говорил, этот код работает , но он ужасно неэффективен, выдает сотни запросов только для того, чтобы найти 10 лучших авторов.Любая помощь будет принята с благодарностью!

1 Ответ

2 голосов
/ 24 декабря 2010

Одной из оптимизаций может быть использование быстрой загрузки.Я подозреваю, что у вас много запросов, которые говорят: SELECT * from Автор WHERE follower_id = 7

Стремительная загрузка может превратить ваши сотни запросов в гигантский для вас.Это может генерировать медленный запрос, но часто это будет быстрее, потому что время медленного запроса было меньше, чем 5000 быстрых запросов.

Я не гуру SQL, но вы также можете использовать GROUP_BY с LIMIT = 10.чтобы получить 10 самых популярных.

Попробуйте что-то вроде

Authors.find(:all, :include => Authors, :group_by => " SELECT `count` as (some subquery I don't know to get the number of followers)", :limit => 10)

Прокрутите вниз до Eager loading ассоциаций

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...