Миграция ActiveRecord не заполняет материализованное представление Postgres

У меня есть MATERIALIZED VIEW это создается с помощью миграции.

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

Примечание: я запутал оператор SELECT, просто поверьте мне, что он работает.

Здесь важно отметить, что я явно назвал WITH DATA, поэтому представление должно быть заполнено и сканируемо сразу.

Этого не происходит. Миграция выполняется, как показано ниже

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

Позже в db:refresh мы видим следующее

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.

Хм что? Я объявил WITH DATA, У меня также есть другая последовательная миграция, которая явно вызывает REFRESH MATERIALIZED VIEW Команда на вид.

Безрезультатно, чтобы завершить задачу rake db: refresh, я должен войти и вручную обновить представление.

Интересное примечание: в файле Structure.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 NO DATA;

Я считаю, что это реальная проблема, но я не знаю, как исправить / обойти. Это также сбивает с толку, потому что даже если он был создан без данных, последующий REFRESH MATERIALIZED VIEW должен заполнить его и пометить как сканируемый.

Есть ли какая-то проблема с Postgres или AR, о которой я не знаю, которая мешает мне заполнить это материализованное представление?

1 ответ

Я знаю, что вопрос задавался почти 2 года назад, но, возможно, мой ответ будет полезен для кого-то еще.

Попробуйте использовать сценический драгоценный камень. Я недавно написал в блоге об этом.

Я считаю, что вам нужно настроить свою собственную стратегию для вызова refresh на материализованных взглядах. У сценического драгоценного камня есть метод освежения, который стоит изучить.

Вы можете посмотреть перед хуками (для спецификаций / тестов) или грабли перед задачами хуков, чтобы сделать это обновление немного более безболезненным (автоматическое объединение в цепочку после вызова migrate, например)

Интересно, что дампы Postgres (через pg_dump команда) материализованные представления созданы WITH DATA как WITH NO DATA также. Я не уверен, что основная причина, но я предполагаю, что это работает как задумано, основываясь на цели запуска дампа.

Тем не мение, pg_dump Также включает в себя REFRESH Команда в дамп-файле (rails не делает), поэтому вам нужно придумать свою собственную стратегию обновления материализованного представления.

После дальнейших раскопок я заметил --schema-only флаг передан pg_dump Команда не будет сбрасывать REFRESH MATERIALIZED VIEW команда. Рельсы db:structure:dump Команда для Postgres, кажется, использует эту команду (как -s). Этого может быть достаточно, чтобы помочь вам определить способ изменить поведение, но я думаю, что другой ответ рекомендует использовать scenic, в сочетании с некоторыми рейк-задачами для автоматического обновления может быть лучшим выбором.

Ссылка: https://github.com/rails/rails/blob/8f2caec401c8e97d9eb1ea84d8263911c50e1ed6/activerecord/lib/active_record/tasks/postgresql_database_tasks.rb#L64

Другие вопросы по тегам