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 Location
s 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?
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With