Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ActiveRecord migration not populating a Postgres materialized view

I have a MATERIALIZED VIEW that is created via a migration.

class MyView < ActiveRecord::Migration
  def up
    ActiveRecord::Base.connection.execute <<-SQL
    CREATE MATERIALIZED VIEW my_view AS (
      SELECT DISTINCT something, something_else, other.thing as real_thing, thing.some_id
          FROM some_table
          JOIN another_table on another_table.id = something
          JOIN one_more_table on some_table.id = other_id
          ORDER BY order_column)
      WITH DATA;
    SQL

    add_index :table, [:key_part_one, :key_part_two]
  end

  ...
end

Note: I've obfuscated the SELECT statement, just trust me that it works.

The important part to note here is that I've explicitly called WITH DATA, so the view should be populated and scannable right away.

This is not happening. The migration runs, shown below

==  MyView: migrating ========================
==  MyView: migrated (0.0763s) ===============

Later on in the db:refresh we see the following

Reindexing Something...
Reindex queued
Reindexing Another...
Reindex queued
Reindexing SomeOtherThing...
Reindex queued
Reindexing One::OtherThing...
Reindex queued
Reindexing MyViewModel...
rake aborted!
ActiveRecord::StatementInvalid: PG::ObjectNotInPrerequisiteState: ERROR:  materialized view "my_view" has not been populated
HINT:  Use the REFRESH MATERIALIZED VIEW command.

Um, what? I declared WITH DATA. I also have another consecutive migration that explicitly calls the REFRESH MATERIALIZED VIEW command on the view.

To no avail, in order to get the rake db:refresh task to complete, I have to go in and manually refresh the view.

Interesting note, in the structure.sql file, its shown as being created WITH NO DATA

CREATE MATERIALIZED VIEW my_view AS (
  SELECT DISTINCT something, something_else, other.thing as real_thing, thing.some_id
      FROM some_table
      JOIN another_table on another_table.id = something
      JOIN one_more_table on some_table.id = other_id
      ORDER BY order_column)
  WITH NO DATA;

I believe this is the real issue but I'm unaware of a fix/workaround. Its also confusing because even if it was created WITH NO DATA, the subsequent REFRESH MATERIALIZED VIEW should populate it and mark it as scannable.

Is there some issue with Postgres or AR that I'm not aware of that is preventing me from populating this materialized view?

like image 918
tyler Avatar asked Mar 09 '16 19:03

tyler


People also ask

What are materialized views in Postgres?

Materialized views in Postgres are a handy way to persist the result of a query to disk. This is helpful when the underlying query is expensive and slow yet high performance SELECT queries are required. When using materialized views they need to be explicitly refreshed to show changes to the underlying table.

How do I refresh a materialized view?

When using materialized views they need to be explicitly refreshed to show changes to the underlying table. This is done through the REFRESH MATERIALIZED VIEW <name>; syntax. Keeping materialized views regularly refreshed is often a delegated to a cron job on a schedule.

What is the default behavior of a login role in Postgres?

In Postgres, the default behavior is a login role that is a member of a group role directly inherits the permissions of the group role. This was shown in the previous example where the my_user role can act as the owner of the test_mv materialized view. This is not always the desired behavior and can be changed by setting the role with NOINHERIT.

Is my_user the owner of the materialized view?

Unfortunately, my_user is not the owner of the materialized view and gets the error telling them so. Use RESET ROLE to get back to the super user role. There are two (2) caveats to the error must be owner from Postgres. The first caveat are superuser roles. Superusers bypass security checks.


1 Answers

I know the question was asked almost 2 years ago but maybe my answer will be useful for someone else.

Try using scenic gem. I have recently written a blog post about it.

like image 148
pmichna Avatar answered Oct 16 '22 15:10

pmichna