From 1fe8b7f646603239f530b1a18427f4f5bc0e2060 Mon Sep 17 00:00:00 2001
From: James Lopez <james@jameslopez.es>
Date: Fri, 5 May 2017 09:40:44 +0200
Subject: [PATCH] refactor propagate service to use batch inserts and subquery
 instead of left join

---
 app/services/projects/propagate_service.rb | 32 ++++++++++++++++++----
 1 file changed, 26 insertions(+), 6 deletions(-)

diff --git a/app/services/projects/propagate_service.rb b/app/services/projects/propagate_service.rb
index 6e24a67d8b0..b067fc2cd64 100644
--- a/app/services/projects/propagate_service.rb
+++ b/app/services/projects/propagate_service.rb
@@ -26,7 +26,7 @@ module Projects
       loop do
         batch = project_ids_batch(offset)
 
-        batch.each { |project_id| create_from_template(project_id) }
+        bulk_create_from_template(batch)
 
         break if batch.size < BATCH_SIZE
 
@@ -34,14 +34,34 @@ module Projects
       end
     end
 
-    def create_from_template(project_id)
-      Service.build_from_template(project_id, @template).save!
+    def bulk_create_from_template(batch)
+      service_hash_list = batch.map do |project_id|
+        service_hash.merge('project_id' => project_id)
+      end
+
+      Project.transaction do
+        Service.create!(service_hash_list)
+      end
     end
 
     def project_ids_batch(offset)
-      Project.joins('LEFT JOIN services ON services.project_id = projects.id').
-        where('services.type != ? OR services.id IS NULL', @template.type).
-        limit(BATCH_SIZE).offset(offset).pluck(:id)
+      Project.connection.execute(
+        <<-SQL
+          SELECT id
+          FROM projects
+          WHERE NOT EXISTS (
+            SELECT true
+            FROM services
+            WHERE services.project_id = projects.id
+            AND services.type = '#{@template.type}'
+          )
+          LIMIT #{BATCH_SIZE} OFFSET #{offset}
+      SQL
+      ).to_a.flatten
+    end
+
+    def service_hash
+      @service_hash ||= @template.as_json(methods: :type).except('id', 'template')
     end
   end
 end
-- 
GitLab