默认情况下,Rails不会填充Postgres物化视图

时间:2018-12-01 13:45:51

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

我要进行以下迁移:

  execute <<-SQL
    CREATE TABLE test_table(
      name char(20)
    );
    INSERT INTO test_table(name) values ('test name');

    CREATE MATERIALIZED VIEW test AS
      SELECT * from test_table
    WITH DATA;
  SQL

请注意,我添加了“ WITH DATA”。 这不会填充数据(当我尝试在视图上进行并发刷新时,由于出现“未填充实体化视图”错误),因此在structure.sql中添加了“ WITH NO DATA”:

CREATE MATERIALIZED VIEW public.test AS
 SELECT test_table.name
   FROM public.test_table
  WITH NO DATA;

我在做什么错?关于实例化视图的Postgres文档说该查询已执行,并在发出命令时用于填充视图(除非使用WITH NO DATA)因此,即使未指定“ WITH DATA”,它也应生成“默认情况下为WITH DATA”,但我却收到“ WITH NO DATA”。 当我使用风景秀丽的图书馆时,它也做同样的事情……

我的问题似乎类似于ActiveRecord migration not populating a Postgres materialized view

编辑 我了解到数据实际上是在开发环境中填充的(尽管它在WITH NO DATA中设置了structure.sql)。问题出在测试环境中,有时它不会填充数据。仍在调查原因...但是不幸的是,structure.sql绝对是不正确的。

1 个答案:

答案 0 :(得分:1)

我希望现在还不晚18个月才有用,但这是我解决此问题的方法。

假设您正在使用(强烈推荐!)scenic gem,

假设您的物化视图支持模型如下所示。我已经稍微修改了refresh方法,以将concurrently作为参数。

class Foo < ApplicationRecord
  # if you're using the excellent "scenic" gem
  def self.refresh(concurrently:)
    Scenic.database.refresh_materialized_view(table_name, concurrently: concurrently, cascade: false)
  end

  # if you're not using the excellent "scenic" gem (why not?)
  # have not tested this but should work
  def self.refresh(concurrently:)
    concurrently_string = concurrently ? "CONCURRENTLY" : ""
    ActiveRecord::Base.connection.execute(
      "REFRESH MATERIALIZED VIEW #{table_name} #{concurrently_string} WITH DATA"
    )
  end

  private

  def readonly?
    true
  end
end

然后,在spec/rails_helper.rb中,仅对每个实例化视图支持的模型执行此操作:

config.before(:suite) do
  Foo.refresh(concurrently: false)
  Bar.refresh(concurrently: false)
  # etc.
end 

请注意,在个别测试中,如果您希望它们反映您已插入到基础表中的数据,在某些情况下仍可能需要手动调用#refresh