- 컬럼 삭제
- 컬럼 이름 변경
- 열 제약 조건 변경
- 열 유형 변경
- 열 기본값 변경
- 대용량 테이블의 스키마 변경
- 인덱스 추가
- 인덱스 삭제
- 테이블 추가
- 테이블 삭제
- 테이블 이름 변경
- 외래 키 추가
- 외래 키 제거
-
integer
주 키를bigint
로 마이그레이션 - 데이터 마이그레이션
다운 타임 방지하기
데이터베이스 작업 중에는 특정 작업에 다운 타임이 필요할 수 있습니다. 마이그레이션 중에 다운 타임을 견딜 수 없기 때문에, 다운 타임 없이 동일한 결과를 얻기 위해 일련의 단계를 사용해야 합니다. 이 안내서에서는 다운 타임이 필요해 보이는 다양한 작업, 그 영향, 그리고 다운 타임 없이 수행하는 방법에 대해 설명합니다.
컬럼 삭제
컬럼을 삭제하는 것은 까다로운데, GitLab 프로세스가 이러한 컬럼이 존재한다고 예상합니다. 심지어 컬럼이 참조되지 않더라도 ActiveRecord가 테이블 스키마를 캐시하기 때문입니다. 이는 컬럼이 명시적으로 무시되지 않은 상태라면 발생하는 문제입니다. 안전하게 이 문제를 해결하려면 세 가지 단계가 세 개의 릴리스에서 필요합니다.
컬럼을 삭제하는 작업은 쉽게 롤백할 수 없는 파괴적인 작업이기 때문에 이를 세 개의 릴리스에 걸쳐서 처리합니다.
이 절차를 따르면 GitLab.com에 배포되는 것과 Self-Managed 설치를 업그레이드하는 과정에서 이러한 단계를 함께 묶지 않게 됩니다.
컬럼 무시 (릴리스 M)
첫 번째 단계는 애플리케이션 코드에서 컬럼을 무시하고, 모델 유효성 검증을 비롯한 컬럼 참조를 모두 제거하는 것입니다. 이 단계는 필요합니다. 왜냐하면 Rails는 컬럼을 캐시하고 다양한 곳에서 이 캐시를 재사용하기 때문입니다. 컬럼을 무시하는 것은 컬럼을 무시하도록 정의함으로써 할 수 있습니다. 예를 들어, 릴리스 12.5
에서 User
모델에서 updated_at
을 무시하려면 다음과 같이 사용합니다:
class User < ApplicationRecord
include IgnorableColumns
ignore_column :updated_at, remove_with: '12.7', remove_after: '2019-12-22'
end
여러 컬럼을 무시할 수도 있습니다:
ignore_columns %i[updated_at created_at], remove_with: '12.7', remove_after: '2019-12-22'
만약 모델이 CE와 EE에 모두 존재한다면 컬럼은 CE 모델에서 무시해야 합니다. 모델이 EE에만 존재한다면 거기에 추가해야 합니다.
컬럼 무시 규칙을 제거할 때 안전한 시점을 표시하는 것이 필요합니다:
-
remove_with
: 일반적으로 추가한 컬럼 무시로부터 두 개의 릴리스(M+2)인 GitLab 릴리스(12.7
는 우리의 예에서)로 설정합니다. -
remove_after
: 컬럼 무시를 제거해도 안전하다고 여기는 날짜로, 일반적으로 M+1 릴리스 날짜 이후, 즉 M+2 개발 주기 중 M+1 릴리스 날짜 이후. 예를 들어,12.7
의 개발 주기는2019-12-18
부터2020-01-17
이고,12.6
은 컬럼을 삭제하는 릴리스이기 때문에12.6
릴리스 날짜를2019-12-22
로 설정하는 것이 안전합니다.
이 정보는 컬럼 무시에 대해 더 잘 이해하고 일반적인 릴리스 및 GitLab.com에 대한 배포에서 컬럼 무시를 너무 이른 시기에 제거하지 않도록 합니다. 예를 들어, 이렇게 하면 컬럼 무시를 무시한 변경 사항과 그 이후 컬럼 무시를 제거하는 변경 사항을 한데 묶어 배포하는 상황을 피할 수 있습니다(결국 다운 타임을 야기할 것입니다).
이 예에서 컬럼을 무시하는 변경은 릴리스 12.5
에 들어갔습니다.
컬럼 삭제 (릴리스 M+1)
위 예시를 계속하면, 컬럼을 삭제하는 것은 릴리스 12.6
에서 배포 후 마이그레이션에 들어갑니다:
먼저 배포 후 마이그레이션을 생성하세요:
bundle exec rails g post_deployment_migration remove_users_updated_at_column
컬럼을 삭제하는 마이그레이션을 작성할 때 다음 시나리오들을 고려해야 합니다:
삭제된 컬럼에 속한 인덱스나 제약이 없을 경우
이 경우, 트랜잭션 마이그레이션을 사용할 수 있습니다:
class RemoveUsersUpdatedAtColumn < Gitlab::Database::Migration[2.1]
def up
remove_column :users, :updated_at
end
def down
add_column :users, :updated_at, :datetime
end
end
삭제된 컬럼에 속한 인덱스나 제약이 있을 경우
만약 down
메서드가 삭제된 인덱스나 제약을 다시 추가해야 한다면, 그것은 트랜잭션 마이그레이션에 들어갈 수 없습니다. 마이그레이션은 이렇게 보일 것입니다:
class RemoveUsersUpdatedAtColumn < Gitlab::Database::Migration[2.1]
disable_ddl_transaction!
def up
remove_column :users, :updated_at
end
def down
add_column(:users, :updated_at, :datetime, if_not_exists: true)
# `up` 메서드에서 삭제된 인덱스나 제약을 다시 추가해야 합니다. 예를 들어:
add_concurrent_index(:users, :updated_at)
end
end
down
메서드에서 마이그레이션이 실행 중 실패할 수 있기 때문에, 컬럼이 이미 존재하는지 확인해야 합니다.
이는 마이그레이션이 트랜잭션을 불가능하게 하는 비-트랜재션 마이그레이션이기 때문에 필요합니다.
전체 마이그레이션을 감싸는 트랜잭션을 불가능하게 하는 disable_ddl_transaction!
을 사용합니다.
데이터베이스 마이그레이션에 대한 자세한 정보는 마이그레이션 스타일 가이드 페이지를 참조하세요.
무시 규칙 제거 (릴리스 M+2)
다음 릴리스인 이 예시에서 12.7
에서는 다른 병합 리퀘스트를 설정하여 무시 규칙을 제거합니다.
이로써 ignore_column
라인과 - 필요하지 않은 경우 - IgnoreableColumns
의 포함도 제거합니다.
이것은 remove_with
로 표시된 릴리스에서만 합쳐져야 하며, 그리고 remove_after
날짜가 지난 후여야 합니다.
컬럼 이름 변경
표준 방식으로 컬럼 이름을 변경하는 것은 애플리케이션이 데이터베이스 마이그레이션 중이나 이후에도 이전 컬럼 이름을 계속 사용할 수 있기 때문에 다운 타임이 필요합니다. 다운 타임이 필요하지 않고 컬럼 이름을 변경하려면 두 가지 마이그레이션이 필요합니다: 일반 마이그레이션과 배포 후 마이그레이션. 두 마이그레이션은 동일한 릴리스에 포함될 수 있습니다. 단계:
- 일반 마이그레이션 추가 (릴리스 M)
- 컬럼 무시 (릴리스 M)
- 배포 후 마이그레이션 추가 (릴리스 M)
- 무시 규칙 삭제 (릴리스 M+1)
일반 마이그레이션 추가 (릴리스 M)
먼저 일반적인 마이그레이션을 생성해야 합니다. 이 마이그레이션은 Gitlab::Database::MigrationHelpers#rename_column_concurrently
를 사용하여 이름을 변경해야 합니다. 예를 들어,
# db/migrate에 있는 일반 마이그레이션
class RenameUsersUpdatedAtToUpdatedAtTimestamp < Gitlab::Database::Migration[2.1]
disable_ddl_transaction!
def up
rename_column_concurrently :users, :updated_at, :updated_at_timestamp
end
def down
undo_rename_column_concurrently :users, :updated_at, :updated_at_timestamp
end
end
이로써 열의 이름을 변경하고, 데이터가 동기화되도록 보장하며, 인덱스 및 외래 키를 복사합니다.
해당 열에 하나 이상의 인덱스가 포함되어 있고 해당 인덱스에 원래 열의 이름이 포함되어 있지 않을 경우, 앞에서 설명한 절차가 실패합니다. 이 경우, 이러한 인덱스를 다시 이름을 변경해야 합니다.
열 무시하기 (릴리스 M)
다음 단계는 애플리케이션 코드에서 열을 무시하고 사용되지 않도록하는 것입니다. 이 단계는 Rails가 열을 캐시하고 다양한 위치에서 이 캐시를 재사용하기 때문에 필요합니다. 이 단계는 열이 삭제될 때 첫 번째 단계와 유사하며, 동일한 요구 사항이 적용됩니다.
class User < ApplicationRecord
include IgnorableColumns
ignore_column :updated_at, remove_with: '12.7', remove_after: '2019-12-22'
end
배포 후 마이그레이션 추가 (릴리스 M)
이름 변경 절차는 배포 후 마이그레이션에서 정리가 필요합니다. 우리는
Gitlab::Database::MigrationHelpers#cleanup_concurrent_column_rename
을 사용하여 이 정리를 수행할 수 있습니다.
# db/post_migrate에 있는 배포 후 마이그레이션
class CleanupUsersUpdatedAtRename < Gitlab::Database::Migration[2.1]
disable_ddl_transaction!
def up
cleanup_concurrent_column_rename :users, :updated_at, :updated_at_timestamp
end
def down
undo_cleanup_concurrent_column_rename :users, :updated_at, :updated_at_timestamp
end
end
큰 테이블을 이름을 변경한다면, 첫 번째 마이그레이션이 실행된 상태이지만 두 번째 정리 마이그레이션이 아직 실행되지 않은 상태를 주의 깊게 고려해야 합니다. Canary를 사용하면 시스템이 상당한 시간동안 이 상태로 동작할 수 있습니다.
무시 규칙 제거 (릴리스 M+1)
열이 삭제될 때와 마찬가지로, 이름 변경이 완료된 후에 다음 릴리스에서 무시 규칙을 제거해야 합니다.
열 제약 조건 변경
NOT NULL
절 (또는 다른 제약 조건)을 추가하거나 제거하는 것은 일반적으로 다운 타임 없이 수행할 수 있습니다. 그러나 이를 수행하려면 모든 애플리케이션 변경사항이 우선 배포되어야 합니다. 따라서 열의 제약 조건을 변경하는 것은 배포 후 마이그레이션에서 수행해야 합니다.
change_column
을 사용하는 것은 전체 열 유형을 재정의하기 때문에 비효율적인 쿼리를 생성하므로 피해야 합니다.
각 특정 사용 사례에 대한 다음 가이드를 확인할 수 있습니다:
- 외래 키 제약 조건 추가
NOT NULL
제약 조건 추가- 텍스트 열에 제한 추가(strings_and_the_text_data_type.md)
열 유형 변경
열의 유형을 변경하는 것은 Gitlab::Database::MigrationHelpers#change_column_type_concurrently
를 사용하여 수행할 수 있습니다. 이 방법은 rename_column_concurrently
와 유사하게 작동합니다. 예를 들어, users.username
의 유형을 string
에서 text
로 변경하려면:
일반 마이그레이션 생성
일반적인 마이그레이션은 일시적인 이름으로 새 열을 생성하고 데이터를 동기화하기 위해 일부 트리거를 설정하는 데 사용됩니다. 해당 마이그레이션은 다음과 같이 보일 것입니다:
# db/migrate에 있는 일반 마이그레이션
class ChangeUsersUsernameStringToText < Gitlab::Database::Migration[2.1]
disable_ddl_transaction!
def up
change_column_type_concurrently :users, :username, :text
end
def down
undo_change_column_type_concurrently :users, :username
end
end
배포 후 마이그레이션 생성
다음으로, 배포 후 마이그레이션을 사용하여 변경 사항을 정리해야 합니다:
# db/post_migrate에 있는 배포 후 마이그레이션
class ChangeUsersUsernameStringToTextCleanup < Gitlab::Database::Migration[2.1]
disable_ddl_transaction!
def up
cleanup_concurrent_column_type_change :users, :username
end
def down
undo_cleanup_concurrent_column_type_change :users, :username, :string
end
end
그리고 여기까지입니다!
새 유형으로 데이터 캐스팅
일부 유형 변경은 데이터를 새 유형으로 캐스팅해야 할 수 있습니다. 예를 들어, text
에서 jsonb
로 변경하는 경우입니다.
이 경우 type_cast_function
옵션을 사용합니다.
잘못된 데이터가 없도록하고, 캐스트가 항상 성공하도록하여야 합니다. 캐스트 오류를 처리하는 사용자 정의 함수를 제공할 수도 있습니다.
예시 마이그레이션:
def up
change_column_type_concurrently :users, :settings, :jsonb, type_cast_function: 'jsonb'
end
열 기본값 변경
열 기본값을 변경하는 것은 Rails가 기본값이 동등한 값을 쓰는 방식 때문에 어렵습니다.
참고: 레일스는 레코드를 작성할 때 기본값을 포스트그레스에 보내지 않습니다. 이 작업은 데이터베이스에 남김니다. 마이그레이션이 열의 기본값을 변경하면 스키마 캐시로 인해 실행중인 애플리케이션은 이 변경 사항을 알지 못합니다. 특히 데이터베이스 마이그레이션을 실행한 후 코드의 새 버전을 배포하는 경우에는 실행 중인 코드가 데이터베이스에 잘못된 데이터를 작성할 위험이 있습니다.
코드를 명시적으로 이전 기본값을 쓴다면, 예전 기본값을 새로운 기본값으로 대체하지 않도록 Rails가 INSERT 쿼리에서 예전 기본값으로 명시적으로 지정해놓은 경우를 막기 위해 다음 두 단계에서 수행해야 합니다:
-
모델에
SafelyChangeColumnDefault
concern 추가 및 다음 마이그레이션에서 기본값 변경 - 다음 소규모 릴리스에서
SafelyChangeColumnDefault
concern 정리합니다.
self-managed 릴리스는 모든 소규모 릴리스를 하나의 제로 다운타임 배포로 번들링하므로 SafelyChangeColumnDefault
의 정리를 하기 위해서는 소규모 릴리스를 기다려야 합니다.
SafelyChangeColumnDefault
concern를 모델에 추가하고 post-migration에서 기본값 변경
첫 번째 단계는 응용 프로그램 코드에서 변경을 안전하게 표시하는 것입니다.
class Ci::Build < ApplicationRecord
include SafelyChangeColumnDefault
columns_changing_default :partition_id
end
그런 다음 기본값을 변경하는 포스트 배포 마이그레이션을 생성하세요:
bundle exec rails g post_deployment_migration change_ci_builds_default
class ChangeCiBuildsDefault < Gitlab::Database::Migration[2.1]
def change
change_column_default('ci_builds', 'partition_id', from: 100, to: 101)
end
end
다음 소규모 릴리스에서 SafelyChangeColumnDefault
concern 정리
다음 소규모 릴리스에서 columns_changing_default
호출을 제거하는 새로운 병합 요청을 생성하세요. 또한, 다른 열에 필요하지 않은 경우 SafelyChangeColumnDefault
를 삭제하세요.
대용량 테이블의 스키마 변경
change_column_type_concurrently
및 rename_column_concurrently
은 다운타임 없이 테이블 스키마를 변경하는 데 사용될 수 있지만 대용량 테이블에는 잘 작동하지 않습니다. 모든 작업이 순차적으로 실행되기 때문에 마이그레이션이 매우 오래 걸릴 수 있어 배포를 방해할 수 있습니다. 또한 순차적으로 많은 행을 빠르게 업데이트하여 데이터베이스에 많은 압력을 줄 수 있습니다.
데이터베이스 압력을 줄이려면 대용량 테이블의 열을 마이그레이션 할 때 백그라운드 마이그레이션을 대신 사용해야 합니다(예: issues
). 백그라운드 마이그레이션은 작업/부하를 더 긴 시간 동안 분산시켜 배포를 늦추지 않습니다.
자세한 정보는 배치 백그라운드 마이그레이션 정리 문서를 참조하세요.
인덱스 추가
add_concurrent_index
를 사용하면 인덱스를 추가할 때 다운타임이 필요하지 않습니다.
더 많은 정보는 마이그레이션 스타일 가이드를 참조하세요.
인덱스 삭제
인덱스를 삭제하는 것은 다운타임이 필요하지 않습니다.
테이블 추가
이 작업은 테이블을 아직 사용 중인 코드가 없을 때 안전합니다.
테이블 삭제
테이블을 삭제하는 것은 애플리케이션이 해당 테이블을 더 이상 사용하지 않는 경우에만 포스트 배포 마이그레이션을 사용하여 안전하게 수행할 수 있습니다.
database dictionary의 설명에 따라 테이블을 db/docs/deleted_tables
에 추가합니다. 테이블이 삭제되어도 데이터베이스 마이그레이션에서 여전히 참조되기 때문입니다.
테이블 이름 변경
테이블 이름을 변경하는 것은 애플리케이션이 이전 테이블 이름을 계속 사용할 수 있기 때문에 다운타임이 필요합니다.
테이블과 ActiveRecord 모델이 아직 사용되지 않는 경우 이전 테이블을 삭제하고 새 테이블을 생성하는 것이 테이블 이름을 “변경”하는 우선적인 방법입니다.
GitLab의 멀티 릴리스 테이블 이름 변경 프로세스를 따라 다운타임 없이 테이블 이름을 변경할 수 있습니다.
외래 키 추가
외래 키를 추가하는 것은 일반적으로 3단계로 진행됩니다.
- 트랜잭션 시작
- 제약 조건을 추가하기 위해
ALTER TABLE
실행 - 모든 기존 데이터 확인
ALTER TABLE
은 일반적으로 트랜잭션 종료까지 배타적인 잠금을 획들므로 이러한 방식은 다운타임이 필요합니다.
GitLab은 Gitlab::Database::MigrationHelpers#add_concurrent_foreign_key
를 사용하여 이 문제를 해결할 수 있도록 합니다. 이 방법을 사용하면 다운타임이 필요하지 않습니다.
외래 키 제거
이 작업은 다운타임이 필요하지 않습니다.
integer
주 키를 bigint
로 마이그레이션
일부 테이블의 integer
주 키(PK)에 대한 오버플로우 리스크를 방지하려면 그들의 PK를 bigint
로 마이그레이션해야 합니다. 이를 위해 다운타임 없이 데이터베이스에 과도한 부하를 일으키지 않고 이를 수행하는 프로세스가 아래에 설명되어 있습니다.
변환 초기화 및 기존 데이터 마이그레이션 시작 (릴리스 N)
이 프로세스를 시작하려면 새로운 bigint
열을 생성하기 위해 일반적인 마이그레이션을 추가하세요. 제공된 initialize_conversion_of_integer_to_bigint
헬퍼를 사용하세요. 이 헬퍼는 새 레코드의 경우 두 열을 동기화하기 위해 데이터베이스 트리거도 생성합니다 (code):
# frozen_string_literal: true
class InitializeConversionOfMergeRequestMetricsToBigint < Gitlab::Database::Migration[2.1]
disable_ddl_transaction!
TABLE = :merge_request_metrics
COLUMNS = %i[id]
def up
initialize_conversion_of_integer_to_bigint(TABLE, COLUMNS)
end
def down
revert_initialize_conversion_of_integer_to_bigint(TABLE, COLUMNS)
end
end
새로운 bigint
열을 무시하세요:
# frozen_string_literal: true
class MergeRequest::Metrics < ApplicationRecord
include IgnorableColumns
ignore_column :id_convert_to_bigint, remove_with: '16.0', remove_after: '2023-05-22'
end
배치된 백그라운드 마이그레이션을 대기열에 넣어 기존 데이터를 마이그레이션하세요 (code):
# frozen_string_literal: true
class BackfillMergeRequestMetricsForBigintConversion < Gitlab::Database::Migration[2.1]
restrict_gitlab_migration gitlab_schema: :gitlab_main
TABLE = :merge_request_metrics
COLUMNS = %i[id]
def up
backfill_conversion_of_integer_to_bigint(TABLE, COLUMNS, sub_batch_size: 200)
end
def down
revert_backfill_conversion_of_integer_to_bigint(TABLE, COLUMNS)
end
end
백그라운드 마이그레이션 모니터
마이그레이션이 실행되는 동안 마이그레이션의 수행 상황을 확인합니다. 이를 위한 여러 방법은 아래에 설명되어 있습니다.
배치된 백그라운드 마이그레이션의 고수준 상태
배치된 백그라운드 마이그레이션 상태를 확인하는 방법을 참조하세요.
데이터베이스 쿼리
관련 데이터베이스 테이블을 직접 쿼리할 수 있습니다. 읽기 전용 레플리카에 액세스 권한이 필요합니다. 예시 쿼리:
-- 주어진 테이블에 대한 일괄 배경 마이그레이션 세부 정보 가져오기
SELECT * FROM batched_background_migrations WHERE table_name = 'namespaces'\gx
-- 주어진 테이블에 대한 상태별 일괄 배경 마이그레이션 작업 수 가져오기
SELECT
batched_background_migrations.id, batched_background_migration_jobs.status, COUNT(*)
FROM
batched_background_migrations
JOIN batched_background_migration_jobs ON batched_background_migrations.id = batched_background_migration_jobs.batched_background_migration_id
WHERE
table_name = 'namespaces'
GROUP BY
batched_background_migrations.id, batched_background_migration_jobs.status;
-- 특정 테이블에 대한 일괄 배경 마이그레이션 진행률 (추정 총 튜플 수 기준)
SELECT
m.table_name,
LEAST(100 * sum(j.batch_size) / pg_class.reltuples, 100) AS percentage_complete
FROM
batched_background_migrations m
JOIN batched_background_migration_jobs j ON j.batched_background_migration_id = m.id
JOIN pg_class ON pg_class.relname = m.table_name
WHERE
j.status = 3 AND m.table_name = 'namespaces'
GROUP BY m.id, pg_class.reltuples;
Sidekiq 로그
일괄 배경 마이그레이션을 실행하는 워커를 모니터링하기 위해 Sidekiq 로그를 사용할 수도 있습니다:
-
@gitlab.com
이메일 주소로 Kibana에 로그인합니다. - 인덱스 패턴을
pubsub-sidekiq-inf-gprd*
로 변경합니다. -
json.queue: cronjob:database_batched_background_migration
필터를 추가합니다.
PostgreSQL 느린 쿼리 로그
데이터베이스의 느린 쿼리 로그는 1초 이상 소요된 쿼리를 추적합니다. 일괄 배경 마이그레이션을 위해 이를 확인하려면:
-
@gitlab.com
이메일 주소로 Kibana에 로그인합니다. - 인덱스 패턴을
pubsub-postgres-inf-gprd*
로 변경합니다. -
json.endpoint_id.keyword: Database::BatchedBackgroundMigrationWorker
필터를 추가합니다. - 선택 사항. 업데이트만 보려면
json.command_tag.keyword: UPDATE
필터를 추가합니다. - 선택 사항. 실패한 문만 보려면
json.error_severity.keyword: ERROR
필터를 추가합니다. - 테이블 명에 따라 필터를 추가할 수도 있습니다.
Grafana 대시보드
데이터베이스의 상태를 모니터링하기 위해 다음과 같은 추가 메트릭을 사용할 수 있습니다:
-
PostgreSQL Tuple 통계: 활성으로 변환 중인 테이블에 대한 높은 업데이트 속도 또는 해당 테이블에 대한 dead tuple의 증가율이 높은 경우,
autovacuum
이 따라 가지 못할 수 있습니다. - PostgreSQL 개요: 주 데이터베이스 서버에서 높은 시스템 사용 또는 초당 트랜잭션(TPS) 수를 보면 마이그레이션이 문제를 일으키고 있을 수 있습니다.
Prometheus 메트릭
각 일괄 배경 마이그레이션에 대한 메트릭 수는 Prometheus에 공개됩니다. 이러한 메트릭은 Grafana에서 검색하고 시각화할 수 있습니다 (예시)를 참조).
열 교체(릴리스 N + 1)
배경 마이그레이션을 완료하고 모든 레코드에 대해 새 ‘bigint’ 열이 채워지면 열을 교체할 수 있습니다. 교체는 사후 배포 마이그레이션을 사용하여 수행됩니다. 정확한 프로세스는 변환되는 테이블에 따라 다릅니다. 하지만 일반적으로 다음 단계를 따라 수행됩니다:
- 제공된
ensure_batched_background_migration_is_finished
도우미를 사용하여 일괄 마이그레이션이 완료되었는지 확인합니다 (예시). 마이그레이션이 완료되지 않았다면 다음 단계는 어차피 실패합니다. 미리 확인함으로써 보다 유용한 오류 메시지를 얻을 수 있습니다. -
Gitlab::Database::MigrationHelpers::ConvertToBigint
모듈에서 제공된add_bigint_column_indexes
도우미 메서드를 사용하여 기존 인덱스에 일치하는 ‘bigint’ 열을 사용하여 인덱스를 생성합니다.- 해당 도우미 메서드는 모든 필요한 ‘bigint’ 인덱스를 생성하는 것으로 예상되지만, 기존 인덱스를 누락하지 않도록 다시 확인하는 것이 좋습니다. 도우미에 대한 자세한 정보는 135781에서 확인할 수 있습니다.
-
integer
열을 사용하는 기존 FK와 일치하는 ‘bigint’ 열을 사용하여 FK를 생성합니다. 다른 테이블을 참조하는 FK 및 마이그레이션이 진행 중인 테이블을 참조하는 FK 모두에 대해 수행합니다 (예시). - 트랜잭션 내에서 열을 교체합니다:
- 관련된 테이블을 잠급니다. 교착 상태 발생 가능성을 줄이기 위해 부모에서 자식 순서로 수행하는 것이 좋습니다 (예시).
- 교체할 열 이름을 바꿉니다 (예시).
- 트리거 함수를 재설정합니다 (예시).
- 기본값을 교체합니다 (예시).
- PK 제약 조건을 교체합니다 (있는 경우) (예시).
- 이전 인덱스를 제거하고 새로운 인덱스의 이름을 변경합니다 (예시).
-
add_bigint_column_indexes
도우미를 사용하여 생성된 ‘bigint’ 인덱스의 이름은Gitlab::Database::MigrationHelpers::ConvertToBigint
모듈의bigint_index_name
을 호출하여 검색할 수 있습니다.
-
- 이전 외래 키를 제거하고 새로운 외래 키의 이름을 변경합니다 (있는 경우) (예시).
예시 merge request 및 마이그레이션.
트리거 및 이전 integer
열 삭제(릴리스 N + 2)
포스트-배포 마이그레이션 및 제공된 cleanup_conversion_of_integer_to_bigint
도우미를 사용하여 데이터베이스 트리거와 이전 integer
열을 삭제하세요 (예시).
무시 규칙 삭제하기(릴리스 N + 3)
열이 삭제된 후의 다음 릴리스에서는 더는 필요하지 않으므로 무시 규칙을 삭제하세요 (예시).
데이터 마이그레이션
데이터 마이그레이션은 까다로울 수 있습니다. 데이터를 마이그레이션하는 일반적인 접근 방법은 3단계로 이루어집니다:
- 초기 데이터 일괄 처리 마이그레이션
- 애플리케이션 코드 배포
- 남은 데이터 마이그레이션
보통 이 방법이 작동하지만 항상 그렇지는 않습니다. 예를 들어, 필드 형식을 JSON에서 다른 형식으로 변경해야 하는 경우 문제가 발생할 수 있습니다. 애플리케이션 코드를 배포하기 전에 기존 데이터를 변경하려고 하면 대부분의 경우 오류가 발생할 수 있습니다. 반면에, 애플리케이션 코드를 배포한 후에 마이그레이션을 수행하게 되면 동일한 문제에 부딪힐 수 있습니다.
단순히 잘못된 데이터를 수정해야 하는 경우에는 보통 포스트-배포 마이그레이션이 충분합니다. 데이터 형식을 변경해야 하는 경우(예: JSON에서 다른 형식으로) 대부분의 경우 새로운 데이터 형식을 위한 새로운 열을 추가하고 애플리케이션이 해당 열을 사용하도록 하는 것이 일반적으로 가장 좋습니다. 이런 경우 절차는 다음과 같습니다:
- 새 형식의 새 열 추가
- 기존 데이터를 이 새 열로 복사
- 애플리케이션 코드 배포
- 포스트-배포 마이그레이션에서 남은 데이터 복사
일반적으로 일반화할 수 있는 해결책은 없습니다. 따라서 이러한 종류의 마이그레이션에 대해 최상의 방법으로 구현되도록 하려면 병합 요청에서 이에 대해 논의하는 것이 가장 좋습니다.