诗歌rails之 Plugin to kill N+1 queries

Hi guys,

I wrote a plugin to kill the N+1 queries, it works very well and maybe helpful to you. The site of the plugin is http://github.com/flyerhzm/bullet. The README is good to explain how to use the plugin and the spec/bullet_association_spec.rb show you what are N+1 queries and what are not.

I will still give you an quick example to show how to use the plugin step by step:

1. setup test environment

Bash代码
  1. $ rails test   
  2. $ cd test   
  3. $ script/generate scaffold post name:string   
  4. $ script/generate scaffold comment name:string post_id:integer   
  5. $ rake db:migrate   
$ rails test 
$ cd test 
$ script/generate scaffold post name:string 
$ script/generate scaffold comment name:string post_id:integer 
$ rake db:migrate 


2. change app/model/post.rb and app/model/comment.rb

Ruby代码
  1. class Post < ActiveRecord::Base   
  2.   has_many :comments   
  3. end   
  4.   
  5. class Comment < ActiveRecord::Base   
  6.   belongs_to :post   
  7. end   
class Post < ActiveRecord::Base 
  has_many :comments 
end 

class Comment < ActiveRecord::Base 
  belongs_to :post 
end 


3. go to script/console and execute

Ruby代码
  1. post1 = Post.create(:name => 'first')   
  2. post2 = Post.create(:name => 'second')   
  3. post1.comments.create(:name => 'first')   
  4. post1.comments.create(:name => 'second')   
  5. post2.comments.create(:name => 'third')   
  6. post2.comments.create(:name => 'fourth')   
post1 = Post.create(:name => 'first') 
post2 = Post.create(:name => 'second') 
post1.comments.create(:name => 'first') 
post1.comments.create(:name => 'second') 
post2.comments.create(:name => 'third') 
post2.comments.create(:name => 'fourth') 


4. change the app/views/posts/index.html.erb to generate a N+1 query

Rhtml代码
  1. <h1>Listing posts</h1>   
  2.   
  3. <table>   
  4.   <tr>   
  5.     <th>Name</th>   
  6.   </tr>   
  7.   
  8.   <% @posts.each do |post| %>   
  9.   <tr>   
  10.     <td><%=h post.name %></td>   
  11.     <td><%= post.comments.collect(&:name) %></td>   
  12.     <td><%= link_to 'Show', post %></td>   
  13.     <td><%= link_to 'Edit', edit_post_path(post) %></td>   
  14.     <td><%= link_to 'Destroy', post, :confirm => 'Are you sure?', :method => :delete %></td>   
  15.   </tr>   
  16.   <% end %>   
  17. </table>   
  18.   
  19. <br />   
  20.   
  21. <%= link_to 'New post', new_post_path %>   
<h1>Listing posts</h1> 

<table> 
  <tr> 
    <th>Name</th> 
  </tr> 

  <% @posts.each do |post| %> 
  <tr> 
    <td><%=h post.name %></td> 
    <td><%= post.comments.collect(&:name) %></td> 
    <td><%= link_to 'Show', post %></td> 
    <td><%= link_to 'Edit', edit_post_path(post) %></td> 
    <td><%= link_to 'Destroy', post, :confirm => 'Are you sure?', :method => :delete %></td> 
  </tr> 
  <% end %> 
</table> 

<br /> 

<%= link_to 'New post', new_post_path %> 


5. add bullet plugin

Bash代码
  1. $ script/plugin install git://github.com/flyerhzm/bullet.git   
$ script/plugin install git://github.com/flyerhzm/bullet.git 


6. enable the bullet plugin in development, add a line to config/environments/development.rb

Ruby代码
  1. Bullet.enable = true   
Bullet.enable = true 


7. start server

Bash代码
  1. $ script/server   
$ script/server 


8. input http://localhost:3000/posts in browser, then you will see a popup alert box says

The request has N+1 queries as follows:
model: Post => associations: [comment]

which means there is a N+1 query from post object to comments associations.

In the meanwhile, there's a log appended into log/bullet.log file

2009-08-17 15:07:31[INFO] N+1 Query: PATH_INFO: /posts; model: Post => assocations: [comments]

The generated SQLs are

Post Load (1.0ms) SELECT * FROM "posts" Comment Load (0.4ms) SELECT * FROM "comments" WHERE ("comments".post_id = 1)
Comment Load (0.3ms) SELECT * FROM "comments" WHERE ("comments".post_id = 2)

9. fix the N+1 query, change app/controllers/posts_controller.rb file

Ruby代码
  1. def index   
  2.   @posts = Post.find(:all:include => :comments)   
  3.   
  4.   respond_to do |format|   
  5.     format.html # index.html.erb   
  6.     format.xml { render :xml => @posts }   
  7.   end   
  8. end   
def index 
  @posts = Post.find(:all, :include => :comments) 

  respond_to do |format| 
    format.html # index.html.erb 
    format.xml { render :xml => @posts } 
  end 
end 


10. refresh http://localhost:3000/posts page, no alert box and no log appended.

The generated SQLs are

Post Load (0.5ms) SELECT * FROM "posts"
Comment Load (0.5ms) SELECT "comments".* FROM "comments" WHERE ("comments".post_id IN (1,2))

a N+1 query fixed. Cool!

Hope you like the plugin!

转载于:https://www.cnblogs.com/orez88/articles/1552681.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值