Thursday, September 18, 2014

Experimenting Rails Eager Loading

While building Rails app, what we frequently do is get a collections of objects from database and then iterate through each of them and get the associated objects and do some operations on these associated objects. For example, we have a PurchaseOrder and PurchaseOrderLineItem model, we might write some thing like

pos = Purchase.all
pos.each do |po|
  po.purchase_order_line_itesm.each do |li|
    # li.some_method
  end
end

How many queries does it issue in this code snippet. The number is 1+the number of purchase order that's returned from the first query. This is called N+1 query problem. Luckily, in Active Record, we have a solution to this problem, which will reduce the number of queries from 1+N to 2 in cases like that. What you need to do is to specify the associated objects using includes method, and it will make sure all the associated objects are loaded with the minimum possible number of queries. So the revised version of the code snippet above would be

pos = Purchase.includes(:purchase_order_line_items).all
pos.each do |po|
  po.purchase_order_line_itesm.each do |li|
    # li.some_method
  end
end

Now if we run this code snippet again, it will only issue two queries. The second query will use IN clause to get all the PurchaseOrderLineItem records whose purchase_order_id matches the ones of the returning Purchase Orders of the first query. This is how the name eager loading comes from, instead of loading a small amount of data using N queries, it loads all the data once using one query.