Ruby on rails Rails 4:如何防止在调用Model.all之前加载所有数据库记录
我遇到了一个性能问题,Ruby on rails Rails 4:如何防止在调用Model.all之前加载所有数据库记录,ruby-on-rails,performance,Ruby On Rails,Performance,我遇到了一个性能问题,处理。在筛选器之前调用所有,然后在处理模型上运行第二个查询处理有大量记录,将它们全部加载到内存中,只需对它们运行第二次查询,就会导致RAM中出现峰值,我想对此进行修复 控制器中的线路为: @filter = ProcessingFilter.new(base_collection: Processing.all, options: params[:filter]) 如您所见,Processing.all作为base\u集合param传递到这里 ProcessingFilt
处理。在筛选器之前调用所有
,然后在处理
模型上运行第二个查询<代码>处理有大量记录,将它们全部加载到内存中,只需对它们运行第二次查询,就会导致RAM中出现峰值,我想对此进行修复
控制器中的线路为:
@filter = ProcessingFilter.new(base_collection: Processing.all, options: params[:filter])
如您所见,Processing.all
作为base\u集合
param传递到这里
ProcessingFilter
然后运行:
class ProcessingFilter
def initialize(base_collection:, options: {})
@base_collection = base_collection
@options = options
end
def collection
@collection ||= begin
scope = @base_collection
if condition1
scope = scope.joins(:another_entry).where(another_entry: {customer_id: customer_id})
end
if condition2
scope = scope.where('created_at >= ?', created_at_start)
end
if condition3
scope = scope.where('created_at <= ?', created_at_end)
end
if condition4
scope = scope.where(number: processing_number)
end
scope
end
end
end
类处理过滤器
def初始化(基本集合:,选项:{})
@基本集合=基本集合
@选项=选项
结束
def收集
@集合| |=开始
范围=@base\u集合
如果条件1
scope=scope.joins(:另一个项目)。其中(另一个项目:{customer\u id:customer\u id})
结束
如果条件2
scope=scope.where('created_at>=?',created_at_start)
结束
如果条件3
scope=scope.where('created_at以防您不使用过滤默认的_作用域(或无论如何都要忽略默认的过滤)处理。unscope
就可以了
顺便问一下,您目前正在使用哪个版本的rails
有关已弃用的方法的附加链接。作用域方法:
如果您不使用过滤默认作用域(或无论如何都要忽略默认过滤)处理。无范围的
可以解决这个问题
顺便问一下,您目前正在使用哪个版本的rails
有关已弃用的方法的附加链接。作用域方法:
免责声明:这本身还不是答案,但因为太长,需要键入代码:
处理。所有
尚未将记录加载到内存中,因为记录是“延迟加载”的,因为它只返回一个ActiveRecord\u关系
对象。只有在对其使用数组
方法后,如每个
,第一个
,最后一个
,映射
,或[]
,它是否只开始将记录从数据库实际提取到内存中
证明:
processings = Processing.all
puts processings.class
# => Processing::ActiveRecord_Relation
puts processings.first.class
# Processing Load (2.9ms) SELECT "processings".* FROM "processings" ORDER BY "processings"."id" ASC LIMIT 1
# => Processing
既然我们知道.all
不会立即将记录加载到内存中,那么我们需要找出为什么在调用@filter=ProcessingFilter.new(base\u collection:Processing.all,options:params[:filter])时,您的代码仍在将记录立即加载到内存中。
仅限于您显示的代码,我无法在ProcessingFilter
类中看到任何触发将记录加载到内存中的内容(没有调用将记录加载到内存中的Array
方法);它们都是ActiveRecord\u Relation
对象。因此,我当前的猜测是,在两个过滤器之间的某个地方,您正在调用Array
方法:
@filter = ProcessingFilter.new(base_collection: Processing.all, options: params[:filter])
# An Array method is called:
@filter.collection.first
如果在rails控制台中执行此操作,则需要附加;nil
,以防止“处理”每行调用的值,因为它会立即加载记录:
@filter = ProcessingFilter.new(base_collection: Processing.all, options: params[:filter]); nil
@filter.collection.first; nil
免责声明:这本身还不是答案,但因为太长,需要键入代码:
处理。所有
尚未将记录加载到内存中,因为记录是“延迟加载”的,因为它只返回一个ActiveRecord\u关系
对象。只有在对其使用数组
方法后,如每个
,第一个
,最后一个
,映射
,或[]
,它是否只开始将记录从数据库实际提取到内存中
证明:
processings = Processing.all
puts processings.class
# => Processing::ActiveRecord_Relation
puts processings.first.class
# Processing Load (2.9ms) SELECT "processings".* FROM "processings" ORDER BY "processings"."id" ASC LIMIT 1
# => Processing
既然我们知道.all
不会立即将记录加载到内存中,那么我们需要找出为什么在调用@filter=ProcessingFilter.new(base\u collection:Processing.all,options:params[:filter])时,您的代码仍在将记录立即加载到内存中。
仅限于您显示的代码,我无法在ProcessingFilter
类中看到任何触发将记录加载到内存中的内容(没有调用将记录加载到内存中的Array
方法);它们都是ActiveRecord\u Relation
对象。因此,我当前的猜测是,在两个过滤器之间的某个地方,您正在调用Array
方法:
@filter = ProcessingFilter.new(base_collection: Processing.all, options: params[:filter])
# An Array method is called:
@filter.collection.first
如果在rails控制台中执行此操作,则需要附加;nil
,以防止“处理”每行调用的值,因为它会立即加载记录:
@filter = ProcessingFilter.new(base_collection: Processing.all, options: params[:filter]); nil
@filter.collection.first; nil
我会考虑将这些条件语句提取到它们自己的范围方法中,然后贬低这个<代码>处理过滤器类。看起来装饰器设计得不好。
您可以使用BaseType集合值来确定被调用的模型,然后在初始化过程中将代理调用到“代码>处理筛选器< /代码>。应为您省下一些麻烦,只需调用BaseSy收藏范围。我怀疑您是因为该用法得到了重复的查询调用。 < P>我会考虑EX。将这些条件引入各自的作用域方法,然后弃用这个ProcessingFilter
类。它看起来像是设计得不好的装饰器
您可以使用base_collection值来确定要调用的模型,然后在初始化时将对ProcessingFilter
的调用代理到适当的作用域。这样可以省去一些麻烦,只需调用base_collection作用域。我怀疑您会因为这种用法而收到重复的查询调用。谢谢。我很高兴为您服务为这个项目使用Rails4.2.6
。我并没有试图忽略默认的过滤,只是尝试在另一个模型中使用几个if语句进行SQL查询,我会