Lazy Loading BLOBs in Active Record
Author: ceefour | Filed under: Beginner, Complaints, Opinions, Rails, Ruby, Tips, Web 2.0If you're new here, you may want to subscribe to my RSS feed. Thanks for visiting!
One of the performance-hurting issue in current Active Record is that it doesn’t allow you to lazy load BLOB columns (and sometimes, TEXT columns), which can contain huge data. Usually there’s nothing wrong, theoretically, with loading all columns. But let’s see how we can improve performance by lazy loading these columns…
Using Views to Lazy Load Columns
My workaround is not to create a separate table, but just create a separate view (I’m using PostgreSQL, but I believe you can do that too with recent MySQL). This view doesn’t contain the blob fields. I use set_table_name in the model to use this view. Since the view is updatable (in PostgreSQL you have to create several RULEs on the view to make it insert/update/delete-able), Active Record doesn’t know it’s dealing with a “fake” table.
Whenever I want to load/update the actual content all I had to do is issue a select_value(“SELECT content FROM photos WHERE ID=?”, …) something like that. Usually you won’t need finder features just to load the lazy blob, only the corresponding ID(s).
The steps:
- Create a database view based on the original table, omitting the columns you want to lazy-load.
- Make sure the view is updatable.
- Use ActiveRecord::Base.set_table_name class method in your model to use the database view you just created.
- Add accessors on your model to read/write lazyloaded columns using plain SQL.
Perhaps there is already a plugin to handle this, but a quick Google search didn’t reveal this. ![]()
Caching Processed Images
The next thing you may want to do is cache some BLOBs (or processed BLOBs) to files so Apache (or whatever your web server is) serves them directly, which is much faster than Rails processing.
I don’t actually cache all images, since my photos table contain huge blobs (usually over 100 KB each). I only cache the thumbnails. At first request to a photo thumbnail, my app will process it using rmagick, then save the generated thumbnail into some folder in RAILS_ROOT/tmp. I have a special RewriteCond/RewriteRule directive in .htaccess so that if a requested thumbnail is already there, Rails won’t be ran at all and Apache serves it directly. This makes thumbnails *very* fast. (I symlink in RAILS_ROOT/public/tmp_thumbnails to the tmp/thumbnails folder)
Were I able to use memcached maybe I’ll use that too. Unfortunately not all hosting services provide this luxury.
Steps:
- Create a temporary folder. Example: #{RAILS_ROOT}/tmp/thumbnails
- Make a symbolic link in public to that folder: (how about Windows?)
ln -s tmp/thumbnails public/tmp_thumbnails
- Make sure your controller/action works correctly. Save the resulting output to a file in your tmp/thumbnails folder.
- Edit your .htaccess as such:
# Make sure the file exists
RewriteCond %{DOCUMENT_ROOT}/tmp_thumbnails/$1.jpg -f# Rewrite the URL so it points to the file, not Rails
RewriteRule ^thumbnails/(\d+)$ tmp_thumbnails/$1.jpg [L]
Sorry for the too theoretical vague steps.
No related posts.
Related posts brought to you by Yet Another Related Posts Plugin.