将活动记录查询拆分为2种方法是否会对数据库造成两次打击?

我有一个数据库查询,我想在其中获取一组与该集合不同的用户:

@range      is a predefinded date range
@shift_list is a list of filtered shifts
def listing
  Shift
    .where(date: @range,shiftname: @shift_list)
    .select(:user_id)
    .distinct
    .map { |id| User.find( id.user_id ) } 
    .sort
end

为了便于阅读,或者为了测试或隔离或代码重用,我读了一些地方,可以将其拆分为单独的方法:

def listing
  shiftlist
    .select(:user_id)
    .distinct
    .map { |id| User.find( id.user_id ) } 
    .sort
end

def shift_list
  Shift
    .where(date: @range,shiftname: @shift_list)
end

所以我重写了此代码以及其他一些代码,现在页面的加载时间是原来的4倍。

我的问题是,这种方法拆分是否会导致数据库被击中两次?还是我在其他地方做过的事情?

我很乐意提出提高此代码效率的建议。


除了需要从代码中删除映射之外,还使用以下代码创建了该移位列表:

def _month_shift_list
  Shift
    .select(:shiftname)
    .distinct
    .where(date: @range)
    .map {|x| x.shiftname }
end 

我的意图是创建一个以字符串形式命名的数组。 我显然缺少数据库访问方面的一些关键理解,因为这种方法显然造成了问题的一部分。


我想我已经找到了以下解决方案:

def month_shift_list
  Shift.
    .where(date: @range)
    .pluck(:shiftname)
    .uniq
end 
ysw9232 回答:将活动记录查询拆分为2种方法是否会对数据库造成两次打击?

不会,数据库不会被两次命中。两种方法中的查询都是延迟加载的。页面加载速度慢的问题在于,map函数现在必须执行多次查找,这会从数据库转换为多个SELECT。您可以将查询重写为此:

def listing
  User.
   joins(:shift).
   merge(Shift.where(date: @range,shiftname: @shift_list).
   uniq.
   sort
end

这对数据库只有一击,它将更快,并且应该产生与上述相同的结果。

这里的假设是,Shift的用户模型上存在has_one / has_many关系

class User < ActiveRecord::Base
  has_one :shift
end

如果您不想在User上建立has_one / has_many关系,则可以将其重写为:

def listing
  User.
   joins("INNER JOIN shifts on shifts.user_id = users.id").
   merge(Shift.where(date: @range,shiftname: @shift_list).
   uniq.
   sort
end

替代:

如果在使用ActiveRecord#merge时遇到问题,则可以使用2个查询。

def listing
  user_ids = Shift.where(date: @range,shiftname: @shift_list).uniq.pluck(:user_id).sort
  User.find(user_ids)
end
本文链接:https://www.f2er.com/3088944.html

大家都在问