ActiveRecord 迁移未填充 Postgres 物化视图

Posted

技术标签:

【中文标题】ActiveRecord 迁移未填充 Postgres 物化视图【英文标题】:ActiveRecord migration not populating a Postgres materialized view 【发布时间】:2016-06-24 08:59:54 【问题描述】:

我有一个通过迁移创建的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 是否存在一些我不知道的问题,导致我无法填充此物化视图?

【问题讨论】:

您是否尝试过在没有 ActiveRecord 和 Rails 的情况下创建和使用视图? 您解决了这个问题吗?我有同样的事情 我不这么认为,如果我回答了,我想我会回答这个问题。 【参考方案1】:

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

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

【讨论】:

那颗宝石看起来很棒。感谢您的链接。但是,除了像 OP 创建的那样写出迁移之外,我看不到它完成了什么。任何想法为什么风景作品和手动做它不?感谢您的任何见解。 对我来说,风景 lib 也是如此。它无缘无故地添加了 NO DATA【参考方案2】:

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

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

有趣的是,Postgres 也将创建的物化视图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

【讨论】:

以上是关于ActiveRecord 迁移未填充 Postgres 物化视图的主要内容,如果未能解决你的问题,请参考以下文章

活动记录关联未保存在数据库中

带有 UUID 主键的 ActiveRecord 迁移

如何编写迁移以重命名 Rails 中的 ActiveRecord 模型及其表?

是否有任何与 rails ActiveRecord 迁移相当的 Firestore 数据库模式迁移概念?

如何将现有的一对多关系迁移到 Rails 和 ActiveRecord 中的多对多

有没有办法在后续 Rails 3 ActiveRecord 迁移中删除 id 列?