你可以把它全部合併到這樣一個查詢:
Plant.joins(:name, :location).where(names: { common_name: "rose" }, locations: { bed_name: "side" })
這導致單個SQL查詢是這樣的:
SELECT "plants".* FROM "plants" INNER JOIN "names" ON "names"."id" = "plants"."name_id" INNER JOIN "locations" ON "locations"."id" = "plants"."location_id" WHERE "names"."common_name" = 'rose' AND "locations"."bed_name" = 'side'
請注意,你必須使用複數表where
子句中的名稱,但joins
子句中的單數協會名稱。
即使有大量表格,這也會幾乎即時運行,假設您的表格已正確編制索引。
這是一個簡單的例子,但您可以使用條件進行相當複雜的連接。全部細節可在ActiveRecord documentation中找到。
編輯
每@丹的評論,你可以加快這更用includes
預取的相關數據加入:
Plant.includes(:name, :location).where(names: { common_name: "rose" }, locations: { bed_name: "side" })
這將加載相關記錄names
和locations
。includes
便於消除(或至少減少)N + 1個查詢。它還足夠聰明,可以知道何時可以在單個查詢中檢索所有數據,並在更有意義時回退到多個查詢;你不必考慮它(儘管有時它會降低效率,所以如果你認爲它會降低性能,請留意你的日誌)。
使用includes
在這種情況下是非常有效的,結果是一個SQL查詢,其中包括關聯數據:
SELECT "plants"."id" AS t0_r0, "plants"."color" AS t0_r1, "plants"."name_id" AS t0_r2, "plants"."location_id" AS t0_r3, "plants"."created_at" AS t0_r4, "plants"."updated_at" AS t0_r5, "names"."id" AS t1_r0, "names"."common_name" AS t1_r1, "names"."created_at" AS t1_r2, "names"."updated_at" AS t1_r3, "locations"."id" AS t2_r0, "locations"."bed_name" AS t2_r1, "locations"."created_at" AS t2_r2, "locations"."updated_at" AS t2_r3 FROM "plants" LEFT OUTER JOIN "names" ON "names"."id" = "plants"."name_id" LEFT OUTER JOIN "locations" ON "locations"."id" = "plants"."location_id" WHERE "names"."common_name" = 'rose' AND "locations"."bed_name" = 'side'
不知道我怎麼錯過了嵌套的語法,但它正是我需要的!我的查詢已經從6000ms到60ms! :) – Ben
您可能會考慮添加'.includes(:name,:location)'以進一步提高性能。以下是關於這個主題的進一步閱讀:https://code.tutsplus.com/articles/improving-the-performance-of-your-rails-app-with-eager-loading--cms-25018 – Dan
謝謝@Dan ,這樣好多了。 –