Несколько запросов в активной записи - PullRequest
0 голосов
/ 26 декабря 2018

Если я запускаю этот запрос в консоли rails,

def c
  ids = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
  users = User.all
  members = Member.where(id: ids).includes(:locations)
  user_id_to_member_id_mapping = {} # Not empty. hash that gives member_id for each userid  
  users.each do |user|
    puts members.find_by(id: user_id_to_member_id_mapping[user.id]).location
  end
end

запускается несколько запросов (запросов объектов-членов) (по одному для каждого значения i).Члены уже находятся в памяти (members переменная)?Как я могу получить данные, необходимые выше, чтобы сделать один запрос?

Member Load (0.2ms)  SELECT  `members`.* FROM `members` WHERE `members`.`id` IN (1, 2, 3, 4, 5, 6, 7, 8, 9, 10) AND `members`.`id` = 1 LIMIT 1
  ProfileAnswer Load (0.4ms)  SELECT `profile_answers`.* FROM `profile_answers` WHERE `profile_answers`.`member_id` = 1
  Member Load (0.4ms)  SELECT  `members`.* FROM `members` WHERE `members`.`id` IN (1, 2, 3, 4, 5, 6, 7, 8, 9, 10) AND `members`.`id` = 2 LIMIT 1
  ProfileAnswer Load (0.2ms)  SELECT `profile_answers`.* FROM `profile_answers` WHERE `profile_answers`.`member_id` = 2
  Member Load (0.2ms)  SELECT  `members`.* FROM `members` WHERE `members`.`id` IN (1, 2, 3, 4, 5, 6, 7, 8, 9, 10) AND `members`.`id` = 3 LIMIT 1
  ProfileAnswer Load (0.2ms)  SELECT `profile_answers`.* FROM `profile_answers` WHERE `profile_answers`.`member_id` = 3
  Member Load (0.2ms)  SELECT  `members`.* FROM `members` WHERE `members`.`id` IN (1, 2, 3, 4, 5, 6, 7, 8, 9, 10) AND `members`.`id` = 4 LIMIT 1
  ProfileAnswer Load (0.2ms)  SELECT `profile_answers`.* FROM `profile_answers` WHERE `profile_answers`.`member_id` = 4
  Member Load (0.2ms)  SELECT  `members`.* FROM `members` WHERE `members`.`id` IN (1, 2, 3, 4, 5, 6, 7, 8, 9, 10) AND `members`.`id` = 5 LIMIT 1
  ProfileAnswer Load (0.2ms)  SELECT `profile_answers`.* FROM `profile_answers` WHERE `profile_answers`.`member_id` = 5
  Member Load (0.4ms)  SELECT  `members`.* FROM `members` WHERE `members`.`id` IN (1, 2, 3, 4, 5, 6, 7, 8, 9, 10) AND `members`.`id` = 6 LIMIT 1

Я не могу использовать member.each, поскольку итератор находится в другом состоянии.

Ответы [ 4 ]

0 голосов
/ 26 декабря 2018

Ваш код будет запускать запрос для каждой Member загрузки из-за строки

members.find_by(id: ids[i]).location

Здесь вы явно использовали find_by, который запускает запрос для каждого члена также для определения местоположения.

Если уменьшение запроса является приоритетным, тогда вы можете использовать ruby ​​здесь

def c
  ids = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
  users = User.all
  members = Member.where(id: ids).includes(:locations)
  user_id_to_member_id_mapping = {} # Not empty. hash that gives member_id for each userid  
  users.each do |user|
   puts members.find { |m| m.id == user_id_to_member_id_mapping[user.id] }&.location
end

Обратите внимание, что это повлияет на вашу производительность, если число участников будет очень высоким.

0 голосов
/ 26 декабря 2018

Предполагается, что по вашему коду у вас есть модель Location с именем таблицы 'profile_answers'.

Участник имеет много profile_answers и имеет много мест через profile_answers.

Тогда,

members = Members.includes(profile_answers: :locations).where(id: ids)
0 голосов
/ 26 декабря 2018

members является областью применения.members.find_by выполняет запрос по области.Следовательно N+1.

Вы хотите вместо:

members =
  Member.
    where(id: ids).
    includes(:locations).
    to_a # greedy load

puts members.map(&:location) # or whatever
0 голосов
/ 26 декабря 2018

Если location - модель, вы должны использовать включает;includes запустит запрос, чтобы получить ваши исходные данные model и включенные модели

program = Program.first
ids = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
members = Members.includes(:locations).where(id: ids)

Теперь, когда вы получите первых членов, вызов его местоположения будет считан из памяти.

Если location является столбцом, и вы хотите загрузить все элементы, вы можете сделать:

program = Program.first
ids = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
members = Members.where(id: ids)
locations = members.pluck(:location)

И, наконец, если вы не хотите использовать элементы, вы можете сделать:

program = Program.first
ids = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
locations = Members.where(id: ids).pluck(:location)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...