在Ruby on Rails中优化ActiveRecord的方法

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

清单 1. 在迁移中创建索引

class AddIndexesToUsers < ActiveRecord::Migration
 def self.up
  add_index :members, :login
  add_index :members, :email
  add_index :members, :first_name
  add_index :members, :last_name
 end

 def self.down
  remove_index :members, :login
  remove_index :members, :email
  remove_index :members, :first_name
  remove_index :members, :last_name
 end
end

ActiveRecord 会负责 id 上的索引,我显式地添加了可在各种搜索中使用的索引,原因是此表很大、不经常更新却经常被搜索。通常,我们会等到对给定的查询中的问题有一定的把握后才会采取相应动作。这种策略可以让我们不必二次猜测数据库引擎。但从用户这方面来看,我们知道该表将会很快具有数百万的用户,如果在经常搜索的列上没有索引,该表的效率会很低。

另外两个常见问题也与迁移有关。如果字符串和列都不应该为空,那么就请确保正确编写了迁移。大多数 DBA(数据库管理员)都会认为 Rails 为空列提供了错误的默认属性:默认情况下列可以为空。如果希望创建一个不能为空的列,您必须显式地添加参数 :null => false。如果具有字符串列,请务必确保编写应用程序的限值。默认地,Rails 迁移会将 string 列按 varchar(255) 编码。通常,这个值过于庞大。应该尽量保持能如实反应应用程序的数据库结构。与提供无任何限制的 login 相反,如果应用程序限制 login 只能为 10 个字符,那么就应该相应地编写数据库,如清单 2 所示:
清单 2. 用限值和非空列编写迁移

t.column :login, :string, :limit => 10, :null => false

此外,还应该考虑默认值以及其他任何能安全提供的信息。通过一点预备工作,就可以节省日后跟踪数据完整性问题的大量时间。在考虑数据库基础的同时,还应该注意哪些页是静态且容易缓存的。在优化查询和缓存页面这两个选项当中,如果您能 “消受” 复杂性,缓存页面将会带来更大的回报。有时,页面或片段都是纯静态的,比如一列状态或一组经常问到的问题。在这种情况下,缓存更胜一筹。而在其他的一些时候,您可能会决定牺牲数据库性能,以减少复杂性。对于 ChangingThePresent,根据问题和环境的具体情况,我们二者都尝试了。如果您也决定要牺牲查询性能,就请继续阅读吧。
N+1 问题

默认情况下,ActiveRecord 关系十分懒散。这意味着框架会一直等待访问关系直到您实际访问了该关系。比方说,每个成员都会有一个地址。可以打开一个控制台并输入如下命令:member = Member.find 1。可以看到追加到日志的如下内容,如清单 3 所示:
清单 3. 从 Member.find(1) 登录

^[[4;35;1mMember Columns (0.006198)^[[0m  ^[[0mSHOW FIELDS FROM members^[[0m
^[[4;36;1mMember Load (0.002835)^[[0m  ^[[0;1mSELECT * FROM members WHERE
 (members.`id` = 1) ^[[0m