PostgreSQL Materialized Views in Rails
Jun 19, 2015
Materialized view is a object that contains the query’s results. Unlike database table it doesn’t support INSERT/UPDATE/DELETE opertaions. Since all this operations unsupported to update materialized view you need to call refresh view opertaion. In PostgreSQL materialized views support was introduced in version 9.3.
From PostgreSQL documentation you can see how to create materialized view. So, you need query that you want to materialize and… that all.
Let’s assume you have next structure: books, authors and feedbacks. Each author has many books, each book has many feedbacks
And let’s assume you need to we need to show top authors by their feedbacks. We have Rails ActiveRecord and it seems easy
But three INNER JOINS, isn’t too much? Let’s use our materialized views! Starting from migration:
To be honest, I’m not big fun of using Rails to_sql method and so on and prefer to write pure SQL for such migrations. But it’s sample and we will keep it so.
Each selected column will be materialized view column, that’s why we used as for authors.id, in our table “authors.id” will be stored in “author_id” column. Unlike simple views, we can index any materialized view column, additionaly, we will make it index unique. As I said before, to actualize data in view we need to call refresh view. In pure PostgreSQL it will be:
But in PostgreSQL 9.4 we can do it concurrently! It will refresh the materialized view without locking out concurrent selects on the materialized view, but… You need uniq index on materialized view for this. Wait a minute, we alredy have one!
As I can see, concurrently refreshing much more quick if your index very simple. With complex index it can be even slower then unconcurrent refreshing. As it behave like table we can even use it as ActiveRecord model.
As I said before, materialized view doesn’t support any editing operations, for this we will use concern ReadOnlyModel
And we need to add association for authors
And that’s all, just use it.
P.S. Don’t forget to chnage your dump format, schema.rb can’t store materialized view structure, so, you need to store all this in SQL. Change in application.rb