加速每个块内的ActiveRecord查询

时间:2016-11-22 23:33:57

标签: ruby activerecord refactoring

我有以下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

0 个答案:

没有答案