ActiveRecord迁移不填充Postgres物化视图

时间:2016-03-09 19:28:35

标签: ruby-on-rails ruby postgresql activerecord materialized-views

我有一个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是否存在一些我不知道的问题阻止我填充这个物化视图?

2 个答案:

答案 0 :(得分:2)

我知道这问题差不多是在2年前提出的,但也许我的回答对其他人有用。

尝试使用scenic gem。我最近写过关于它的a blog post

答案 1 :(得分:0)

我认为您需要设置自己的策略以在物化视图上调用refresh。风景秀丽的宝石上有一个method for refreshing,值得研究。

您可以在进行钩子操作之前(针对规格/测试)进行查看,或者在进行钩子任务之前进行扫描,以使此刷新更加轻松(例如,在调用migrate之后自动链接刷新)

有趣的是,Postgres转储(通过pg_dump命令)将物化视图也创建为WITH DATA的{​​{1}}。我不确定根本原因,但我假设这是基于运行转储的目的而设计的。

但是,WITH NO DATA确实在转储文件中包含了pg_dump命令(rails没有),这就是为什么您需要提出自己的策略来刷新实例化视图的原因。

进一步挖掘之后,我注意到传递给REFRESH命令的--schema-only标志不会转储pg_dump命令。 Postgres的rails REFRESH MATERIALIZED VIEW命令似乎使用了此命令(如db:structure:dump)。这可能足以帮助您确定一种改变行为的方式,但是我认为建议使用-s的另一个答案以及结合自动执行刷新的rake任务可能是您的最佳选择。

参考:https://github.com/rails/rails/blob/8f2caec401c8e97d9eb1ea84d8263911c50e1ed6/activerecord/lib/active_record/tasks/postgresql_database_tasks.rb#L64