1

Rails 3.2.13 с PostgreSQLжадная загрузка ассоциации со сложным запросом

Мы пытаемся оптимизировать следующий код модели, который извлекает набор электронной коммерции Заказы из базы данных, на основе заданных пользователем критериев фильтрации.

Пользователь может выбрать, чтобы отфильтровать заказы на основании статуса заказа, статуса оплаты & Статус доставки. Они могут установить для них либо ==, либо <> конкретное значение для каждого.

После этого мы отфильтровываем любые цифровые заказы, а затем разбиваем на страницы результаты.

Все это хорошо работает, за исключением того, что у Ордена есть много ассоциаций, таких как продукты, адреса, платежи и т. Д. Это вызывает N + 1 запросы и делает процесс чрезвычайно медленным.

Order.rb:

belongs_to :shop 
has_many :shipping_lines , :dependent => :destroy 
has_many :line_items , :dependent => :destroy 
has_many :taxlines , :dependent => :destroy 
has_many :fulfillments , :dependent => :destroy 
has_many :notes , :dependent => :destroy 
has_many :discounts , :dependent => :destroy 
has_one :billing_address , :dependent => :destroy 
has_one :shipping_address , :dependent => :destroy 
has_one :payment_detail, :dependent => :destroy 
has_many :order_histories, :dependent => :destroy 

Любых идеи о том, как мы можем включать ассоциации нетерпеливых загруженные в ниже запросе?

Пример ввод: пользователь может хочет видеть любого (открытый или закрытый), оплаченные заказы, которые еще не погружен

Order Status == 'open' 

Payment Status == 'any' 

Shipping Status <> 'shipped' 

Магазин идентифицируются субдомен

def by_filter(subdomain, filter,page) 
    shop_condition = "shop_id = #{subdomain.shops[0].id}" 
    if filter.name != "All" 
    if filter.order_status == "any" 
     status_condition = "status in (?)" 
     order_status = Filter::ORDER_STATUS.values - ["any"] 
    else 
     status_condition = "status #{Filter::STATUS_OPERATORS_MAPPING[filter.order_status_operator]} ?" 
     order_status = filter.order_status 
    end 

    if filter.payment_status == "any" 
     payment_status_condition = "payment_status in (?)" 
     payment_status = Filter::PAYMENT_STATUS.values - ["any"] 
    else 
     payment_status_condition = "payment_status #{Filter::STATUS_OPERATORS_MAPPING[filter.payment_status_operator]} ?" 
     payment_status = filter.payment_status 
    end 

    if filter.fulfillment_status == "any" 
     fulfillment_status_condition = "fulfillment_status in (?)" 
     fulfillment_status = Filter::FULFILLMENT_STATUS.values - ["any"] 
    else 
     fulfillment_status_condition = "fulfillment_status #{Filter::STATUS_OPERATORS_MAPPING[filter.fulfillment_status_operator]} ?" 
     fulfillment_status = filter.fulfillment_status 
    end 

    conditions = "#{status_condition} AND #{payment_status_condition} AND #{fulfillment_status_condition} AND #{shop_condition} " 
    else 
    conditions = shop_condition 
    end 


    orders = self.where([conditions, order_status, payment_status, fulfillment_status]).order("order_created_at #{filter.sort_by}") 


    if filter.digital_orders 
    orders_arr = ((orders.all.collect(&:shipping_address) - [nil]).collect(&:order)).flatten 
    orders = Kaminari.paginate_array(orders_arr).page(page).per(filter.show) 
    else 
    orders = orders.page(page).per(filter.show) 
    end 
    return orders 
end 

СКПА Созданный запрос выглядит так:

SELECT "orders".* FROM "orders" WHERE (status = 'open' AND payment_status in ('authorized', 'pending', 'paid', 'partially_paid', 'partially_refunded', 'refunded', 'voided') AND fulfillment_status <> 'shipped' AND shop_id = 58) ORDER BY order_created_at DESC 

Мы попытались сделать регулярное .includes, но t его, кажется, не имеет никакого эффекта. Например:

orders = self.includes(:shipping_address).where([conditions, order_status, payment_status, fulfillment_status]).order("order_created_at #{filter.sort_by}") 
+0

Выберите один сайт и удалить другой вопрос пожалуйста. Вы дублировали это здесь: http://codereview.stackexchange.com/q/41650/26613 и даже не потрудились связывать их, поэтому вы, вероятно, будете тратить время людей на дублирующие ответы. –

+0

Извинения, исправлено сейчас. Спасибо, что указали это. –

ответ

1

Использовать названные области применения вместо определения метода для модели заказа.

class Order 

named_scope :with_address, 
:include => :shipping_address 

... 

Я бы сделал фильтрацию и заказ с помощью областей.

Вы можете прочитать больше о: включать и: присоединяется с http://venkatev.wordpress.com/2010/02/04/activerecord_joins_and_include/

+0

Спасибо, Aret, это, безусловно, помогает. Мы повторим этот код, хотя и полностью, и используем что-то вроде [Ransack] (https://github.com/activerecord-hackery/ransack), так как это даст нам большую гибкость и производительность. –

Смежные вопросы