次のような単一のクエリにそれをすべて組み合わせることができます。
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個のクエリを排除する(または少なくとも減らす)のに便利です。また、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
ありがとう@ダン、それははるかに良い方法。 –