简体   繁体   English

Rails数据库性能调优

[英]Rails database performance tuning

I'm working a lot with a VERY large mysql2 database at the moment, and although I have indexed what I thought were the proper fields, the return time for some queries is quite slow. 目前,我正在使用非常大的mysql2数据库进行很多工作,尽管我已经索引了我认为适当的字段,但是某些查询的返回时间非常慢。

I have two models that are causing issues, Comment and Commenter . 我有两个引起问题的模型CommentCommenter

Now, there is a has_many relationship between Commenter and Comment , but my query relies on finding the each Comment's Commenter's username. 现在,有一个has_many关系CommenterComment ,但我的查询依赖于寻找每个评论的评论者的用户名。 So I'll run something like this: 因此,我将运行以下内容:

c = Blog.first.comments ##this bit runs fine, I indexed the "blog_id" field on Comments
c.collect {|c| c.commenter.username}

To help with the speed issues, I created an index on the commenter_id field for the Comment model. 为了解决速度问题,我在Commenter模型的commenter_id字段上创建了一个索引。 But it is still running very slow.. 但是它仍然运行非常缓慢。

Does anybody know of what I could do differently, that would help increase the speed of the query? 有人知道我可以做些什么,那将有助于提高查询速度吗?

An index on commenter_id helps when you want to find the comments for a given commenter_id ("find me all the comments joe made"). 在索引commenter_id帮助,当你想找到一个给定的评论commenter_id (“找到我提出的所有意见乔”)。

But when you do c.commenter you're searching for users, presumably the one whose id is equal to the comment's commenter_id . 但是,当您使用c.commenter您正在搜索用户,大概是其id等于评论的commenter_id There should already be an index on the id column. id列上应该已经有一个索引。 The surefire way is to take the actual sql statements generated (in development these are in development.log), and use explain on them, for example surefire的方法是采用实际生成的sql语句(在开发中,这些语句在development.log中),并在其上使用解释(例如)

explain select * from comments where id = 12345

Given that it's very unlikely that you managed to create a table without an index on it's id column, the most likely culprit is eager loading - if a post had 500 comments then the above code would fetch the associated users one by one, and those 500 roundtrips to the database add up 鉴于您很难创建一个表而不在其id列上建立索引,因此最有可能的罪魁祸首是急于加载-如果某条帖子包含500条评论,则以上代码将逐个获取关联的用户,而那500条往返数据库的总和

c.includes(:commenter).collect {...}

or 要么

c.eager_load(:commenter).collect {...}

will fix that (the above snippets assume you're using rails 3). 将解决此问题(以上代码段假定您正在使用导轨3)。

Collect is going to load ActiveRecord objects for every commenter with all fields one at a time. Collect将为每个带有所有字段的评论者一次加载ActiveRecord对象。 Including / Eager Loading will load them with one query which will help with speed, but if you want the absolute best performance and you just need the names you're better off reaching down to SQL more directly with something to the tune of: 包含/急于加载将使用一个查询来加载它们,这将有助于提高速度,但是如果您想要绝对最佳的性能,并且只需要名称,那么最好通过以下方式更直接地接触到SQL:

c         = Blog.first.comments
user_ids  = c.collect(&:commenter_id)
usernames = Commenter.where(['commenter_id IN (?)',user_ids]).select('username').collect(&:username)

First of all you do too much unnecessary queries here c.collect {|c| c.commenter.username} 首先,您在这里做了太多不必要的查询c.collect {|c| c.commenter.username} c.collect {|c| c.commenter.username} I think eager loading can help you. c.collect {|c| c.commenter.username}我认为热切的加载可以为您提供帮助。 Watch this http://railscasts.com/episodes/23-counter-cache-column?autoplay=true 观看此http://railscasts.com/episodes/23-counter-cache-column?autoplay=true

I figured it out using eager load, which is not the link RaskolnikOFF posted, but the rails-cast before it, http://railscasts.com/episodes/22-eager-loading (still gave you an upvote for driving me to the answer) 我使用热切的负载算出了它,这不是RaskolnikOFF发布的链接,而是之前的rails-cast, http: //railscasts.com/episodes/22-eager-loading(仍然为您提供了推动我前往回答)

Apparently what I was looking for was the following: 显然我正在寻找以下内容:

b = Blog.find(:first, :include=>{:comments => :commenter})
b.comments.collect {|c| c.commenter.username}

The first line loads the first blog and all of its relations (and returns the blog). 第一行加载第一个博客及其所有关系(并返回博客)。 So when I call the second line, everything is already loaded and waiting to be accessed.. 因此,当我拨打第二行时,所有内容均已加载并等待访问。

Which works way better than what I was originally doing. 哪种方法比我最初做的更好。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM