我有三个具有以下关联的模型:
User has_many :owns, has_many :owned_books, :through => :owns, source: :book
Book has_many :owns
Own belongs_to :user, :counter_cache => true, belongs_to :book
我还有一个页面,通过以下查询跟踪拥有的顶级用户:
User.all.order('owns_count desc').limit(25)
我现在想添加一个新页面,该页面可以按照上面的拥有情况跟踪热门用户,但条件为:
Book.where(:publisher => "Publisher #1")
最有效的方法是什么?
答案 0 :(得分:1)
如果这种情况有特别的东西,我很有意思,但我的镜头将是以下内容。
首先,我不知道如何在这里应用多态关联。您只有一本书可以属于该对象(用户)。据我所知,多态是将书连接到几个dif。对象(例如用户,图书馆,书架等)(编辑 - 问题的初始文本提到多态关联,现在它没有'
其次,我不相信有一种方法可以在这里缓存计数器,只要"发布者#1"是一个变化的输入参数,而不是一组预定义和已知的发布者(少数常量)。
第三,我认为单一出版商的书籍数量相对有限。因此,即使您的表中有数百万本书,每个出版商的书籍数量也应该达到数百本。
然后,您可以先查询所有发布商的图书ID,例如
book_ids = Book.where(:publisher => "Publisher #1").pluck(:id)
然后在拥有表中查询最高用户ID:
Owns.select("user_id, book_id, count(book_id) as total_owns").where(book_id: book_ids).group(:user_id).order(total_owns: :desc).limit(25)
免责声明 - 我没有在rails控制台中尝试使用该语句,因为我没有定义您的对象。我基于ActiveRecord中的群组通话docs
修改即可。为了提高效率,您可以尝试以下方法:
0)以防万一,确保Owns表上有两个外键的索引。
1)对第二个查询使用pluck以及不创建Own对象,尽管由于limit(25)而不应该有很大的区别。像这样:
users_ids = Owns.where(book_id: book_ids).group(:user_id).order("count(*) DESC").limit(25).pluck("user_id")
请参阅this question以供参考。
2)在一个后续查询中加载所有结果用户,而不是为每个用户加载N个查询
top_users = User.where(:id => users_ids)
3)尝试按第一顺序加入User表:
owns_res = Owns.includes(:user).select("user_id, book_id, count(book_id) as total_owns").where(book_id: book_ids).group(:user_id).order("total_owns DESC").limit(25)
然后使用owns_res.first.user