From 8ee830e8258fe0ac1db01d7c64087b51abda9a65 Mon Sep 17 00:00:00 2001
From: Sam <sam.saffron@gmail.com>
Date: Fri, 8 Jul 2016 12:54:03 +1000
Subject: [PATCH] PERF: improve performance of weekly job

---
 lib/score_calculator.rb | 54 +++++++++++++++++++++++++++--------------
 1 file changed, 36 insertions(+), 18 deletions(-)

diff --git a/lib/score_calculator.rb b/lib/score_calculator.rb
index a9ee09758..681877bda 100644
--- a/lib/score_calculator.rb
+++ b/lib/score_calculator.rb
@@ -32,40 +32,58 @@ class ScoreCalculator
   private
 
   def update_posts_score(min_topic_age)
+    limit = 20000
+
     components = []
     @weightings.each_key { |k| components << "COALESCE(#{k}, 0) * :#{k}" }
     components = components.join(" + ")
 
-    builder = SqlBuilder.new(
-      "UPDATE posts SET score = x.score
-       FROM (SELECT id, #{components} as score FROM posts) AS x
-       /*where*/"
+    builder = SqlBuilder.new <<SQL
+       UPDATE posts p
+        SET score = x.score
+       FROM (
+        SELECT id, #{components} as score FROM posts
+        /*where*/
+        limit #{limit}
+       ) AS x
+       WHERE x.id = p.id
+SQL
 
-    )
-
-    builder.where("x.id = posts.id
-                  AND (posts.score IS NULL OR x.score <> posts.score)", @weightings)
+    builder.where("score IS NULL OR score <> #{components}", @weightings)
 
     filter_topics(builder, min_topic_age)
 
-    builder.exec
+    while builder.exec.cmd_tuples == limit
+    end
   end
 
   def update_posts_rank(min_topic_age)
+    limit = 20000
 
-    builder = SqlBuilder.new("UPDATE posts SET percent_rank = x.percent_rank
-              FROM (SELECT id, percent_rank()
-                    OVER (PARTITION BY topic_id ORDER BY SCORE DESC) as percent_rank
-                    FROM posts) AS x
-                   /*where*/")
-
-    builder.where("x.id = posts.id AND
-               (posts.percent_rank IS NULL OR x.percent_rank <> posts.percent_rank)")
+    builder = SqlBuilder.new <<SQL
+UPDATE posts
+SET percent_rank = X.percent_rank
+FROM (
+  SELECT posts.id, Y.percent_rank
+  FROM posts
+  JOIN (
+    SELECT id, percent_rank()
+                 OVER (PARTITION BY topic_id ORDER BY SCORE DESC) as percent_rank
+    FROM posts
+   ) Y ON Y.id = posts.id
+  /*where*/
+  LIMIT #{limit}
+) AS X
+WHERE posts.id = X.id
+SQL
 
+    builder.where("posts.percent_rank IS NULL OR Y.percent_rank <> posts.percent_rank")
 
     filter_topics(builder, min_topic_age)
 
-    builder.exec
+    while builder.exec.cmd_tuples == limit
+    end
+
   end
 
   def update_topics_rank(min_topic_age)