开发者

Is it possible to run a find_by_sql query in Rails / ActiveRecord without loading all results into memory?

I'm building a Rails plugin that extracts a lot of data from Rails apps. It builds queries dynamically that span multiple tables, and t开发者_运维问答here will be a lot of results returned. Here's an example of one of the queries built for pulling purchase data out of a Spree (Rails shopping cart):

select orders.user_id as from_id, variants.product_id as to_id from orders, line_items, variants where orders.user_id is not null and variants.product_id is not null and orders.id = line_items.order_id and line_items.variant_id = variants.id order by from_id;

The problem is that ActiveRecord loads up all results into memory. Is there a way to avoid that without dropping down to writing DB-specific code? (I'm aware of find_each, but that doesn't allow for sorting.)


It's definitely possible, and here's an article that walks through it:

http://www.rubyinside.com/paginate_by_sql-rails-pagination-on-your-own-sql-queries-50.html

They have code you can copy verbatim, but the key is using SQL's count method. With this code, you can call paginate_by_sql instead of find_by_sql, and you pass in the page and per-page params.


Maybe you also want to look into, Rails ActiveRecord batches, to retrieve records in smaller chunks:

http://guides.rubyonrails.org/active_record_querying.html#retrieving-multiple-objects-in-batches


Jaime's answer led me along a more productive path of queries landing at will_paginate, which offers a paginate_by_sql method. With a teency bit of effort, that was wrapped up in a paginated SQL each:

def paginated_sql_each(query, &block)
  page = 1
  begin
    results = paginate_by_sql(query, :page => page)
    results.each { |r| block.call(r) }
    page += 1
  end while !results.empty?
end
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜