初使用 AR 的关联,比如我有一个表 book 和 master,每本书有一个主人,我要列出 20 本书,同时列出主人的名字
我就在 book 表里用了belongs_to :master
,然后找出 20 条数据,结果在输出时看到了足足 21 条 SQL
到底是不是我用错了,或者我用的时机不对?否则效率未免太低了点吧,要是我要显示 100 本书那不是要 101 条 SQL 了?
麻烦解惑,万分感谢!
关联本身只管定义关系,性能什么的他不会关心。你这是典型的 n + 1 问题,一条 SQL 查出所有 book,20 条 SQL 对每个 book 查出它的 master。 用 include 可以解决你所说的问题。
Book.include(:master).all
生成的 SQL 你自己看看,很好懂的。
通常的想法是查询多导致效率低,但 robbin 最近写的 blog 谈到这个问题,有不一样的见解 http://robbinfan.com/blog/38/orm-cache-sumup
摘录一段:
总结来说,ORM缓存的基本理念是:
以减少数据库服务器磁盘IO为最终目的,而不是减少发送到数据库的SQL条数。实际上使用ORM,会显著增加SQL条数,有时候会成倍增加SQL。
数据库schema设计的取向是尽量设计 细颗粒度 的表,表和表之间用外键关联,颗粒度越细,缓存对象的单位越小,缓存的应用场景越广泛
尽量避免多表关联查询,尽量拆成多个表单独的主键查询,尽量多制造 n + 1 条查询,不要害怕“臭名昭著”的 n + 1 问题,实际上 n + 1 才能有效利用ORM缓存
谢谢几位的回答,看了 Robin 的文章,受益良多
不过@darkbaby123 说的方法,我试了下,并不能成立,报错说“include”是私有方法,是我的 Rails 版本问题?
Ruby 1.9.3 Rails 3.2.12
@milk ,用 rails 3 API 会比较好,这样写:
Book.includes(:master)
P.S. 通常情况下我不会用 all,all 会直接读数据库并返回一个 array,而像includes
和where
等 rails 3 API 会等到真正需要读数据的时候才去查询数据库