모도리는 공부중

[SQL Alchemy & Alembic] DDL문으로 작성된 테이블 인덱스와 Alchemy 모델에 작성된 인덱스에 차이가 있을 경우 (feat. ChatGPT) 본문

내 지식 정리/날것 그 자체

[SQL Alchemy & Alembic] DDL문으로 작성된 테이블 인덱스와 Alchemy 모델에 작성된 인덱스에 차이가 있을 경우 (feat. ChatGPT)

공부하는 모도리 2024. 12. 30. 16:59
728x90
반응형

결론적으로, Alembic의 --autogenerate 기능은 다음과 같이 동작합니다:


1. SQL DDL에만 있고 SQLAlchemy 모델에 없는 인덱스

Alembic은 이러한 인덱스를 "불필요한 인덱스"로 간주하여 삭제 스크립트를 생성합니다.

근거:

  • Alembic 공식 문서에서는 --autogenerate가 SQLAlchemy 모델 정의를 기준으로 데이터베이스 상태를 조정한다고 명시하고 있습니다.
  • Alembic은 모델과 데이터베이스 상태의 차이점을 기반으로 동작하며, 모델에 정의되지 않은 인덱스는 불필요한 것으로 판단하여 drop_index 명령을 생성합니다.

예시 동작:

SQL DDL에만 있는 인덱스 idx_sql_ddl_only:

CREATE INDEX idx_sql_ddl_only ON example_table (column1);

SQLAlchemy 모델에 해당 인덱스가 없을 경우:

alembic revision --autogenerate -m "Remove outdated index"

결과 스크립트:

def upgrade():
    pass  # 모델과 일치하지 않으므로 추가 없음

def downgrade():
    op.drop_index('idx_sql_ddl_only', table_name='example_table')

2. SQL DDL과 SQLAlchemy 모델에 동일한 컬럼의 인덱스가 있지만, 이름이 다른 경우

Alembic은 인덱스 이름이 다르면 이를 "서로 다른 인덱스"로 간주하여, 기존 인덱스를 삭제하지 않고 SQLAlchemy 모델에 정의된 이름으로 새 인덱스를 생성합니다.

근거:

Alembic 공식 문서와 소스 코드(compare.py)에서는 autogenerate가 인덱스를 비교할 때 인덱스 이름컬럼 구성을 기준으로 판단한다고 명시되어 있습니다.

  • 이름이 다를 경우:
    • Alembic은 "기존 인덱스를 삭제하지 않고, 새 인덱스를 추가"하는 방식으로 동작합니다.
    • 이는 Alembic이 데이터베이스 상태를 변경하기 위해 기존 인덱스를 대체하지 않고 병렬로 생성할 수 있음을 보여줍니다.

예시 동작:

SQL DDL에 이미 존재하는 인덱스 idx_sql_ddl_name:

CREATE INDEX idx_sql_ddl_name ON example_table (column1);

SQLAlchemy 모델에 새 인덱스 정의:

class ExampleTable(Base):
    __tablename__ = 'example_table'
    id = Column(Integer, primary_key=True)
    column1 = Column(String(50))

    __table_args__ = (
        Index('idx_model_name', 'column1'),  # 다른 이름으로 정의된 인덱스
    )

autogenerate 결과:

def upgrade():
    op.create_index('idx_model_name', 'example_table', ['column1'], unique=False)  # 새로 생성

def downgrade():
    op.drop_index('idx_model_name', table_name='example_table')  # 새로 생성된 인덱스 삭제

3. 공식 문서에서 관련 부분

Alembic 공식 문서 (Autogenerate Section):

"Autogenerate compares the current database state to the SQLAlchemy models and generates migration scripts based on the differences. Differences are determined by both object names (e.g., table names, index names) and configurations (e.g., column lists, constraints)."

동작 원리를 명확히 설명:

  1. "Object names are compared first":
    • 인덱스 이름이 다르면 동일한 컬럼을 참조하더라도 서로 다른 객체로 간주.
  2. "If names match, configurations are compared":
    • 이름이 같고 구성(컬럼, unique 여부 등)이 다를 경우, Alembic은 이를 수정하도록 스크립트를 생성.

4. 최종 결론

  • SQL DDL에만 있고 SQLAlchemy 모델에 없는 인덱스:
    • Alembic은 이를 삭제 대상으로 간주하여 drop_index 명령을 생성합니다.
  • SQL DDL과 SQLAlchemy 모델에 동일한 컬럼을 참조하지만 이름이 다른 인덱스:
    • Alembic은 기존 인덱스를 유지하고, 새로 정의된 이름의 인덱스를 추가로 생성합니다.
    • 이는 Alembic이 인덱스 이름을 기준으로 "서로 다른 인덱스"로 간주하기 때문입니다.

추가로 더 알고 싶은 점이 있거나 실험 중 다른 결과가 발생하면 언제든 말씀해주세요! 😊

728x90
반응형
Comments