Rails - эффективно извлекает и рассчитывает данные по нескольким отношениям - PullRequest
1 голос
/ 24 ноября 2010

Попытка получить данные наиболее эффективным способом для некоторых отчетов с использованием Rails 2.3 и MySQL.

В нашем приложении есть пользователи, сделки и покупки.Отношения выглядят так:

class User
  has_many :purchased_deals
  has_many :deals, :through => :purchased_deals
end

class Deal
  has_many :purchased_deals
  has_many :users, :through => :purchased_deals
end

class PurchasedDeal
  belongs_to :deal
  belongs_to :user
end

Для отчета, который я запускаю, мне нужно получить всех пользователей, которые совершили покупку (т. Е. Имеют хотя бы один купленный товар), а затем общую сумму всехсделки, которые они купили (цена указана в Сделке, а не в Закупке).

Конечно, я мог бы начать со списка всех пользователей, включая как сделки, так и купленные сделки.Я попробовал это, и запрос был массовым (30 000 пользователей, давай или забирай, 3000 сделок, более 100 000 приобретенных сделок).

Я мог бы начать с пользователей, затем сделать .each и найти те, которыезаключить сделку на покупку, разделить их на свои группы, а затем выполнить итерацию по каждому из этих , чтобы получить общую сумму покупки, но это достаточное количество запросов.

В настоящее времяОба эти метода занимают так много времени, что запросы истекаютКакой самый эффективный способ получить нужные мне данные?Кстати, добавление столбцов в таблицы является вполне приемлемым решением.У меня есть полный доступ к базе данных, чтобы делать то, что мне нужно.

Спасибо!

Ответы [ 2 ]

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

Чтобы получить список идентификаторов пользователей с более чем одной покупкой, вы можете сделать следующее, чтобы получить доступ только к одной таблице:

user_ids = PurchasedDeal.count(:group => :user_id, :having => 'count_all > 0').keys

Впоследствии вы можете получить всех этих пользователей с помощью:

users = User.find user_ids

Вещи могут быть ускорены с помощью счетчика кэша.В вашей модели пользователя добавьте опцию :counter_cache => true к ассоциации has_many для купленных сделок.Вам понадобится дополнительный целочисленный столбец в таблице пользователей и инициализация, которая может выглядеть следующим образом при миграции:

add_column :users, :purchased_deals_count, :integer, :null => false, :default => 0
User.each { |u| User.reset_counters u, :purchased_deals }

Как только это выйдет, это станет намного проще:

users = User.all :conditions => 'purchased_deals_count > 0'

Rails будет поддерживать для вас актуальную колонку с большинством стандартных операций.


Чтобы получить общую цену, всегда требуется объединение.Или вы можете создать хэш цен сделок и выполнить утомительную обработку в Ruby.Я не эксперт по SQL, но вы можете избавиться от объединения, сохранив цену с помощью BuyasedDeal.Иначе, вот как это сделать с объединением:

user_id_to_price = PurchasedDeal.sum 'deal.price', :include => :deal, :group => :user_id

Вы можете отфильтровать это только по нужным пользователям, добавив что-то вроде :conditions => ['user_id IN (?)', users].(Где users может быть списком идентификаторов, но также объектов пользователя.)

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

Предполагая, что вы добавите столбец цен в таблицу приобрела цену, вы можете получить информацию о пользователях и общую цену сделок, например:

select users.id, sum(purchased_deals.price) from users, purchased_deals where users.id = purchased_deals.user_id group by users.id having sum(purchased_deals.price) > 0
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...