在获取带有相关记录的对象数组时,我获得了使用预先加载以避免N + 1的好处,但是在获取单个记录时使用预先加载是否很重要?
就我而言
user has_many :addresses
user has_many :skills
user has_many :devices
user has_many :authentications
在show动作中,我试图用机架迷你探测器看看是否有趣使用预先加载
User.includes(:skills, :addresses, :devices, :authentications).find(params[:id])
但我似乎有相同数量的sql请求..
有关使用此类案件的预先加载的任何建议吗?
答案 0 :(得分:5)
在获取单个记录时使用预先加载是否很重要?
对于一级深层的协会,没有。
如果你有嵌套关联,是的。
# class User
has_many :skills
# class Skill
belongs_to :category
# this code will fire N + 1 queries for skill->category
user.skills.each do |skill|
puts skill.category
end
在这种情况下,最好是急切加载skills: :category
User.includes(skills: :category).find(id)
修改强>
Rails提供了两种避免N + 1查询的方法,它们称为preload
和eager_load
。
Preload 会为每个集合触发单个SQL查询。
Eager load 尝试构建一个大型的左连接SELECT,以检索1个查询中的所有集合。
简短版本是includes
让Rails选择使用哪一个。但你可以强迫一种方式。
User.eager_load(:skills, :addresses, :devices, :authentications).find(params[:id])
应检索1个查询中的所有记录。
进一步阅读:
答案 1 :(得分:3)
尝试使用Bullet gem检测未使用或缺少的预先加载。它旨在告诉您是否存在include
语句浪费或N + 1查询效率低下,includes
会有所帮助。
如果出现问题,可以将其配置为输出到Rails记录器以通知您。或者,您可以在浏览器中向需要优化的页面显示通知。