Reputation: 634
How can I improve this query?
f, s, t, ft, et, tf = [], [], [], [], [], []
reports = pros.each do |pro|
pro_report = pro.project_reports.where(project_id: project_id).size
f << pro_report.where(position: 1).size
s << pro_report.where(position: 2).size
t << pro_report.where(position: 3).size
ft << pro_report.where('position BETWEEN ? AND ?', 4, 10).size
et << pro_report.where('position BETWEEN ? AND ?', 11, 20).size
tf << pro_report.where('position BETWEEN ? AND ?', 21, 50).size
end
{f: f.sum, s: s.sum, t: t.sum, ft: ft.sum, et: et.sum, tf: tf.sum}
Is it a good idea to create a Postgres VIEW? How can I do that? Any improvement on speed or structure is welcomed.
Thank you.
Upvotes: 0
Views: 49
Reputation: 4860
There is no need for the loop. Do it as below
pro_ids = pros.map(&:id)
pro_reports = ProjectReport.where(project_id: pro_ids)
f = pro_reports.where(position: 1).size
s = pro_reports.where(position: 2).size
t = pro_reports.where(position: 3).size
ft = pro_reports.where('position BETWEEN ? AND ?', 4, 10).size
et = pro_reports.where('position BETWEEN ? AND ?', 11, 20).size
tf = pro_reports.where('position BETWEEN ? AND ?', 21, 50).size
Remember to have a proper index in the position column - in that case is a must.
Alternatively you can do a single query to the database grouping by position and then use Ruby Hash#select
and Rails Enumerable#sum
to get the desired values:
pro_ids = pros.map(&:id)
hash_pos_count = ProjectReport.where(project_id: pro_ids).group(:position).size
f = hash_pos_count.select{ |k, v| k == 1 }.first.last
...
ft = hash_pos_count.select{ |k, v| k >= 3 && k <= 10 }.sum(&:last)
...
Upvotes: 1
Reputation: 1439
Since in your scenario most of the queries are on position
field I would suggest making and index on that field.
Upvotes: 1