2

has_one 関連付けが設定されたモデルがあります。

class User
  has_one :shirt

class Shirt
  belongs_to :user

現時点では.includes(:shirt)、ユーザーの限られた配列を取得するときに追加でき、期待どおりに 2 つの SQL クエリを実行します。

私たちにとっての問題は、ページをロードするためのクエリがこれを行っていることです。

SELECT "shirt".* FROM "shirts" WHERE "shirt"."user_id" IN (2147521, 2147522 ... )

たとえば、50 人のユーザーとシャツを取得する場合、これはあまりパフォーマンスが高くありません。私たちのユーザーとシャツのテーブルは大きいです。次のようにして、Rails に強制的に INNER JOIN を使用させることで、速度が大幅に向上することに気付きました。

User.where( ... ).joins(:shirts).includes(:shirts).limit(50)

残念ながら、これはシャツを持っているユーザーのみを返します。関連するシャツを持っているかどうかに関係なく、限られたユーザーの配列を返すことができる必要があります。

デフォルトの2クエリ方式の代わりにLEFT OUTER JOINを使用してRailsに関連付けられたオブジェクトを熱心にロードさせる方法はありますか?

編集

where関連付けられたオブジェクトの値が null かどうかにかかわらず true を返す句を追加します。関連付けられたオブジェクトがなくても、少なくとも Postgres では問題ないようです。

User.where( ... ).includes(:shirt).where("shirts.created_at IS NULL OR shirts.created_at IS NOT NULL")

これで問題は解決しますが、理想的とは言えません。デフォルトの 2 クエリ アプローチの代わりに LEFT OUTER JOIN を使用する方法はありませんか?

4

3 に答える 3

2

この投稿で説明されているように、ほとんどの場合、2 クエリ アプローチの方が高速であると考えられています (ただし、1 対 1 の関係の場合は必ずしもそうとは限りません)。Rails に LEFT OUTER JOIN を強制的に使用させたい場合は、関連するテーブルに無意味なフィルターを追加することでこれを行うことができます。

User.where( ... ).
     includes(:shirts).
     where("shirts.id IS NULL OR shirts.id = shirts.id").
     limit(50)
于 2012-12-17T18:01:30.827 に答える
0

Rails4 への適用:

User.where( ... ).includes(:shirts).references(:shirts)

また

User.where( ... ).eager_load(:shirts)

LEFT OUTER JOINかなり別のクエリを強制します

于 2015-03-02T19:14:06.157 に答える