Rails 提供了四种不同加载关联数据的方法。下面就来介绍一下。

一、Preload

Preload 是以附加一条查询语句来加载关联数据的

 User.preload(:posts).to_a

 # =>
SELECT "users".* FROM "users"
SELECT "posts".* FROM "posts" WHERE "posts"."user_id" IN (1)

这种方式与是 includes 默认加载数据的方式

由于 preload 总是生成两条 sql,所以不能在后面使用 where 条件,下面的查询会报错

User.preload(:posts).where("posts.desc='ruby is awesome'")

# =>
SQLite3::SQLException: no such column: posts.desc:
SELECT "users".* FROM "users" WHERE (posts.desc='ruby is awesome')

在 preload 的 where 条件只能这样使用

User.preload(:posts).where("users.name='Neeraj'")

# =>
SELECT "users".* FROM "users" WHERE (users.name='Neeraj')
SELECT "posts".* FROM "posts" WHERE "posts"."user_id" IN (3)

二、Includes

默认情况下 Includes 加载关联数据和 preload 一样

但它比 preload 要聪明一些。上面看到关于 preload 的查询 User.preload(:posts).where("posts.desc='ruby is awesome'") 会失败。下面看看 includes:

User.includes(:posts).where('posts.desc = "ruby is awesome"').to_a

# =>
SELECT "users"."id" AS t0_r0, "users"."name" AS t0_r1, "posts"."id" AS t1_r0,
"posts"."title" AS t1_r1,
"posts"."user_id" AS t1_r2, "posts"."desc" AS t1_r3
FROM "users" LEFT OUTER JOIN "posts" ON "posts"."user_id" = "users"."id"
WHERE (posts.desc = "ruby is awesome")

这里你可以看到 includes 把两条分开的 SQL 用 LEFT OUTER JOIN 生成一条数据,并且它还包括了 where 条件

所以在一些情况下 includes 把两条语句合成一条。但最简单情况下它是使用两条的。但如果你就想要 includes 使用一条 sql 语句, references 可以做到:

User.includes(:posts).references(:posts).to_a

# =>
SELECT "users"."id" AS t0_r0, "users"."name" AS t0_r1, "posts"."id" AS t1_r0,
"posts"."title" AS t1_r1,
"posts"."user_id" AS t1_r2, "posts"."desc" AS t1_r3
FROM "users" LEFT OUTER JOIN "posts" ON "posts"."user_id" = "users"."id"

上面只会生成一条 sql

三、Eager load

eager loading 是以 LEFT OUTER JOIN 加载所有相关数据的。

User.eager_load(:posts).to_a

# =>
SELECT "users"."id" AS t0_r0, "users"."name" AS t0_r1, "posts"."id" AS t1_r0,
"posts"."title" AS t1_r1, "posts"."user_id" AS t1_r2, "posts"."desc" AS t1_r3
FROM "users" LEFT OUTER JOIN "posts" ON "posts"."user_id" = "users"."id"

它正是 includes 使用 where 或 order 从 posts表中获取数据时强制生成一条 sql 的情况。

四、Joins

Joins 方式是使用 inner join 加载关联数据

User.joins(:posts)

# =>
SELECT "users".* FROM "users" INNER JOIN "posts" ON "posts"."user_id" = "users"."id"

上面的情况下 posts 数据不会被查询出来,它会得到重复数据。举个例子:

def self.setup
User.delete_all
Post.delete_all u = User.create name: 'Neeraj'
u.posts.create! title: 'ruby', desc: 'ruby is awesome'
u.posts.create! title: 'rails', desc: 'rails is awesome'
u.posts.create! title: 'JavaScript', desc: 'JavaScript is awesome' u = User.create name: 'Neil'
u.posts.create! title: 'JavaScript', desc: 'Javascript is awesome' u = User.create name: 'Trisha'
end

上面的测试数据运行之后会得到:

#<User id: 9, name: "Neeraj">
#<User id: 9, name: "Neeraj">
#<User id: 9, name: "Neeraj">
#<User id: 10, name: "Neil">

我们可以使用 distinct 来去重:

User.joins(:posts).select('distinct users.*').to_a

如果想要 posts 表的数据也可以 select 出来

records = User.joins(:posts).select('distinct users.*, posts.title as posts_title').to_a
records.each do |user|
puts user.name
puts user.posts_title
end

注意:在应用 joins 查询数据的时候使用 user.posts 会生成另外一个 sql 语句

原文地址:

http://blog.bigbinary.com/2013/07/01/preload-vs-eager-load-vs-joins-vs-includes.html

最新文章

  1. DNS反射攻击阻止
  2. UVA 1351 十三 String Compression
  3. sftp
  4. 记一次Surface Pro 2还原操作
  5. Quartz 第二课 Jobs and Triggers(官方文档翻译)
  6. [Excel] C#GridViewExport帮助类,美化导出 (转载)
  7. 不用不知道 apply()与call()的强大
  8. Java NIO——2 缓冲区
  9. 使用Spring MVC构建REST风格WEB应用
  10. JQuery坑,说说哪些大家都踩过的坑
  11. 基本urllib库
  12. 创建数组必须指定数组数目之new运算符避免这种限制
  13. 4.4Python数据处理篇之Matplotlib系列(四)---plt.bar()与plt.barh条形图
  14. JMeter命令行监控CPU和内存资源
  15. SpringBatch Sample (三)(XML文件操作)
  16. python中画散点图
  17. Flex 确定弹出窗口的绝对位置x , y
  18. Easyui combobox onChange事件
  19. Visual Studio 2017(VS2017) 企业版 Enterprise 注册码
  20. c语言中变量/函数命名以单下划线(_)和双下划线(__) 开头的意义

热门文章

  1. Ural State University Internal Contest October&#39;2000 Junior Session
  2. Codeforces 396A 数论,组合数学
  3. 【遥感专题系列】微波遥感(二、合成孔径雷达SAR基础)
  4. 使用vba doc转docx
  5. javascript操作Date对象
  6. POJ 2533 Longest Ordered Subsequence(裸LIS)
  7. c语言描述的数据结构的注意细节
  8. c语言描述的直接插入排序法
  9. 原 史上最简单的SpringCloud教程 | 第八篇: 消息总线(Spring Cloud Bus)(Finchley版本)
  10. 使用actionerror做失败登录验证