Rails默认不填充Postgres物质化视图。

问题描述 投票:1回答:1

我有以下迁移。

  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".这并没有填充数据(因为当我试图对视图进行并发刷新时,我得到了 "materialized view has not been populated "的错误信息),并在 "WITH NO DATA "中添加了 "WITH NO DATA"。structure.sql:

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迁移不填充Postgres物质化视图。

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

ruby-on-rails postgresql materialized-views
1个回答
0
投票

我希望这不是十八个月后才有用,但这是我解决这个问题的方法。

假设你正在使用(强烈推荐!)的 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 在某些情况下,如果你想让它们反映出你已经插入到底层表中的数据,则需要手动操作。

© www.soinside.com 2019 - 2024. All rights reserved.