我有以下API端点,它构建一个DateTime
个对象数组,然后遍历它。对于每个日期,代码会查找当天更新的帖子并获取completed_requests_count
。然后它将它们相加并将该数据推送到data
对象以进一步处理并返回给客户端。整个过程相当缓慢。现在,只需要执行此代码的ActiveRecord
部分,平均需要400毫秒。
我想知道的是我如何进一步优化它以将时间缩短一半(或更好)。瓶颈似乎在两个each
块内。有没有办法迭代日期并提取我需要的值而不需要为每次迭代执行单独的查询?
def dashboard_metrics
# Get all TwitterPosts, FacebookPosts, LinkedInPosts, and InstagramPosts
tw_posts = current_user.twitter_posts
fb_posts = current_user.facebook_posts
li_posts = current_user.linked_in_posts
ig_posts = current_user.instagram_posts
# Build date range if custom dates selected
if params[:start_date].present? && params[:end_date].present?
@start_date = DateTime.parse(params[:start_date]).midnight
@end_date = DateTime.parse(params[:end_date]).midnight
# Build array of DateTime objects
dates = (@start_date..@end_date).to_a
num_days = dates.count
dates_for_last_period = ((@end_date - (2 * num_days).days)..(@start_date - 1.day)).to_a
else
# Number of days for window
num_days = params[:num_days].present? && params[:num_days].to_i > 0 ? params[:num_days].to_i : 30
# Build array of DateTime objects
dates = (0..num_days).map { |n| (DateTime.now - n.days).midnight }.reverse
dates_for_last_period = ((num_days + 1)..(num_days * 2)).map { |n| (DateTime.now - n.days).midnight }.reverse
end
# Initialize data object
data = [{ key: 'Twitter', values: [] }, { key: 'Facebook', values: [] }, { key: 'LinkedIn', values: [] }, { key: 'Instagram', values: [] }]
# Initialize Reach and Value counts
reach_this_period = 0
reach_last_period = 0
# Iterate over array of DateTime objects and increment/push values for each date to data object
dates.each do |date|
# Get Amplify counts for each post type and multiply by average follower/friend count for platform
tw_amplify_count = (tw_posts.where("twitter_posts.updated_at >= ? and twitter_posts.updated_at < ?", date, date + 1).pluck(:completed_requests_count).reduce(:+) || 0) * 300
fb_amplify_count = (fb_posts.where("facebook_posts.updated_at >= ? and facebook_posts.updated_at < ?", date, date + 1).pluck(:completed_requests_count).reduce(:+) || 0) * 350
li_amplify_count = (li_posts.where("linked_in_posts.updated_at >= ? and linked_in_posts.updated_at < ?", date, date + 1).pluck(:completed_requests_count).reduce(:+) || 0) * 700
ig_amplify_count = (ig_posts.where("instagram_posts.updated_at >= ? and instagram_posts.updated_at < ?", date, date + 1).pluck(:completed_requests_count).reduce(:+) || 0) * 200
# Push [date, amplify_count] pairs to data object for each post type
data[0][:values] << [date, tw_amplify_count]
data[1][:values] << [date, fb_amplify_count]
data[2][:values] << [date, li_amplify_count]
data[3][:values] << [date, ig_amplify_count]
reach_this_period += tw_amplify_count + fb_amplify_count + li_amplify_count + ig_amplify_count
end
# Iterate over array of DateTime objects for previous N days and get sign_in and confirmation counts
dates_for_last_period.each do |date|
# Get Amplify counts for each post type and multiply by average follower/friend count for platform
tw_amplify_count = (tw_posts.where("twitter_posts.updated_at >= ? and twitter_posts.updated_at < ?", date, date + 1).pluck(:completed_requests_count).reduce(:+) || 0) * 208
fb_amplify_count = (fb_posts.where("facebook_posts.updated_at >= ? and facebook_posts.updated_at < ?", date, date + 1).pluck(:completed_requests_count).reduce(:+) || 0) * 200
li_amplify_count = (li_posts.where("linked_in_posts.updated_at >= ? and linked_in_posts.updated_at < ?", date, date + 1).pluck(:completed_requests_count).reduce(:+) || 0) * 390
ig_amplify_count = (ig_posts.where("instagram_posts.updated_at >= ? and instagram_posts.updated_at < ?", date, date + 1).pluck(:completed_requests_count).reduce(:+) || 0) * 104
reach_last_period += tw_amplify_count + fb_amplify_count + li_amplify_count + ig_amplify_count
end
# Do some more stuff with all the data we just grabbed and return it to the client
end