ActiveRecord Запрос подробных и сводных данных - PullRequest
3 голосов
/ 09 ноября 2010

Используя Rails3, у меня есть таблица downloads со столбцами download_date и credits. То, что я хочу сгенерировать - это таблица типа:

 Date        Credits
 2010-11-01  25
 2010-11-01  27
*2010-11-01  52  <= Sum of previous 2 rows
 2010-11-02  32
*2010-11-02  32  <= Sum of previous row

Это можно сделать, используя что-то вроде:

u.downloads.group_by(&:download_date).each do |date, downloads|
  downloads.each do |d|
    puts " %10s  %3d" % [d.download_date, d.credits]
  end
  puts "*%10s  %3d" % [date, downloads.sum(&:credits)]
end

Это решение, хотя и работает, не слишком похоже на Rails и приводит к довольно большому количеству запросов SQL. Предполагается, что 100 пользователей x 10 000 загрузок в год и количество запросов к концу года составляет порядка 1 000 000 для каждой из этих обслуживаемых страниц.

Любое решение, которое я придумаю, должно быть независимым от базы данных, если это вообще возможно. Я знаю, что буду использовать PostgreSQL на Heroku для развертывания, и моя версия для разработки, пусть и ошибочная, все еще работает на MySQL.

Я надеюсь, что предоставил достаточно информации о проблемной области и связанных с этим проблемах. Есть мнения или предложения?

Ответы [ 2 ]

1 голос
/ 10 ноября 2010

То, что вы делаете, на самом деле уже довольно оптимизировано.Единственная проблема - вы загружаете одну загрузку за раз.Используйте u.downloads.all.group_by (добавьте туда all), чтобы загрузить все загрузки одновременно.Таким образом, вы в значительной степени сводитесь к одному запросу.

Обновление: Хотя, на второй взгляд, в Rails 3 это даже не должно вызывать несколько запросов.Существует множество причин, по которым вы можете столкнуться с проблемами N + 1.Например, если вы сделаете обратную ссылку на конкретную загрузку из какого-либо связанного объекта где-то в вашем представлении - rails может не знать, что эта загрузка уже была извлечена из базы данных как часть вашего массива, и повторно извлечь ее снова.Если вы видите много запросов - этот код не должен вызывать их.

0 голосов
/ 09 ноября 2010

Поскольку вы уже выполняете итерацию самостоятельно, вы также можете сделать сумму:

u.downloads.group_by(&:download_date).each do |date, downloads|
  subtotal_credits = 0
  downloads.each do |d|
    puts " %10s  %3d" % [d.download_date, subtotal_credits += d.credits]
  end
  puts "*%10s  %3d" % [date, subtotal_credits]
end
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...