带外键约束的关联引发N+1 query,eager-loading失效问题问询
问题分析与解答
你遇到的问题其实是两个容易忽略的细节导致的,和外键约束本身没有直接关系——外键约束只是数据库层面的完整性限制,并不会影响ActiveRecord的预加载逻辑。
1. 最关键的错误:预加载的关联和实际访问的关联不匹配
看你第二个查询的代码:
Market.includes(:base_currency2).each { |x| puts x.base_currency.code }
你用includes(:base_currency2)预加载了base_currency2这个关联,但循环里访问的却是x.base_currency.code(不带2的那个关联)!
这就意味着你预加载的base_currency2完全没被用到,每次循环访问base_currency时,ActiveRecord都会去数据库单独查询一次对应的Currency记录,自然就出现了N+1问题。
如果把代码改成这样:
Market.includes(:base_currency2).each { |x| puts x.base_currency2.code }
你会看到日志里只有两次查询:一次加载所有Market,一次批量加载对应的Currency,不会有N+1。
2. 模型与表名不匹配的潜在问题
你的迁移代码里创建的是market2表:
create_table :market2 do |t| # ...字段定义 end
但你的模型是class Market < ApplicationRecord,默认情况下ActiveRecord会把模型映射到复数形式的表名markets,这会导致模型找不到正确的表。如果这是笔误,建议把迁移里的表名改成markets;如果确实要用market2表,需要在模型里指定:
class Market < ApplicationRecord self.table_name = 'market2' # ...关联定义 end
总结
外键约束本身不会导致N+1查询,你遇到的问题完全是因为:
- 预加载的关联和实际访问的关联不一致
- 模型和表名存在不匹配的潜在问题
修正这两个点后,带外键约束的关联同样可以正常使用预加载。
内容的提问来源于stack exchange,提问作者ray
相关产品推荐
相关产品推荐

