Techioz Blog

Rails:一意制約を追加すると、structure.sql ファイルとデータベースのインデックスが削除されるのはなぜですか

概要

一意のインデックスを使用する一意の制約を追加するとインデックスが削除されるだけである理由を知りたいのですが、詳しく説明します。次の移行があります。

class AddUniqueIndexOnNamesForProgramsSuppliersCollections < ActiveRecord::Migration[5.2]
  disable_ddl_transaction!

  def up
    execute("CREATE UNIQUE INDEX CONCURRENTLY idx_supplier_company_id_and_name_unique ON public.suppliers USING btree (company_id, name);")
    execute("CREATE UNIQUE INDEX CONCURRENTLY idx_programs_company_id_and_name_unique ON public.programs USING btree (company_id, name);")
    execute("CREATE UNIQUE INDEX CONCURRENTLY idx_collections_supplier_id_and_name_unique ON public.collections USING btree (supplier_id, name);")
  end

  def down
    remove_index :suppliers, name: :idx_supplier_company_id_and_name_unique
    remove_index :programs, name: :idx_programs_company_id_and_name_unique
    remove_index :collections, name: :idx_collections_supplier_id_and_name_unique
  end
end

上記の移行を実行すると、インデックスが Structure.sql ファイルに追加されます。次に、次のような別の移行があります。

class AddUniqueConstraintsOnNamesForProgramsSuppliersCollections < ActiveRecord::Migration[5.2]
  disable_ddl_transaction!

  def up
    sql = <<~END_OF_SQL
      ALTER TABLE public.suppliers ADD CONSTRAINT supplier_company_id_and_name_unique UNIQUE USING INDEX idx_supplier_company_id_and_name_unique;
      ALTER TABLE public.programs ADD CONSTRAINT programs_company_id_and_name_unique UNIQUE USING INDEX idx_programs_company_id_and_name_unique;
      ALTER TABLE public.collections ADD CONSTRAINT collections_supplier_id_and_name_unique UNIQUE USING INDEX idx_collections_supplier_id_and_name_unique;
    END_OF_SQL

    execute(sql)
  end

  def down
    sql = <<~END_OF_SQL
      ALTER TABLE public.suppliers DROP CONSTRAINT supplier_company_id_and_name_unique;
      ALTER TABLE public.programs DROP CONSTRAINT programs_company_id_and_name_unique;
      ALTER TABLE public.collections DROP CONSTRAINT collections_supplier_id_and_name_unique;
    END_OF_SQL
    execute(sql)
  end
end

2 番目の移行を実行すると、インデックスが Structure.sql ファイルと DB から削除され、代わりに制約が追加されます。そのため、インデックスを制約で置き換えているのだと思いますが、両方を使用したいのですが、何かアイデアはありますか?

解決策

PostgreSQL では、制約の名前はそれを実装するインデックスの名前と同じにするという規則があります。

それで、あなたが書くなら

ALTER TABLE tab ADD UNIQUE USING INDEX abc;

制約は abc と呼ばれます。次のように書くと、

ALTER TABLE tab ADD CONSTRAINT def UNIQUE USING INDEX abc;

インデックス abc の名前は def に変更されます。