Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Speeding up large data graph query and rendering with AMS

I have a query that spans multiple tables which in the end uses Active Model Serializers to render the data. Currently a large portion of the time is spent in the serializers since I am forced to query some of the data from within the serializer itself. I want to find a way to speed this up, and that may be not using AMS (this is okay).

My data model is as follows:

Location
  -> Images
  -> Recent Images
  -> Days Images
Image
  -> User

The recent_images and days_images are the same as the images but with a scope to do a where to filter by days and limit to 6.

Currently this whole process takes about 15 seconds locally and 2-4 seconds in production. I feel like I can perform this much quicker but am not entirely sure how I can modify my code.

The query to fetch the Locations is:

ids = @company
  .locations
  .active
  .has_image_taken
  .order(last_image_taken: :desc)
  .page(page)
  .per(per_page)
  .pluck(:id)
Location.fetch_multi(ids)

fetch_multi is from the identity_cache gem. These results then hit the serializer which is:

class V1::RecentLocationSerializer < ActiveModel::Serializer
  has_many :recent_images, serializer: V1::RecentImageSerializer do
    if scope[:view_user_photos]
      object.fetch_recent_images.take(6)
    else
      ids = object.recent_images.where(user_id: scope[:current_user].id).limit(6).pluck(:id)
      Image.fetch_multi(ids)
    end
  end

  has_many :days_images do
    if scope[:view_user_photos]
      object.fetch_days_images
    else
      ids = object.days_images.where(user_id: scope[:current_user].id).pluck(:id)
      Image.fetch_multi(ids)
    end
  end
end

The scopes for recent and days images is:

scope :days_images, -> { includes(:user).active.where('date_uploaded > ?', DateTime.now.beginning_of_day).ordered_desc_by_date }
scope :recent_images, -> { includes(:user).active.ordered_desc_by_date }

My question is if you think I need to ditch AMS so I don't have to query in the serializer, and if so, how would you recommend to render this?

like image 406
CWitty Avatar asked Nov 07 '22 23:11

CWitty


1 Answers

I may have missed the point here - what part is slow? What do the logs look like? Are you missing a db index? I don't see a lot of joins in there, so maybe you just need an index on date_uploaded (and maybe user_id). I don't see anything in there that is doing a bunch of serializing.

You can easily speed up the sql in many ways - like, a trigger (in ruby or sql) that updates the image with a user_active boolean so you can dump that join. (you'd include that in the index)

OR build a cached table just with the IDs in it. Kind of like an inverted index (I'd also do it in redis, but that's me) that has a row for each user/location that is updated when an image is uploaded.

Push the work to the image upload rather than where it is now, viewing the list.

like image 122
court3nay Avatar answered Nov 15 '22 06:11

court3nay