Я все еще изучаю рубин, рельсы и ActiveRecord каждый день. Сейчас я изучаю SQL через новое небольшое приложение, которое я создаю, но проблема в том, что основной вид моего приложения в настоящее время составляет ~ 2000 запросов на обновление страницы, oouuuppps.Как оптимизировать этот запрос ActiveRecord?
Итак, теперь, когда я знаю, что у меня есть вся необходимая информация в моей БД и что я могу отображать их правильно, мне пора оптимизировать их, но я просто не знаю, с чего начать честно.
Это мои модели объединения
class League < ActiveRecord::Base
belongs_to :user
has_many :league_teams
has_many :teams, :through => :league_teams
end
class Team < ActiveRecord::Base
has_many :gameweeks
has_many :league_teams
has_many :leagues, :through => :league_teams
end
class Gameweek < ActiveRecord::Base
belongs_to :team
has_and_belongs_to_many :players
has_and_belongs_to_many :substitutes, class_name: "Player", join_table: "gameweeks_substitutes"
belongs_to :captain, class_name: "Player"
belongs_to :vice_captain, class_name: "Player"
end
class Player < ActiveRecord::Base
serialize :event_explain
serialize :fixtures
serialize :fixture_history
has_many :gameweeks, class_name: "captain"
has_many :gameweeks, class_name: "vice_captain"
has_and_belongs_to_many :gameweeks
has_many :player_fixtures
end
Так что это мой контроллер:
@league = League.includes(teams: [{gameweeks: [{players: :player_fixtures} , :captain]}]).find_by(fpl_id:params[:fpl_id])
@teams = @league.teams
@defense_widget_leaderboard = @league.position_based_leaderboard_stats(@teams, ['Defender', 'Goalkeeper'])
И это одна из метода в моей модели Лиги:
def position_based_leaderboard_stats(teams,positions_array)
leaderboard = []
teams.each do |team|
position_points = 0
gameweeks = team.gameweeks
gameweeks.each do |gameweek|
defense = gameweek.players.where(type_name:positions_array)
defense.each do |player|
player.player_fixtures.where(gw_number: gameweek.number).each do |p|
position_points += p.points
end
end
end
leaderboard << [team.team_name,position_points]
end
return leaderboard.sort_by {|team| team[1]}.reverse
end
У меня есть 4 метода, которые выглядят более или менее то же, что и выше. Каждый из них выполняет от 300 до 600 запросов.
Насколько я понимаю, это типичный случай N + 1 запросов. Я попытался уменьшить с помощью включений в @league, но это заставило меня отказаться от 2000 до 1800 запросов.
Я просмотрел group_by
, joins
и sum
, но я не смог заставить его работать.
Ближе всего я должен работать был этот
players = PlayerFixture.group("player_id").sum(:points)
Где я мог бы запросить, делая players[player.id]
, но это не дает мне правильные результаты в любом случае, потому что он не принимает во внимание в Gameweeks> Игроки> Player_fixtures отношения.
Как уменьшить количество запросов, которые я выполняю? Я пошел на #RubyOnRails на Freenode и люди говорили мне, что это может быть сделано в 1 запрос, но не будет указывать мне в любых направлениях или помочь мне ...
Благодарности
Только что попробовал, и это ничего не меняет. Метод все еще выполняет ~ 640 запросов. – Syl
Я сделал опечатку: она должна быть (gameweeks:: players) вместо (gameweeks: players). Вы исправились? – hedgesky
Да, я исправил вашу опечатку. Все еще ничего не меняет на количество запросов: / – Syl