1
\$\begingroup\$

I've got relation in my database as following :

Customer has many Orders
Order has many Parts
Order has many Upc

So my requirement is to copy all orders from one customer and attach or copy those orders (with their dependencies including parts and upcs) to another customer. With originals customers orders to be left in-tacked, so I'd basically clone orders and dependencies from customer a to customer b

Here is what I got so far, but its kinda slow (slowest first):

I'd iterate trough customers orders first and then I'd call copy_order1 method to copy order and dependencies to another customer. here is copy_order1 (which is in class Customer):

def copy_order1(source_order)
 order_attributes = source_order.attributes.merge({:customer_id => self.customer_id})
 ['id', 'deleted_at'].each{|k| order_attributes.delete k}
 ord = Order.create(order_attributes)
 source_order.parts.each do |part|
 part_attributes = part.attributes.merge({:order_id => ord.id})
 ['id', 'deleted_at'].each{|k| part_attributes.delete k}
 Part.create(part_attributes)
 end
 source_order.upcs.each do |upc|
 upc_attributes = upc.attributes.merge({:order_id => ord.id})
 ['id', 'deleted_at'].each{|k| upc_attributes.delete k}
 Upc.create(upc_attributes)
 end
 return ord
 end

And there I made slightly faster method called copy_order2 :

def copy2(destination_customer)
 ActiveRecord::Base.transaction do
 Order.includes(:customer, :part, :upc).where(:customer_id => self.id).find_in_batches(:batch_size => 50) do |batch|
 batch.each do |order|
 new_order = order.dup
 new_order.parts << order.parts.each {|part| tmp = part.dup; tmp.id = tmp.order_id = nil; tmp}
 new_order.upcs << order.upcs.each {|upcs| tmp = upc.dup; tmp.id = tmp.order_id = nil; tmp}
 destination_customer.orders << new_ordert
 end
 # Save one batch
 destination_customer.save!
 end
 end
 end

Can anyone suggest performance friendly way to do this from your own experience? How would you approach this issue if you had one?

asked Jul 23, 2013 at 13:38
\$\endgroup\$
1
  • \$\begingroup\$ Wouldn't it be better to simply point the second customer to the same order, rather than introducing duplication and a deep copy? Or do you want the orders to be updated independently after the copy? \$\endgroup\$ Commented Aug 1, 2013 at 2:08

1 Answer 1

2
\$\begingroup\$

The #dups are probably unnecessary. If you unset the ID ActiveRecord already "thinks" that the object is new, and #save will create a new one in the DB. But the main bottleneck is probably the amount of DB queries generated. The easiest way to gain some performance in such cases is to wrap the whole block into a transaction. The best way would probably use bulk inserts (e.g. with a gem like https://github.com/zdennis/activerecord-import).

But if you've to do so many deep copies you also should rethink if you're using the right approach (or DB) here.

answered Aug 29, 2013 at 9:00
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.