在Rails中使用.includes()时,有没有一种方法可以显式显示.select()列



我正试图优化我的查询,以了解RAM的使用情况,而.includes(:ocr(中的一个表上有太多列(还有一个大列(。有没有一种方法可以让我仍然使用Rails的.includes((,但从includes((表中选择显式的.select((列?

我想排除使用N+1的情况,这是.joins((生成的。

即。

User.select(:email).includes(:ocr => select(:small_value_only))

您没有提供太多关于如何设置表的信息,所以我假设User为belongs_to :ocr,User有一个ocr_id列,ocr表的名称为ocr

应该使用joins而不是includes,这就是生成INNER JOIN查询并能够检索联接表的列的方式。最后,您可以使用AS对列名进行别名,这样在您的模型中更容易检索:

users = User.joins(:ocr).select(:email, :ocr_id, '`ocr`.`small_value_only` AS `ocr_sma`')
users.each do |user|
user.email # Users.email for this record
user.ocr_sma # Joined Ocr.small_value_only for this record
end

(很明显,我把它别名为ocr_sma,但你可以给它起你想要的名字(

如果您真的只想获取列数据而不是完整的ActiveRecord对象,那么应该使用pluck而不是select。加速这类大查询正是pluck的初衷。pluck只是返回一个数据数组:

values = User.includes(:ocr).pluck(:email, "ocr.small_value_only")
# SELECT "user"."email", ocr.small_value_only FROM "users"
#   LEFT OUTER JOIN "ocrs" ON "ocr"."user_id" = "users"."id"
#
# [["email_1", 3], ["email_2", 7]] # 3 and 7 are the small values

如果您想要ActiveRecord对象,但希望跳过填充某些数据,则与上面相同,但用left_joins替换includes,用select替换pluck

values = User.left_joins(:ocr).select(:email, "ocr.small_value_only")
# SELECT "user"."email", ocr.small_value_only FROM "users"
#   LEFT OUTER JOIN "ocrs" ON "ocr"."user_id" = "users"."id"
#
# #<ActiveRecord::Relation [#<user id: 1>, #<user id: 2>]>

无论哪种方式,正如您所看到的,SELECT语句都是相同的,并且只返回选定的数据列。

我不想说以下选项一定比Benj和Old Pro建议的要好,而是想提供更多的替代方案。

第一个使用了includes方法,因为这正是OP所要求的。但是,由于默认情况下includes将选择主模型(User(的所有列,因此必须首先通过except方法删除该默认选择:

User.includes(:ocr).except(:select).select(:id, 'ocr.small_value_only')

当然,首先使用join会更容易。

以下选项源于我不喜欢在AR查询中使用字符串,因为它往往依赖于AR实际上应该为您抽象的被调用模型的知识,即数据库表(ocr(的名称。

去除这些知识的一个简单实现是从模型中获取表名:

User.joins(:ocr).select(:email, "`#{Ocr.table_name}`.`small_value_only`")

下一种选择依赖于merge来去除用于选择列的字符串:

User.joins(:ocr).merge(Ocr.select(:project_id)).select(:id) 

但是,由于生成的sql没有引用small_value_only的Ocr表,因此相当于写入:

User.joins(:ocr).select(:email, :small_value_only) 

并且仅在CCD_ 23不存在于CCD_。

最后一种选择没有这个缺点,但要详细得多:

User.joins(:ocr).select(Ocr.select(:small_value_only).arel.projections).select(:id)

我认为您应该在User like:中创建一个新的关联

belongs_to :ocr_small_value_only, -> {select('ocr.id,ocr.small_value_only')}, class_name: 'ocr', foreign_key: 'ocr_id'

然后使用进行查询

User.select('ocr_id, email').includes(:ocr_small_value_only)

相关内容

最新更新