多态 ActiveRecord 查询问题
Issue with polymorphic ActiveRecord query
我有以下三个模型:
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")
最有效的方法是什么?
如果这个案例有什么特别之处,我很感兴趣,但我的镜头如下。
首先,我看不出这里如何应用多态关联。您只有一个对象(用户)可以属于该书。据我了解,多态是为了将书连接到几个差异。对象(例如用户、图书馆、书架等)(编辑 - 问题的初始文本提到了多态关联,现在没有)
其次,我认为这里没有缓存计数器的方法,只要 "Publisher #1" 是一个变化的输入参数,而不是一组少数预定义和已知的发布者(很少有常量) ).
第三,我认为单个出版商的图书数量相对有限。因此,即使您的 table 中有数百万本书,每个出版商的图书数量最多也应该是数百本。
然后可以先查询所有出版社的图书id,例如
book_ids = Book.where(:publisher => "Publisher #1").pluck(:id)
然后在 owns table 中查询顶级用户 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 table 上有索引。
1) 对第二个查询也使用 pluck 以不创建自己的对象,尽管由于 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) 尝试按第一个顺序加入用户 table:
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
我有以下三个模型:
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")
最有效的方法是什么?
如果这个案例有什么特别之处,我很感兴趣,但我的镜头如下。
首先,我看不出这里如何应用多态关联。您只有一个对象(用户)可以属于该书。据我了解,多态是为了将书连接到几个差异。对象(例如用户、图书馆、书架等)(编辑 - 问题的初始文本提到了多态关联,现在没有)
其次,我认为这里没有缓存计数器的方法,只要 "Publisher #1" 是一个变化的输入参数,而不是一组少数预定义和已知的发布者(很少有常量) ).
第三,我认为单个出版商的图书数量相对有限。因此,即使您的 table 中有数百万本书,每个出版商的图书数量最多也应该是数百本。
然后可以先查询所有出版社的图书id,例如
book_ids = Book.where(:publisher => "Publisher #1").pluck(:id)
然后在 owns table 中查询顶级用户 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 table 上有索引。
1) 对第二个查询也使用 pluck 以不创建自己的对象,尽管由于 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) 尝试按第一个顺序加入用户 table:
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