概要
PythonのアプリでAlembicを利用してマイグレーション(autogenerate
)していたのですが、なぜか既にあるインデックスがマイグレーションファイルに表示される(=alembicが再度作成しようとする)、という事象が発生。
原因と解決方法がわかったので紹介します。
前提
db:mysql8.0
python:3.12
alembic:1.13.2
SQLAlchemy:2.0.32
経緯
SQLAlchemyのモデル定義には以下のように記載していました。
type_id = Column(Integer, primary_key=True, index=True)
これでmigrationファイルを生成(alembic revision --autogenerate
コマンドを実行)すると、以下のように認識されていました。
sa.Column('type_id', sa.Integer(), nullable=False),
データベースを確認すると、PRIMARY
という名前でインデックスが作成されています。
しかし、この状態で別のモデル定義をいじってからマイグレーションファイルを生成すると、なぜか以下のようにインデックス作成が差分で表示されます。
op.create_index(op.f('ix_type_type_id'), 'type', ['type_id'], unique=False)
既にPRIMARY
という名前のインデックスがあるのに、ix_type_type_id
という別名でインデックス作成しようとしてくるのです。
なぜ既にあるのにAlembic側が再度生成しようとしてくるのだろう...?
原因と解決方法
結論、index=True
としていたのが理由でした。
以下の記事に辿り着いた時に原因がわかりました。
おそらく、MySQLなどのDB側で主キーに対してインデックスを作成してくれるのに、Alembicのマイグレーションでもインデックス作成するように指示してしまっているため、このように重複する事象が発生したと考えられます。
よく見ると、元々あった(MySQL側のもの?)インデックスにはユニーク制約があって、後で生成された(Alembic側?)インデックスにはユニーク制約がありませんでした。他は、上述の名前以外に違いはありませんでした。
つまり、Alembic側が「あれ、私が知っているインデックス名のものがないな...」と判断して、よしなに作成してくれたのではないか、ということです。
ということで、以下のようにSQLAlchemyのモデル定義からindex=True
を外せば、今後Alembicマイグレーション時に差分表示されないようになりました。
type_id = Column(Integer, primary_key=True)