我目前正在使用非常大的mysql2数据库工作,尽管我已经将我认为正确的字段编入索引,但某些查询的返回时间非常慢。
我有两个导致问题的模型,Comment
和Commenter
。
现在,has_many
和Commenter
之间存在Comment
关系,但我的查询依赖于查找每个评论的评论者用户名。所以我会运行这样的事情:
c = Blog.first.comments ##this bit runs fine, I indexed the "blog_id" field on Comments
c.collect {|c| c.commenter.username}
为了解决速度问题,我在Comment模型的commenter_id
字段上创建了一个索引。但它仍然运行得很慢..
有人知道我能做些什么不同,这有助于提高查询的速度吗?
答案 0 :(得分:3)
commenter_id
上的索引有助于您查找给定commenter_id
的评论("找到我做过的所有评论")。
但是当您c.commenter
进行搜索时,您可能会找到id
等于评论commenter_id
的用户。 id
列上应该已有索引。确定的方法是获取生成的实际sql语句(在开发中这些是在development.log中),并使用解释,例如
explain select * from comments where id = 12345
鉴于您设法创建一个没有索引的id
列的表格,最不可能的罪魁祸首就是热切加载 - 如果帖子有500条评论,那么上面的代码将逐个获取关联的用户,并将这500次往返数据库的内容加起来
c.includes(:commenter).collect {...}
或
c.eager_load(:commenter).collect {...}
将解决这个问题(上面的代码段假设您使用的是rails 3)。
答案 1 :(得分:2)
Collect将为每个评论者一次加载一个所有字段的ActiveRecord对象。包含/ Eager Loading将使用一个查询来加载它们,这将有助于提高速度,但是如果你想要绝对最佳性能并且你只需要名称,那么最好直接使用以下内容直接使用SQL:
c = Blog.first.comments
user_ids = c.collect(&:commenter_id)
usernames = Commenter.where(['commenter_id IN (?)',user_ids]).select('username').collect(&:username)
答案 2 :(得分:1)
首先,你在这里做了太多不必要的查询
c.collect {|c| c.commenter.username}
我认为渴望加载可以帮助你。观看此http://railscasts.com/episodes/23-counter-cache-column?autoplay=true
答案 3 :(得分:0)
我想出了使用急切的负载,这不是RaskolnikOFF发布的链接,而是它之前的导轨,http://railscasts.com/episodes/22-eager-loading(仍然给你一个推动我的答案的支持)
显然我正在寻找的是以下内容:
b = Blog.find(:first, :include=>{:comments => :commenter})
b.comments.collect {|c| c.commenter.username}
第一行加载第一个博客及其所有关系(并返回博客)。因此,当我调用第二行时,所有内容都已加载并等待访问..
哪种方式比我原来做的更好。