목록 파티션
- GitLab 15.4에서 도입됨 Introduced.
설명
파티션할 테이블에 파티셔닝 키 열을 추가합니다.
파티셔닝 키를 다음 제약 조건에 포함합니다:
- 기본 키.
- 파티션할 테이블을 참조하는 모든 외래 키.
- 모든 고유 제약 조건.
예
단계 1 - 파티션 키 추가
파티셔닝 키 열을 추가합니다. 예를 들어, Rails 마이그레이션에서:
class AddPartitionNumberForPartitioning < Gitlab::Database::Migration[2.1]
enable_lock_retries!
TABLE_NAME = :table_name
COLUMN_NAME = :partition_id
DEFAULT_VALUE = 100
def change
add_column(TABLE_NAME, COLUMN_NAME, :bigint, default: 100)
end
end
단계 2 - 필요한 인덱스 생성
파티셔닝 키 열을 포함한 인덱스를 추가합니다. 예를 들어, Rails 마이그레이션에서:
class PrepareIndexesForPartitioning < Gitlab::Database::Migration[2.1]
disable_ddl_transaction!
TABLE_NAME = :table_name
INDEX_NAME = :index_name
def up
add_concurrent_index(TABLE_NAME, [:id, :partition_id], unique: true, name: INDEX_NAME)
end
def down
remove_concurrent_index_by_name(TABLE_NAME, INDEX_NAME)
end
end
단계 3 - 고유 제약 조건 적용
파티셔닝 키 열을 포함하도록 모든 고유 인덱스를 변경합니다.
기본 키 인덱스도 포함됩니다.
[primary_key_column, :partition_id]
에 고유 인덱스를 추가하여 다음 두 단계에서 필요할 것입니다.
예를 들어, Rails 마이그레이션에서:
class PrepareUniqueContraintForPartitioning < Gitlab::Database::Migration[2.1]
disable_ddl_transaction!
TABLE_NAME = :table_name
OLD_UNIQUE_INDEX_NAME = :index_name_unique
NEW_UNIQUE_INDEX_NAME = :new_index_name
def up
add_concurrent_index(TABLE_NAME, [:id, :partition_id], unique: true, name: NEW_UNIQUE_INDEX_NAME)
remove_concurrent_index_by_name(TABLE_NAME, OLD_UNIQUE_INDEX_NAME)
end
def down
add_concurrent_index(TABLE_NAME, :id, unique: true, name: OLD_UNIQUE_INDEX_NAME)
remove_concurrent_index_by_name(TABLE_NAME, NEW_UNIQUE_INDEX_NAME)
end
end
단계 4 - 외래 키 제약 조건 적용
파티셔닝 키 열을 포함한 외래 키를 적용합니다. 예를 들어, Rails 마이그레이션에서:
class PrepareForeignKeyForPartitioning < Gitlab::Database::Migration[2.1]
disable_ddl_transaction!
SOURCE_TABLE_NAME = :source_table_name
TARGET_TABLE_NAME = :target_table_name
COLUMN = :foreign_key_id
TARGET_COLUMN = :id
FK_NAME = :fk_365d1db505_p
PARTITION_COLUMN = :partition_id
def up
add_concurrent_foreign_key(
SOURCE_TABLE_NAME,
TARGET_TABLE_NAME,
column: [PARTITION_COLUMN, COLUMN],
target_column: [PARTITION_COLUMN, TARGET_COLUMN],
validate: false,
on_update: :cascade,
name: FK_NAME
)
# 이것은 높은 트래픽의 테이블을 다룰 때 별도의 후속 마이그레이션으로 수행해야 합니다.
validate_foreign_key(TABLE_NAME, [PARTITION_COLUMN, COLUMN], name: FK_NAME)
end
def down
with_lock_retries do
remove_foreign_key_if_exists(SOURCE_TABLE_NAME, name: FK_NAME)
end
end
end
on_update: :cascade
옵션은 파티셔닝 열을 업데이트하려면 필수입니다. 이는 모든 종속 행에 대한 업데이트를 전파합니다.
지정하지 않으면, 대상 테이블에서 파티션 열을 업데이트하려고 할 때 Key is still referenced from table ...
오류가 발생하고, 소스 테이블에서 파티션 열을 업데이트하려고 하면 Key is not present in table ...
오류가 발생합니다.
이 마이그레이션은 다음을 사용하여 자동으로 생성할 수 있습니다:
./scripts/partitioning/generate-fk --source source_table_name --target target_table_name
5단계 - 기본 키 변경
파티셔닝 키 열을 포함하여 기본 키를 변경합니다. 이는 모든 참조 외래 키에 대해 파티션 키를 포함한 후에만 수행할 수 있습니다. 예를 들어, Rails 마이그레이션에서:
class PreparePrimaryKeyForPartitioning < Gitlab::Database::Migration[2.1]
disable_ddl_transaction!
TABLE_NAME = :table_name
PRIMARY_KEY = :primary_key
OLD_INDEX_NAME = :old_index_name
NEW_INDEX_NAME = :new_index_name
def up
swap_primary_key(TABLE_NAME, PRIMARY_KEY, NEW_INDEX_NAME)
end
def down
add_concurrent_index(TABLE_NAME, :id, unique: true, name: OLD_INDEX_NAME)
add_concurrent_index(TABLE_NAME, [:id, :partition_id], unique: true, name: NEW_INDEX_NAME)
unswap_primary_key(TABLE_NAME, PRIMARY_KEY, OLD_INDEX_NAME)
# 참조된 외래 키를 추가해야 합니다. 예: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/113725/diffs
end
end
참고:
ActiveRecord
는 복합 기본 키를 지원하지 않으므로 모델에서 기본 키를 명시적으로 설정하는 것을 잊지 마세요.
class Model < ApplicationRecord
self.primary_key = :id
end
6단계 - 부모 테이블 생성 및 기존 테이블을 초기 파티션으로 연결
이제 데이터베이스 팀에서 제공하는 다음 도움말을 사용하여 기존 테이블을 초기 파티션으로 연결하여 부모 테이블을 생성할 수 있습니다.
예를 들어, Rails 포스트 마이그레이션에서 리스트 파티셔닝을 사용하는 경우:
class PrepareTableConstraintsForListPartitioning < Gitlab::Database::Migration[2.1]
include Gitlab::Database::PartitioningMigrationHelpers::TableManagementHelpers
disable_ddl_transaction!
TABLE_NAME = :table_name
PARENT_TABLE_NAME = :p_table_name
FIRST_PARTITION = 100
PARTITION_COLUMN = :partition_id
def up
prepare_constraint_for_list_partitioning(
table_name: TABLE_NAME,
partitioning_column: PARTITION_COLUMN,
parent_table_name: PARENT_TABLE_NAME,
initial_partitioning_value: FIRST_PARTITION
)
end
def down
revert_preparing_constraint_for_list_partitioning(
table_name: TABLE_NAME,
partitioning_column: PARTITION_COLUMN,
parent_table_name: PARENT_TABLE_NAME,
initial_partitioning_value: FIRST_PARTITION
)
end
end
class ConvertTableToListPartitioning < Gitlab::Database::Migration[2.1]
include Gitlab::Database::PartitioningMigrationHelpers::TableManagementHelpers
disable_ddl_transaction!
TABLE_NAME = :table_name
PARENT_TABLE_NAME = :p_table_name
FIRST_PARTITION = 100
PARTITION_COLUMN = :partition_id
def up
convert_table_to_first_list_partition(
table_name: TABLE_NAME,
partitioning_column: PARTITION_COLUMN,
parent_table_name: PARENT_TABLE_NAME,
initial_partitioning_value: FIRST_PARTITION
)
end
def down
revert_converting_table_to_first_list_partition(
table_name: TABLE_NAME,
partitioning_column: PARTITION_COLUMN,
parent_table_name: PARENT_TABLE_NAME,
initial_partitioning_value: FIRST_PARTITION
)
end
end
참고:
시퀀스 이름을 명시적으로 모델에서 설정하는 것을 잊지 마세요. 이는 라우팅 테이블에 의해 소유되며 ActiveRecord
는 이를 결정할 수 없습니다. 이는 table_name
이 라우팅 테이블로 변경된 후에 정리할 수 있습니다.
class Model < ApplicationRecord
self.sequence_name = 'model_id_seq'
end
파티셔닝 제약 마이그레이션이 10분 이상 걸리는 경우, 바쁜 시간 동안 포스트 마이그레이션이 실행되지 않도록 비동기로 실행되도록 설정할 수 있습니다.
다음 마이그레이션 AsyncPrepareTableConstraintsForListPartitioning
를 앞에 붙이고 async: true
옵션을 사용하세요. 이 변경은 파티셔닝 제약 조건을 NOT VALID
로 표시하고 주말 동안 테이블의 기존 데이터를 검증하기 위해 예약된 작업을 추가합니다.
그런 다음 두 번째 포스트 마이그레이션 PrepareTableConstraintsForListPartitioning
는 기존 데이터가 이미 이전 주말에 테스트되었기 때문에 파티셔닝 제약 조건을 검증된 것으로만 표시합니다.
예를 들어:
class AsyncPrepareTableConstraintsForListPartitioning < Gitlab::Database::Migration[2.1]
include Gitlab::Database::PartitioningMigrationHelpers::TableManagementHelpers
disable_ddl_transaction!
TABLE_NAME = :table_name
PARENT_TABLE_NAME = :p_table_name
FIRST_PARTITION = 100
PARTITION_COLUMN = :partition_id
def up
prepare_constraint_for_list_partitioning(
table_name: TABLE_NAME,
partitioning_column: PARTITION_COLUMN,
parent_table_name: PARENT_TABLE_NAME,
initial_partitioning_value: FIRST_PARTITION,
async: true
)
end
def down
revert_preparing_constraint_for_list_partitioning(
table_name: TABLE_NAME,
partitioning_column: PARTITION_COLUMN,
parent_table_name: PARENT_TABLE_NAME,
initial_partitioning_value: FIRST_PARTITION
)
end
end
Step 7 - 외래 키를 상위 테이블로 다시 지정하기
초기 파티션을 참조하는 테이블은 이제 상위 테이블을 가리키도록 업데이트해야 합니다. 이 변경이 없으면 해당 테이블의 레코드가 다음 파티션에서 행을 찾지 못하게 되며, 그들은 초기 파티션에서 찾으려고 할 것입니다.
단계:
- 파티션된 테이블에 외래 키를 추가하고 비동기적으로 검증합니다.
예를 들어 - GitLab.com에서 비동기 검증이 완료된 후 동기적으로 검증합니다.
예를 들어 - 오래된 외래 키를 제거하고 새 외래 키의 이름을 옛 이름으로 바꿉니다.
예를 들어
Step 8 - 파티션 간 ID 고유성 보장
모든 고유성 제약 조건은 파티셔닝 키를 포함해야 하므로, 파티션 간 중복 ID를 가질 수 있습니다. 이를 해결하기 위해 데이터베이스만 ID 값을 설정하도록 강제하고 시퀀스를 사용하여 이를 생성합니다. 시퀀스는 고유한 값을 생성하도록 보장됩니다.
예를 들어:
class EnsureIdUniquenessForPCiBuilds < Gitlab::Database::Migration[2.1]
include Gitlab::Database::PartitioningMigrationHelpers::UniquenessHelpers
enable_lock_retries!
TABLE_NAME = :p_ci_builds
SEQ_NAME = :ci_builds_id_seq
def up
ensure_unique_id(TABLE_NAME, seq: SEQ_NAME)
end
def down
revert_ensure_unique_id(TABLE_NAME, seq: SEQ_NAME)
end
end
Step 9 - 파티션된 테이블 분석 및 새 파티션 생성
자동 진공 데몬은 파티션된 테이블을 처리하지 않습니다. 테이블 계층의 통계가 최신 상태로 유지되도록 주기적으로 수동 ANALYZE
를 실행해야 합니다.
Ci::Partitionable
을 구현하고 partitioned: true
옵션이 있는 모델은 기본적으로 매주 분석됩니다. 이를 활성화하고 새 파티션을 생성하려면 PostgreSQL 초기화 프로그램에 모델을 등록해야 합니다.
Step 10 - 애플리케이션을 업데이트하여 파티션된 테이블을 사용하기
이제 상위 테이블이 준비되었으므로 애플리케이션을 이를 사용하도록 업데이트할 수 있습니다:
class Model < ApplicationRecord
self.table_name = :partitioned_table
end
모델에 따라 변경 관리 이슈를 사용하는 것이 더 안전할 수 있습니다.