防止 ActiveRecord 迁移对 db/struct.sql 进行巨大更改

Tim*_*and 5 ruby sql postgresql activerecord ruby-on-rails

在测试(而非生产)数据库上运行下面的 ActiveRecord 迁移时,db/structure.sql会出现较大的变化。这是可重现的。变化是:

  • 基于迁移代码的少量预期更改(根据需要)。
  • 大量意外的更改,这些更改与迁移代码无关(不是所希望的)。所有这些意外的更改都重新排列了迁移中 SQL 代码中未提及的表视图和物化视图的顺序。这些重新排列的表、视图和物化视图与迁移中的SQL代码中的项目关联(例如,通过依赖关系)。

是什么导致了这些巨大的不相关差异,最重要的是,如何防止这些巨大的不相关差异

它们是否与生产数据库服务器上的 postgresql 版本和在测试数据库上执行迁移的计算机上的 postgresql 版本不匹配有关?

这些不相关的更改使git diff输出的用处大大降低。GitHub 上的结果也是如此diff

在下面这个最小的示例中,仅重新排列了一些表。但在现实生活中(较大的)迁移中,它改变了数十个表、视图和 matview 的顺序 - 这是一个巨大的变化

class FixFooBarBaz < ActiveRecord::Migration[5.2]

  def up
    sql = <<~SQL
                  DROP VIEW master_foo;
                  DROP VIEW IF EXISTS bar1;
                  CREATE OR REPLACE VIEW bar1 AS
                  SELECT * FROM baz1
                  UNION ALL
                  SELECT * FROM baz2;
                  CREATE OR REPLACE VIEW master_foo AS
                  SELECT
                      *,
                      'bar1' AS bar_type
                  FROM
                      bar1
                  UNION ALL
                  ...
    SQL

    execute sql
  end

  def down
    sql = <<~SQL
                  DROP VIEW IF EXISTS master_foo;
                  DROP VIEW IF EXISTS bar1;
                  ...
    SQL

    execute sql
  end
end 
Run Code Online (Sandbox Code Playgroud)

使用的硬件/软件:

执行迁移的机器:

MacBookPro, Apple M1 Max, macOS Sonoma 14.2.1
ruby 2.7.3p183 (2021-04-05 revision 6847ee089d) [arm64-darwin21]
15.3 psql (PostgreSQL) 15.3 (Homebrew)
Run Code Online (Sandbox Code Playgroud)

生产数据库服务器:

psql (14.9 (Homebrew), server 13.3 (Ubuntu 13.3-1.pgdg20.04+1))
Run Code Online (Sandbox Code Playgroud)

mar*_*ets 3

是的,这可能是由于您在不同的机器和/或配置(例如安装的插件)之间使用的数据库引擎的不同版本造成的。示例:克隆存储库并从头开始重新创建数据库后structure.sql,现在此文件中出现一些意外的更改: https: //github.com/coopdevs/timeoverflow/pull/713/files

其他可能的原因是:Rails(Active Record)为了更好的可读性、一致性或任何其他原因进行了内部更改。示例:https: //github.com/rails/rails/issues/44571

请记住,文件中表或视图顺序的差异structure.sql(同样适用于方法schema.rb)通常不会影响 Rails 应用程序的功能。但要小心,如果您看到其他类型的更改,请仔细检查它们(例如,在 MySQL 中,我看到了排序规则字符的更改,这可能会在您的应用程序中导致实际的奇怪问题)。

关于“顺序”,可以通过在迁移中使用:before和选项来强制执行。:after例子:

create_table :my_table, before: :my_other_table
Run Code Online (Sandbox Code Playgroud)

这些选项也适用于列:

add_column :my_table, :my_new_attribute, :integer, after: :my_other_column
Run Code Online (Sandbox Code Playgroud)