使用PostgreSQL的Rails 3.2.13
我们正在尝试优化以下模型代码,该代码根据用户定义的过滤条件从数据库中检索一组电子商务订单。
用户可以选择根据订单状态,付款状态&发货状态。他们可以将这些设置为==
或<>
每个特定值。
在此之后,我们过滤掉任何数字订单,然后对结果进行分页。
这一切都运作良好,除了订单有很多关联,例如产品,地址,付款等。这会导致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
生成的SQL查询如下所示:
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但这似乎没有效果。例如:
orders = self.includes(:shipping_address).where([conditions, order_status, payment_status, fulfillment_status]).order("order_created_at #{filter.sort_by}")
答案 0 :(得分:1)
使用命名范围,而不是定义Order模型的方法。
class Order
named_scope :with_address,
:include => :shipping_address
...
我也会使用范围进行过滤和排序。
您可以阅读更多关于:include和:来自http://venkatev.wordpress.com/2010/02/04/activerecord_joins_and_include/
的联接