向 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 模型添加额外字段以减少不必要的数据库查询的主要内容,如果未能解决你的问题,请参考以下文章

向 ModelAdmin 表单添加额外字段

如何向 Django 模型添加额外数据以在模板中显示?

向 rails 命令添加额外属性

Rails has_many 通过表单在连接模型中带有复选框和额外字段

Rails - 如何在索引控制器方法中使用额外字段渲染json

ruby on rails 向数据库添加新字段