向 Rails 模型添加额外字段以减少不必要的数据库查询
Posted
技术标签:
【中文标题】向 Rails 模型添加额外字段以减少不必要的数据库查询【英文标题】:Adding Extra Fields to Rails Model to Reduce Unnecessary DB Queries 【发布时间】:2021-12-18 20:44:41 【问题描述】:我们有一个模型 Booking,它连接到许多其他模型。
class Booking < ApplicationRecord
belongs_to :business
belongs_to :employee
# a whole lot more below
end
在显示视图中有一行代码:
Room Service Employee: #booking.employee.first_name
由于这一行,有一个数据库查询来查找预订指定员工的名字。
当每天查看 10,000 次预订时,就有 10,000 次 DB 调用愚蠢的名字。
我的问题是,将“employee_name”字段添加到 Booking 模型并在那里写入员工姓名而不是每次都去数据库获取该信息是否有意义?数据库查询可能只需要 25 毫秒,但它们加起来。真的有区别吗?
我是公司里唯一的程序员,所以我没有任何资深开发人员要问。我已经谷歌了,但找不到任何有用的东西。在网上向我传道!
感谢您的意见!
【问题讨论】:
是的,这是额外的查询,但优化这样的事情还为时过早吗?如果将名称复制到两个表中,则每当名称更改时都必须对其进行维护。它有点复杂-值得吗?也许如果你真的在寻找优化。 【参考方案1】:除非万不得已,否则我通常会避免重复。
如果您知道要预先使用.eager_load
,则可以防止额外的查询:
@booking = Booking.eager_load(:employee)
.find(params[:id])
这会在单个数据库查询中同时加载预订和员工。如果您要显示和列出预订和相关员工,您可以使用.includes
来避免N+1 query:
@bookings = Booking.includes(:employee)
.all
@bookings.each |b| puts b.employee.first_name # will only do a single query
当您第一次调用booking.employee
(在集合实例上)时,这将一次“延迟加载”所有员工记录。
如果您不想加载整个员工记录,您可以加入并从该表中选择所需的列:
@bookings = Booking.joins(:employee)
.select(
Booking.arel_table[Arel.star],
Employee.arel_table[:first_name].as("employee_name")
)
@bookings.each |b| puts b.employee_name
您选择并分配别名的任何列都将在结果集中的模型中作为方法使用。魔法!
见:
Making sense of ActiveRecord joins, includes, preload, and eager_load【讨论】:
以上是关于向 Rails 模型添加额外字段以减少不必要的数据库查询的主要内容,如果未能解决你的问题,请参考以下文章
Rails has_many 通过表单在连接模型中带有复选框和额外字段