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 物化视图的主要内容,如果未能解决你的问题,请参考以下文章
如何编写迁移以重命名 Rails 中的 ActiveRecord 模型及其表?
是否有任何与 rails ActiveRecord 迁移相当的 Firestore 数据库模式迁移概念?