積極的な読み込みでN+1クエリの問題を回避しようとしていますが、機能していません。関連するモデルはまだ個別にロードされています。
関連するActiveRecordsとそれらの関係は次のとおりです。
class Player < ActiveRecord::Base
has_one :tableau
end
Class Tableau < ActiveRecord::Base
belongs_to :player
has_many :tableau_cards
has_many :deck_cards, :through => :tableau_cards
end
Class TableauCard < ActiveRecord::Base
belongs_to :tableau
belongs_to :deck_card, :include => :card
end
class DeckCard < ActiveRecord::Base
belongs_to :card
has_many :tableaus, :through => :tableau_cards
end
class Card < ActiveRecord::Base
has_many :deck_cards
end
class Turn < ActiveRecord::Base
belongs_to :game
end
私が使用しているクエリは、Playerのこのメソッド内にあります。
def tableau_contains(card_id)
self.tableau.tableau_cards = TableauCard.find :all, :include => [ {:deck_card => (:card)}], :conditions => ['tableau_cards.tableau_id = ?', self.tableau.id]
contains = false
for tableau_card in self.tableau.tableau_cards
# my logic here, looking at attributes of the Card model, with
# tableau_card.deck_card.card;
# individual loads of related Card models related to tableau_card are done here
end
return contains
end
それはスコープと関係がありますか?このtableau_containsメソッドは、より大きなループでいくつかのメソッド呼び出しを実行します。これらの同じオブジェクトがループされて調べられる場所がいくつかあるため、最初は積極的な読み込みを試みました。次に、ループの直前にロードを使用して、最終的に上記のコードを試しましたが、ログのtableau_cardsループ内のCardに対する個々のSELECTクエリがまだ表示されています。tableau_cardsループの直前にもIN句を使用した遅延読み込みクエリが表示されます。
編集:より大きな外側のループを含む以下の追加情報
EDIT2:回答からのヒントで以下のループを修正
EDIT3:目標を含むループに詳細を追加
これがより大きなループです。after_saveのオブザーバー内にあります
def after_save(pa)
turn = Turn.find(pa.turn_id, :include => :player_actions)
game = Game.find(turn.game_id, :include => :goals)
game.players.all(:include => [ :player_goals, {:tableau => [:tableau_cards => [:deck_card => [:card]]]} ])
if turn.phase_complete(pa, players) # calls player.tableau_contains(card)
for goal in game.goals
if goal.checks_on_this_phase(pa)
if goal.is_available(players, pa, turn)
for player in game.players
goal.check_if_player_takes(player, turn, pa)
... # loop through player.tableau_cards
end
end
end
end
end
end
ターンクラスの関連コードは次のとおりです。
def phase_complete(phase, players)
all_players_complete = true
for player in players
if(!player_completed_phase(player, phase))
all_players_complete = false
end
end
return all_players_complete
end
for player in game.players
プレーヤーをロードするために別のクエリを実行しています。キャッシュされます。つまり、ログにCACHEラベルがありますが、game.playersはすでにメモリにロードされているはずなので、クエリはまったくないと思います。
目標モデルからの別のスニペット:
class Goal < ActiveRecord::Base
has_many :game_goals
has_many :games, :through => :game_goals
has_many :player_goals
has_many :players, :through => :player_goals
def check_if_player_takes(player, turn, phase)
...
for tab_card in player.tableau_cards
...
end
end