在Ruby on Rails中优化ActiveRecord的方法

2019-09-25 09:43:54丽君

^[[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

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

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

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

该代码应该能够工作,但必须要针对此成员、每个联系人以及每个联系人的地址进行查询。通过用 :include => :contacts 包括 :contacts,可以稍许提高性能。也可以通过将二者都包括进来进一步地改进,如清单 9 所示:
清单 9: 为某个成员的联系人获取城市

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

通过使用嵌套包含选项还能获得更好的改进:

member = Member.find(1, :include => {:contacts => :address})
member.contacts.each {|contact| puts contact.address.city}

该嵌套包含可让 Rails 热包含 contacts 和 address 关系。一旦要在给定的查询中使用关系,就可以采用热加载技术。此技术是我们在 ChangingThePresent.org 中使用得最为频繁的一种性能优化技术,但它还是有一些限制的。当必须要连接两个以上的表时,最好还是采用 SQL。如果需要进行报告,最好是简单地采取数据库连接,跨过 ActiveRecord 以及 ActiveRecord::Base.execute("SELECT * FROM...")。通常来讲,热关联足够解决问题。现在,我将转变话题,探讨 Rails 开发人员所关心的另一个麻烦问题:继承。
继承和 Rails

当大多数 Rails 开发人员第一次接触到 Rails 时,他们就会立刻被迷住。它太简单了。您只需在数据库表上创建一个 type 类,然后再从父类中继承子类即可。Rails 会负责其余的事情。比如,有一个名为 Customer 表,它可以从名为 Person 类继承。一个客户可以有 Person 的所有列,外加信誉度和订购历史。清单 10 显示了该种解决方案的简洁之美。主表具有父类和子类的所有列。