From b139087c5fbaffbf54ae5b4b43bef07d262687b6 Mon Sep 17 00:00:00 2001 From: Matt-Yorkley <9029026+Matt-Yorkley@users.noreply.github.com> Date: Thu, 11 May 2023 20:28:28 +0100 Subject: [PATCH 1/2] Clone ExchangeVariant objects in bulk An ExchangeVariant is a simple representation of a join table between Exchange and Variant. Previously this code was triggering an additional INSERT query for every variant added to the newly cloned exchange. Some exchanges have ~3000 variants! The code now creates them in bulk in a single INSERT statement. When cloning large order cycles this can improve performance by ~1000% or so. --- app/models/exchange.rb | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/app/models/exchange.rb b/app/models/exchange.rb index a315ccd1c6..2522d5622d 100644 --- a/app/models/exchange.rb +++ b/app/models/exchange.rb @@ -86,9 +86,9 @@ class Exchange < ApplicationRecord exchange = dup exchange.order_cycle = new_order_cycle exchange.enterprise_fee_ids = enterprise_fee_ids - exchange.variant_ids = variant_ids exchange.tag_ids = tag_ids exchange.save! + clone_all_exchange_variants(exchange.id) exchange end @@ -105,4 +105,14 @@ class Exchange < ApplicationRecord receiver.touch_later end + + private + + def clone_all_exchange_variants(exchange_id) + return unless variant_ids.any? + + ExchangeVariant.insert_all( + variant_ids.map{ |variant_id| { variant_id: variant_id, exchange_id: exchange_id } } + ) + end end From 636b365304966bd5ff64b4cdcc08753fb765415f Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Fri, 12 May 2023 10:30:47 +1000 Subject: [PATCH 2/2] Tell Rubocop and devs about bulk insert --- app/models/exchange.rb | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/models/exchange.rb b/app/models/exchange.rb index 2522d5622d..e52d412c96 100644 --- a/app/models/exchange.rb +++ b/app/models/exchange.rb @@ -108,10 +108,13 @@ class Exchange < ApplicationRecord private + # An Order Cycle can have thousands of ExchangeVariants. + # It's a simple association without any callbacks on creation. So we can + # insert in bulk and improve the performance tenfold for large order cycles. def clone_all_exchange_variants(exchange_id) return unless variant_ids.any? - ExchangeVariant.insert_all( + ExchangeVariant.insert_all( # rubocop:disable Rails/SkipsModelValidations variant_ids.map{ |variant_id| { variant_id: variant_id, exchange_id: exchange_id } } ) end