I been all day trying to refactor my queries. It was taking several minutes for a table with 20 records to load. At first, I blamed the query in this stackoverflow post:
rails - using Rails.cache gives error
However, after doing some testing, I realized that query was loading very fast, and was not the culprit.
Then I blamed it on kaminari, as I thought that kaminari was populating thousands of records into ruby objects, as I explained in this post:
But that was wrong too. Kaminari was only loading 20 records at a time (I used the logger to check how many reports where being loaded and it showed 20).
So finally I think I found the real culprit. It is another query that occurs during the pagination of that page. I realized that this query is taking more than 20 seconds to load each time it is run:
def virtual_fence_duration
inside_fence_time = nil
outside_fence_time = nil
outside_fence_time = self.time
previous_reports = Report.where{(time < my{self.time}) &
(unit_id == my{self.unit_id})}.order('time desc')
previous_reports.each do |report|
alerts = report.alerts.collect { |a| a.code_name }
if alerts.include? "Inside virtual fence"
inside_fence_time = report.time
break
end
end
if inside_fence_time && outside_fence_time
"Virtual Fence Elapsed Time: #{(((outside_fence_time - inside_fence_time).to_i).to_f/60.0).ceil} minutes"
else
""
end
end
Basically, this method gets called when there is an alert that is "outside virtual fence". I store the time. And then I query all the reports previous to it (reports has_many alerts). Then I use the each iterator of ruby to go through every single report and then the alerts associated with those reports to find the alert that is "inside virtual fence". Then I store the time of that report and take the difference between the two times. This logic seems to be taking forever if there are alot of reports between the two durations. Is there a more efficient way to do this in sql (mysql) or ruby?