diff --git a/app/controllers/projects/cycle_analytics_controller.rb b/app/controllers/projects/cycle_analytics_controller.rb
index ed885729fbba0953e4d253601a98b5f23d01e01c..9dab7bfa3808d5e86f8ea09785763c84176682e8 100644
--- a/app/controllers/projects/cycle_analytics_controller.rb
+++ b/app/controllers/projects/cycle_analytics_controller.rb
@@ -1,32 +1,5 @@
 class Projects::CycleAnalyticsController < Projects::ApplicationController
   def show
-    @metrics = {
-      issue: issue
-    }
-  end
-
-  private
-
-  def issue
-    query = <<-HEREDOC
-       WITH ordered_data AS (
-         SELECT extract(milliseconds FROM (COALESCE(first_associated_with_milestone_at, first_added_to_board_at) - issues.created_at)) AS data_point,
-                row_number() over (order by (COALESCE(first_associated_with_milestone_at, first_added_to_board_at) - issues.created_at)) as row_id
-         FROM issues
-         INNER JOIN issue_metrics ON issue_metrics.issue_id = issues.id
-         WHERE COALESCE(first_associated_with_milestone_at, first_added_to_board_at) IS NOT NULL
-       ),
-
-       ct AS (
-         SELECT count(1) AS ct
-         FROM ordered_data
-       )
-
-       SELECT avg(data_point) AS median
-       FROM ordered_data
-       WHERE row_id between (select ct from ct)/2.0 and (select ct from ct)/2.0 + 1;
-    HEREDOC
-
-    ActiveRecord::Base.connection.execute(query).to_a.first['median']
+    @cycle_analytics = CycleAnalytics.new
   end
 end
diff --git a/app/models/cycle_analytics.rb b/app/models/cycle_analytics.rb
new file mode 100644
index 0000000000000000000000000000000000000000..d037b1fef121a602fee54df5eeca50e853187ada
--- /dev/null
+++ b/app/models/cycle_analytics.rb
@@ -0,0 +1,40 @@
+class CycleAnalytics
+  def issue
+    issues = Issue.includes(:metrics).where("issue_metrics.id IS NOT NULL").references(:issue_metrics).to_a
+    start_time_fn = -> (issue) { issue.created_at  }
+    end_time_fn = -> (issue) { issue.metrics.first_associated_with_milestone_at.presence || issue.metrics.first_added_to_board_at.presence }
+
+    calculate_metric(issues, start_time_fn, end_time_fn)
+  end
+
+  def plan
+    issues = Issue.includes(:metrics).where("issue_metrics.id IS NOT NULL").references(:issue_metrics).to_a
+    start_time_fn = -> (issue) { issue.metrics.first_associated_with_milestone_at.presence || issue.metrics.first_added_to_board_at.presence }
+    end_time_fn = lambda do |issue|
+      merge_requests = issue.closed_by_merge_requests
+      merge_requests.map(&:created_at).min if merge_requests.present?
+    end
+
+    calculate_metric(issues, start_time_fn, end_time_fn)
+  end
+
+  private
+
+  def calculate_metric(data, start_time_fn, end_time_fn)
+    times = data.map do |data_point|
+      start_time = start_time_fn[data_point]
+      end_time = end_time_fn[data_point]
+
+      if start_time.present? && end_time.present?
+        end_time - start_time
+      end
+    end
+
+    median(times.compact)
+  end
+
+  def median(coll)
+    size = coll.length
+    (coll[size / 2] + coll[(size - 1) / 2]) / 2.0
+  end
+end
diff --git a/app/views/projects/cycle_analytics/show.html.haml b/app/views/projects/cycle_analytics/show.html.haml
index e9bdd71b30aca896400fd9d7b4fdd77d8e5bba7e..6aad68617fee575b36ec4658dd2a3db6f38cdcc1 100644
--- a/app/views/projects/cycle_analytics/show.html.haml
+++ b/app/views/projects/cycle_analytics/show.html.haml
@@ -1 +1,8 @@
-%pre= @metrics
+%ul.list-group
+  %li.list-group-item
+    Issue:
+    = distance_of_time_in_words @cycle_analytics.issue
+
+  %li.list-group-item
+    Plan:
+    = distance_of_time_in_words @cycle_analytics.plan