如何用ActiveRecord单查询预加载多关联,避免N+1且不使用map获取指定字段?
解决方案
要实现一次查询获取指定Project下所有Model的title,同时避免N+1问题且不用map,可以直接通过关联查询+字段提取的方式完成:
写法一(从Model出发关联查询)
Model.joins(gs_collector: { collector: :project }).where(projects: { id: 92666 }).pluck(:title)
写法二(从Project出发关联查询)
Project.where(id: 92666).joins(collectors: { gs_collector: :model }).pluck('models.title')
原理说明
joins(...)会在SQL层面建立Project→Collector→GsCollector→Model的完整关联,确保一次查询拉取所有关联数据。pluck直接从数据库提取指定字段的数组结果,不会加载整个ActiveRecord对象实例,既高效又不需要后续的map处理。
原方案的问题所在
原代码Project.find(92666).collectors.map{...}的执行流程会触发多次查询:
- 查询指定Project(1次)
- 查询该Project下的所有Collectors(1次)
- 遍历每个Collector时,分别查询对应的GsCollector和Model(共2*N次,N为Collector数量)
总共产生1+1+2N次数据库请求,属于典型的N+1性能问题,而上述方案仅执行1次SQL查询即可得到结果。
内容的提问来源于stack exchange,提问作者croceldon
相关产品推荐
相关产品推荐

