Оптимизация вложенного запроса activerecord - PullRequest
2 голосов
/ 09 августа 2011

Вопрос Activerecord .. Как оптимизировать этот запрос ..

Prefectures (have many) Cities (have many) Shops (have many) Sales (have many) Brands

Я хотел бы получить список из одной продажи на префектуру, которая еще не завершена .., а затем перечислить доступные брендына распродаже.

Вложение делает для меня такую ​​хитрость!

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

#Get all sales which are yet to finish, ordered by finish date
upcoming_sales = Sale.includes([{:shop => {:city => :prefecture}}, :brands])
  .where("finish > ?", Date.today)
  .order('start ASC, finish ASC')
  .select(['shop.city.prefecture.name', 'brands.name'])

#filter down to a single sale per prefecture
 @sales = upcoming_sales.each_with_object({}){ |s,o|
    o[s.shop.city.prefecture.name] = o[s.shop.city.prefecture.name] ||= s
  }     

Ответы [ 3 ]

2 голосов
/ 17 августа 2011

Как насчет этого?

class Sale < ActiveRecord::Base

    belongs_to :shop
    has_many :brands

    def self.first_sale_per_prefecture()
        first_sale_id_per_prefecture = %(
            select max(sales.id) 
            from sales
            inner join shops on shop_id = shops.id
            inner join cities on city_id = cities.id
            where finish > #{Date.today}
            group by prefecture_id
            order by finish desc)

        where("sales.id in (#{first_sale_id_per_prefecture})").includes(:brands, :shop => {:city => :prefecture})
    end
end
2 голосов
/ 11 августа 2011

Вы можете получить информацию о предстоящих продажах, а затем присоединиться к магазинам => города => префектуры и SELECT DISTINCT prefecture_id

, что обеспечит вам только одну продажу в каждой префектуре.Как то так:

@sales = Sale.includes([{:shop => :prefecture},:brands])
  .order('finish DESC')
  .where("finish > ?", Date.today)
  .joins(:shops => { :cities => :prefectures })
  .select('sales.*, DISTINCT prefecture.id')
0 голосов
/ 18 августа 2011

Я собираюсь попробовать это, используя Arel

class Sale < ActiveRecord::Base

  belongs_to :shop


  class << self
    # Returns only Sale objects with obj.finish > today
    # add on other ActiveRecord queries:
    # Sale.unfinished.all
    # Sale.unfinished.all :limit => 10
    def unfinished
      where(Sale.arel_table[:finish].gt(Date.today))
    end

    # should select only one set of unfinished sales, 
    # and where the prefecture name is distinct
    def distinct_prefecture
      Sale.unfinished.joins({:shop => {:city => :prefecture}}).where(Prefecture.arel_table[:name].distinct)
    end
  end
end

Затем, где вы хотите:

@sales = Sale.distinct_prefecture \
  .includes(:brands]) \     # should already include the other stuff with joins
  .order('start ASC, finish ASC')
@brand_list = @sales.collect{|s| s.brands}

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

@sales = Sale.distinct_prefecture  \
  .limit(10)  \
  .includes(:brands]) \
  .order('start ASC, finish ASC')
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...