快速业务通道

真实世界中的Rails,第3部分: 优化ActiveRecord - 编程入门网

作者 佚名技术 来源 NET编程 浏览 发布时间 2012-06-14
ls,第3部分: 优化ActiveRecord(4) 时间:2011-11-20

由于您应该看 到针对每个地址的查询,所以就性能而言,结果并不尽如人意。清单 6 给出了问题的全部:

清单 6. N+1 问题的查询

^[[4;36;1mMember Load (0.004063)^[[0m  ^[[0;1mSELECT * FROM 

members WHERE
(members.`id` IN (1,2,3)) ^[[0m
 ^[[36;2m./vendor/plugins/paginating_find/lib/paginating_find.rb:98:in `find''^[[0m
^[[4;35;1mAddress Load (0.000989)^[[0m  ^[[0mSELECT * FROM addresses WHERE
(addresses.addressable_id = 1 AND addresses.addressable_type = ''Member'') LIMIT 1^

[[0m
 ^[[35;2m./vendor/plugins/paginating_find/lib/paginating_find.rb:98:in `find''^[[0m
^[[4;36;1mAddress Columns (0.073840)^[[0m  ^[[0;1mSHOW FIELDS FROM addresses^[[0m
^[[4;35;1mAddress Load (0.002012)^[[0m  ^[[0mSELECT * FROM addresses WHERE
(addresses.addressable_id = 2 AND addresses.addressable_type = ''Member'') LIMIT 1^

[[0m
 ^[[35;2m./vendor/plugins/paginating_find/lib/paginating_find.rb:98:in `find''^[[0m
^[[4;36;1mAddress Load (0.000792)^[[0m  ^[[0;1mSELECT * FROM addresses WHERE
(addresses.addressable_id = 3 AND addresses.addressable_type = ''Member'') LIMIT 1^

[[0m
 ^[[36;2m./vendor/plugins/paginating_find/lib/paginating_find.rb:98:in `find''^

[[0m

结果正如我所预见的那样糟糕。所有成员共用一个查询,而每个地址各用一个查询。我们 检索了三个成员,所以一共用了四个查询。如果是 N 个成员,就会有 N+1 个查询。这就是可怕的 N+1 问题。大多数持久性框架都采用热关联(eager association)来解决该问题。Rails 也不例外。如果需 要访问关系,就可以选择将其包括到初始查询中。ActiveRecord 使用 :include 选项来实现此目的。如 果将查询更改为 Member.find([1,2,3], :include => :address).each {|member| puts member.address.city},结果就会稍好一些:

清单 7. 解决 N+1 问题

^

[[4;35;1mMember Load Including Associations (0.004458)^[[0m  ^[
  [0mSELECT members.`id` AS t0_r0, members.`type` AS t0_r1,
  members.`about_me` AS t0_r2, members.`about_philanthropy`
  ...
  addresses.`id` AS t1_r0, addresses.`address1` AS t1_r1,
  addresses.`address2` AS t1_r2, addresses.`city` AS t1_r3,
  ...
  addresses.`addressable_id` AS t1_r8 FROM members
  LEFT OUTER JOIN addresses ON addresses.addressable_id
  = members.id AND addresses.addressable_type =
  ''Member'' WHERE (members.`id` IN (1,2,3)) ^[
  [0m
^[[35;2m./vendor/plugins/paginating_find/lib/paginating_find.rb:
 98:in `find''^[[0m

真实世界中的Rails,第3部分: 优化ActiveRecord(5)

时间:2011-11-20

该查询的速度也会更快。一个查询会检索所有成员和地址。这就是热关联的工作原理。

通过 ActiveRecord,还可以嵌套 :include 选项,但嵌套深度只有一级。例如,有多个 contacts 的 Member 以及有一个 address 的 Contact 就属于这种情况。如果想要为某个成员的联系人显示所有城市,就可以 使用清单 8 中所示的代码:

清单 8: 为某个成员的联系人获取城市

member = 

Member.find(1)
member.contacts.each {|contact| puts contact.address.city}

该代码应该能够工作,但必 须要针对此成员、每个联系人以及每个联系人的地址进行查询。通过用 :include => :contacts 包括 :contacts,可以稍许提高性能。也可以通过将二者都

凌众科技专业提供服务器租用、服务器托管、企业邮局、虚拟主机等服务,公司网站:http://www.lingzhong.cn 为了给广大客户了解更多的技术信息,本技术文章收集来源于网络,凌众科技尊重文章作者的版权,如果有涉及你的版权有必要删除你的文章,请和我们联系。以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢!

分享到: 更多

Copyright ©1999-2011 厦门凌众科技有限公司 厦门优通互联科技开发有限公司 All rights reserved

地址(ADD):厦门软件园二期望海路63号701E(东南融通旁) 邮编(ZIP):361008

电话:0592-5908028 传真:0592-5908039 咨询信箱:web@lingzhong.cn 咨询OICQ:173723134

《中华人民共和国增值电信业务经营许可证》闽B2-20100024  ICP备案:闽ICP备05037997号