ActiveRecord迁移无法填充Postgres材料化视图

12

我有一个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 文件中,它显示被创建为 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;

我认为这是真正的问题,但我不知道有什么解决方法/变通方法。这也令人困惑,因为即使它是使用NO DATA创建的,后续的REFRESH MATERIALIZED VIEW应该会填充它并将其标记为可扫描。

是否有一些关于Postgres或AR的问题,我不知道,这导致我无法填充这个材料化视图?


1
你尝试过在没有ActiveRecord和Rails的情况下创建和使用视图吗? - mu is too short
1
你解决了这个问题吗?我也遇到了同样的事情。 - Kote
我不这么认为,如果我知道答案的话,我肯定会回答的。 - Tyler
2个回答

3

我知道这个问题已经被问了将近两年,但也许我的答案对其他人有用。

尝试使用 scenic gem。我最近写了一篇关于它的博客文章


那个 gem 看起来很不错。感谢提供链接。然而,除了编写一个类似于 OP 创建的迁移之外,我并没有看到它能够实现什么。有任何想法为什么 scenic 能够工作而手动操作却不能?感谢您的任何见解。 - Eric D. Fields
1
对我来说,Scenic Lib也是一样的。它无缘无故地添加了NO DATA。 - Kote

0

我相信你需要为调用物化视图的refresh设置自己的策略。Scenic gem有一个值得研究的刷新方法

你可以查看before hooks(用于规范/测试)或rake before hook任务,使这个刷新更加轻松(例如,在调用migrate后自动链接刷新)

有趣的是,Postgres通过pg_dump命令转储创建WITH DATA的物化视图也会作为WITH NO DATA转储。我不确定根本原因,但我认为这是按设计工作的,基于运行转储的目的。

然而,pg_dump在转储文件中也包括一个REFRESH命令(Rails没有),这就是为什么你需要想出自己的刷新物化视图的策略。

经过进一步的挖掘,我注意到传递给pg_dump命令的--schema-only标志不会转储REFRESH MATERIALIZED VIEW命令。对于Postgres,Rails的db:structure:dump命令似乎使用此命令(作为-s)。这可能足以帮助您识别更改行为的方法,但我认为另一个答案建议使用scenic,再加上一些rake任务来自动刷新,可能是您最好的选择。
参考:https://github.com/rails/rails/blob/8f2caec401c8e97d9eb1ea84d8263911c50e1ed6/activerecord/lib/active_record/tasks/postgresql_database_tasks.rb#L64

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接