Rails 4:Joins vs Includes:为什么嵌套关联的结果不同?

时间:2015-04-06 04:36:39

标签: ruby-on-rails

在Rails 4应用程序中,我有两个模型:

Merchant has_many:offering_specials

OfferSpecial belongs_to:merchant

我想要检索所有商家及其开放的特殊产品(使用status_code:" OP")

我试过了:

@merchants = Merchant.joins(:offering_specials).where(offering_specials: { status_code: "OP" })

这是查询:

Merchant Load (0.4ms)  SELECT `merchants`.* FROM `merchants` INNER JOIN `offering_specials` ON `offering_specials`.`merchant_id` = `merchants`.`id` WHERE `offering_specials`.`status_code` = 'OP'

但是它检索了所有提供特价,包括开放(" OP")和待定(" PN")。

然而,使用包括工作:

@merchants = Merchant.joins(:offering_specials).where(offering_specials: { status_code: "OP" })

这只检索了公开发售特价。但是看看慢得多的查询:

  SQL (19.9ms)  SELECT `merchants`.`id` AS t0_r0, `merchants`.`name` AS t0_r1, `merchants`.`slug` AS t0_r2, `merchants`.`url` AS t0_r3, `merchants`.`summary` AS t0_r4, `merchants`.`description` AS t0_r5, `merchants`.`active_for_display` AS t0_r6, `merchants`.`active_for_offerings_by_merchant` AS t0_r7, `merchants`.`active_for_offerings_by_legatocard` AS t0_r8, `merchants`.`credit_limit` AS t0_r9, `merchants`.`search_location_code` AS t0_r10, `merchants`.`image_file_name` AS t0_r11, `merchants`.`image_file_size` AS t0_r12, `merchants`.`image_content_type` AS t0_r13, `merchants`.`image_updated_at` AS t0_r14, `merchants`.`logo_file_name` AS t0_r15, `merchants`.`logo_file_size` AS t0_r16, `merchants`.`logo_content_type` AS t0_r17, `merchants`.`logo_updated_at` AS t0_r18, `merchants`.`created_at` AS t0_r19, `merchants`.`updated_at` AS t0_r20, `offering_specials`.`id` AS t1_r0, `offering_specials`.`special_number` AS t1_r1, `offering_specials`.`merchant_id` AS t1_r2, `offering_specials`.`merchant_user_id` AS t1_r3, `offering_specials`.`nonprofit_percentage` AS t1_r4, `offering_specials`.`discount_percentage` AS t1_r5, `offering_specials`.`start_at` AS t1_r6, `offering_specials`.`end_at` AS t1_r7, `offering_specials`.`closed_at` AS t1_r8, `offering_specials`.`max_dollar_amount_for_offering` AS t1_r9, `offering_specials`.`max_dollar_amount_per_buyer` AS t1_r10, `offering_specials`.`status_code` AS t1_r11, `offering_specials`.`created_at` AS t1_r12, `offering_specials`.`updated_at` AS t1_r13 FROM `merchants` LEFT OUTER JOIN `offering_specials` ON `offering_specials`.`merchant_id` = `merchants`.`id` WHERE `offering_specials`.`status_code` = 'OP'

如何让这个查询使用连接而不是包含?

1 个答案:

答案 0 :(得分:0)

此类查询通常不会返回关联记录。您正在申请商家列表,以及您获得的商家列表。当您随后请求其中一个商家的关联的OfferingSpecials时,将执行一个新查询(您应该在日志中看到),并且您获得所有这些查询,因为您没有另行指定。您的问题中的代码不包括您执行此操作的位置,但您必须在某处执行此操作才能获取OfferingSpecials。

使用includes要求加入关联,这意味着它将受到查询的限制,这就是为什么当你这样做时你看到它的工作原理。它速度较慢,因为它现在为您取出这些额外的记录,而不是稍后单独进行。

如果您确实想要使用.joins重构此内容,则只需将条件添加到您获取商家.offering_specials的行:

@merchants.each do |m|
  m.offering_specials.where(:status_code => 'OP')
end

但是,在这样做之前,你应该读一下为什么急切加载存在 - 你可能通过执行一个较慢的查询而不是许多快速查询来获得更好的性能,或者如果数量较多,你可能会这样做商家记录涉及通过一些门槛(可能会也可能不会发生,具体取决于您的应用程序的性质)。