2017-07-21 13 views
0

私のコードでは、2つのモデル(投稿やコメントなど)を結合してから、3番目のモデル(作成者など)を読み込むことができます。私は各レコードを印刷するときレールは、ポストの最初のインスタンスの熱心に読み込まれたモデルデータを使用しますが、ポストの追加のインスタンスごとに追加のデータベースクエリをトリガします。これはn + 1の問題のビットです。返されたレコードごとに結合後、熱心に読み込まれたデータを使用するにはどうすればよいですか?

私が理解できないのは、なぜ私は、各投稿の最初のレコードには熱心に読み込まれたデータを使用でき、結合によって返された追加のレコードは使用できないのですか?

私は同様の質問を見てきましたが、まったく同じ問題をこれらのアドレスで感じることはありません。これらを含める:

私はまた、具体的ActiveRecord::Associations::Preloader、レールのソースコードに見てきたとするビットローカルに変更しようとしています問題がどこにあるのか、ここで発生するのかを絞り込むことができるかどうかを確認してください。私はおそらくこのクラスがidによって一意ではないレコードインスタンスを取り除いていると考えていましたが(これは92行目だと思います)、私がこれを変更すると私の問題は解決されません。

私はwhacky edge caseに当てはまりましたが、実際のコードではfind_by_sqlを使用しており、これを効果的に実装することができませんでした。

私はgist with steps to reproduce the issueを作成しました。どんな助けもありがとう。

注:この例は、実際のコードで同じ問題が発生していることを示す最も簡単な設定です。私の例では、私はコメントと作者を熱心に読み込むことができますが、実際のコードではもっと複雑な結合があり、結合が必要です。私はこの例からCommentモデルを熱心に読み込むことはできません。

答えて

0

これを将来的に見つけた人にとっては、私が見つけたものと実装したものがあります。私の要旨に概説され、簡単な例

簡単な要旨の例では、私は望ましい結果は以下の変更も得ることができることを見出しました。

要旨:私は、追加のクエリなしで望んでいた結果を得るauthorに参加することで

# Works as expected. 
posts = Post.joins(:comments, :author).select("posts.*, comments.body").includes(:author) 
posts.each do |x| 
    puts "#{x.title} #{x.author.name} #{x.body}" 
end 

# Triggers n+1 for author after first puts of an author. 
posts = Post.joins(:comments).select("posts.*, comments.body").includes(:author) 
posts.each do |x| 
    puts "#{x.title} #{x.author.name} #{x.body}" 
end 

に変更。

より複雑な例と実施

上記は私のより複雑な現実世界の問題で、私は私の問題を実証するために使用される私の簡単な例を解決しますが(私の質問で述べたように)私は、この追加を実装することができませんでした物事を解決するために参加する。

代わりに、この偉大なThoughbot postとgithubのレールハンドブック(Query Object PatternDecorator Pattern)に概説されているように、クエリオブジェクトパターンとデコレータパターンを実装しました。

これらのパターンを使用すると、わたしが望んでいた特定の関連付けをロードするだけでなく、はるかに複雑なクエリのすべての利点を得ることができました。

関連する問題