2012-08-14 114 views

回答

47

Rails有兩種避免n + 1問題的方法。其中一個涉及創建一個基於聯接的大查詢來引入您的關聯,另一個涉及爲每個關聯進行單獨的查詢。

當您做includes時,ra​​ils會決定使用哪種策略。它默認爲單獨的查詢方法(預加載),除非它認爲您正在使用來自條件或訂單中的關聯的列。由於這隻適用於連接方法,所以它使用它。

Rails的啓發式檢查有時會出錯,或者您可能有一個偏好某種方法的特定原因。 preload(及其配套方法eager_load)允許您指定希望使用哪種策略。

+0

真棒 - 一個模糊的,沒有記錄的ActiveRecord角落。感謝閃耀一些光! – Phantomwhale 2012-08-15 05:57:35

+3

此博客討論相同的主題http://blog.bigbinary。com/2013/07/01/preload-vs-eager-load-vs-joins-vs-includes.html – 2013-07-04 18:11:00

+2

此博客文章非常有用和清晰http://blog.arkency.com/2013/12/rails4-預加載/ – 2014-06-10 10:14:58

-3

正如apidoc所說:「此方法已被棄用或移到最新的穩定版本上,最新的現有版本(v3.0.9)顯示在這裏。」所以區別在於,只包括NOT不推薦。

+3

'不推薦或移動'。在這種情況下,它已被移動,未被棄用。他們不一樣。 – 2012-08-14 07:03:39

+0

對不起,但如果我有可能調用它(Rails 3.2.6),它不會移動我 - 只是棄用。 – freeze 2012-08-14 08:40:46

+2

當人們將代碼從一個模塊重構到另一個模塊時,apidoc變得非常混亂 - 它可以認爲即使從公共api的角度來看,它也沒有移動 – 2012-08-14 11:16:08

0

詳細瞭解請參閱this博客。

在短褲:

預壓加載在一個單獨的查詢的關聯數據。

User.preload(:posts).to_a 

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

包括負載關聯數據在一個單獨的查詢就像 預緊力。然而,它是更智能preload。但在某些情況下,它會結合查詢。

如何包括更聰明?

我們不能使用郵政局在哪裏條件。以下查詢將導致錯誤。

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') 

但我們可以使用交表在查詢包括

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") 

正如你可以看到包括使用兩個單獨的查詢,以創建一個單一LEFT OUTER開關JOIN得到數據。並且它也應用了提供的條件。