날짜 범위 파티셔닝
설명
GitLab 마이그레이션 도우미에서 가장 잘 지원하는 스키마는 날짜 범위 파티셔닝입니다. 여기서 테이블의 각 파티션은 단일 월의 데이터를 포함합니다. 이 경우 파티셔닝 키는 타임스탬프 또는 날짜 열이어야 합니다. 이 유형의 파티셔닝이 잘 작동하려면 대부분의 쿼리가 특정 날짜 범위의 데이터에 액세스해야 합니다.
구체적인 예로 audit_events
테이블을 고려해 보겠습니다. 이 테이블은 애플리케이션 데이터베이스에서 첫 번째로 파티셔닝된 테이블이었습니다. 이 테이블은 애플리케이션에서 발생하는 보안 이벤트의 감사 항목을 기록합니다. 대부분의 경우 사용자는 특정 시간 프레임에서 발생하는 감사 활동을 보고 싶어합니다. 그 결과로 날짜 범위 파티셔닝이 데이터에 액세스되는 방식과 자연스럽게 맞았습니다.
더 자세히 살펴보기 위해 간소화된 audit_events
스키마를 상상해 보겠습니다:
CREATE TABLE audit_events (
id SERIAL NOT NULL PRIMARY KEY,
author_id INT NOT NULL,
details jsonb NOT NULL,
created_at timestamptz NOT NULL);
이제 UI의 일반적인 쿼리가 특정 날짜 범위, 예를 들어 단일 주차의 데이터를 표시할 것으로 상상해 보겠습니다:
SELECT *
FROM audit_events
WHERE created_at >= '2020-01-01 00:00:00'
AND created_at < '2020-01-08 00:00:00'
ORDER BY created_at DESC
LIMIT 100
테이블이 created_at
열로 파티셔닝되어 있다면 기본 테이블은 다음과 같을 것입니다:
CREATE TABLE audit_events (
id SERIAL NOT NULL,
author_id INT NOT NULL,
details jsonb NOT NULL,
created_at timestamptz NOT NULL,
PRIMARY KEY (id, created_at))
PARTITION BY RANGE(created_at);
참고: 파티셔닝된 테이블의 기본 키는 반드시 기본 키 정의에 파티션 키를 포함해야 합니다.
또한 테이블에 대한 파티션 목록이 있을 수 있습니다:
audit_events_202001 FOR VALUES FROM ('2020-01-01') TO ('2020-02-01')
audit_events_202002 FOR VALUES FROM ('2020-02-01') TO ('2020-03-01')
audit_events_202003 FOR VALUES FROM ('2020-03-01') TO ('2020-04-01')
각 파티션은 독립된 물리적인 테이블이며, 기본 audit_events
테이블과 같은 구조를 가지지만 파티션 키가 지정된 범위 내에 있는 행 데이터만 포함합니다. 예를 들어 audit_events_202001
파티션에는 created_at
열이 2020-01-01
이상이고 2020-02-01
미만인 행이 포함됩니다.
이제 이전의 예시 쿼리를 다시 살펴보면 데이터베이스는 WHERE
를 사용하여 모든 일치 행이 audit_events_202001
파티션에 있다는 것을 인식할 수 있습니다. 모든 파티션의 모든 데이터를 검색하는 대신 적절한 파티션의 한 달치 데이터만 검색할 수 있습니다. 큰 테이블의 경우 데이터베이스가 액세스해야 하는 데이터 양을 현저하게 줄일 수 있습니다. 그러나 파티셔닝 키를 기반으로 필터링하지 않는 쿼리가 있다고 상상해 보겠습니다. 예를 들어:
SELECT *
FROM audit_events
WHERE author_id = 123
ORDER BY created_at DESC
LIMIT 100
이 예시에서는 데이터베이스가 검색을 위해 어떤 파티션이든 오도록 파티션을 제거할 수 없습니다. 따라서 각 파티션을 개별적으로 쿼리하고 행을 단일 결과 집합으로 집계해야 합니다. author_id
가 색인화되었을 것이므로 성능 영향은 수용할만할 것입니다. 그러나 더 복잡한 쿼리의 경우 오버헤드가 상당할 수 있습니다. 파티셔닝은 데이터의 액세스 패턴이 파티셔닝 전략을 지원하는 경우에만 사용해야 하며 그렇지 않으면 성능에 영향을 미칠 수 있습니다.
예시
단계 1: 파티셔닝된 복사본 생성 (릴리스 N)
첫 번째 단계는 원본 테이블의 파티셔닝된 복사본을 생성하는 마이그레이션을 추가하는 것입니다. 이 마이그레이션은 원본 테이블의 데이터를 기준으로 적절한 파티션을 만들고 원본 테이블에서 파티셔닝된 복사본으로의 쓰기를 동기화하는 트리거를 설치합니다.
audit_events
테이블의 created_at
열을 기준으로 파티셔닝하는 예시 마이그레이션은 다음과 같습니다:
class PartitionAuditEvents < Gitlab::Database::Migration[2.1]
include Gitlab::Database::PartitioningMigrationHelpers
def up
partition_table_by_date :audit_events, :created_at
end
def down
drop_partitioned_table_for :audit_events
end
end
이 마이그레이션이 실행된 후에는 원본 테이블에 대한 모든 삽입, 업데이트 또는 삭제가 새 테이블에도 복제됩니다. 업데이트 및 삭제의 경우 해당 행이 파티셔닝된 테이블에 있는 경우에만 영향을 미칩니다.
단계 2: 파티셔닝된 복사본 채우기 (릴리스 N)
두 번째 단계는 배포 후 마이그레이션을 추가하여 기존 테이블의 데이터를 파티셔닝된 복사본으로 백필하는 배경 작업을 예약하는 것입니다.
이전의 예시를 계속해서, 마이그레이션은 다음과 같을 것입니다:
class BackfillPartitionAuditEvents < Gitlab::Database::Migration[2.1]
include Gitlab::Database::PartitioningMigrationHelpers
disable_ddl_transaction!
restrict_gitlab_migration gitlab_schema: :gitlab_main
def up
enqueue_partitioning_data_migration :audit_events
end
def down
cleanup_partitioning_data_migration :audit_events
end
end
이 단계는 내부적으로 BATCH_SIZE 및 SUB_BATCH_SIZE를 50,000
및 2,500
으로 사용하여 일괄 배경 마이그레이션을 예약합니다. 자세한 내용은 일괄 배경 마이그레이션 가이드를 참조하십시오.
단계 3: 백필 후 정리 (릴리스 N+1)
이 단계는 단계 2를 포함한 릴리스 이후에 최소한 한 번의 릴리스에서 수행되어야 합니다. 이로써 자체 관리 설치에서 배경 마이그레이션이 올바르게 실행되기에 충분한 시간을 확보합니다. 이 단계에서는 배포 후 마이그레이션을 추가하여 배경 마이그레이션 이후에 청소하는 작업을 수행합니다. 이는 남아 있는 작업을 강제로 실행하고 삭제되거나 실패한 작업으로 인해 누락된 데이터를 복사하는 것을 포함합니다.
경고: 단계 2와 3 사이에 필수적인 중지가 있어야 합니다. 이로써 단계 2의 배경 마이그레이션이 성공적으로 완료될 수 있습니다.
다시 한번, 이 예시를 계속해서, 마이그레이션은 다음과 같을 것입니다:
class CleanupPartitionedAuditEventsBackfill < Gitlab::Database::Migration[2.1]
include Gitlab::Database::PartitioningMigrationHelpers
disable_ddl_transaction!
restrict_gitlab_migration gitlab_schema: :gitlab_main
def up
finalize_backfilling_partitioned_table :audit_events
end
def down
# no op
end
end
이 마이그레이션이 완료된 후에는 원본 테이블과 파티셔닝된 테이블이 동일한 데이터를 포함해야 합니다. 원본 테이블에 설치된 트리거는 앞으로 계속하여 데이터가 동기화되도록 보장합니다.
단계 4: 파티션된 테이블과 파티션되지 않은 테이블 교체 (릴리스 N+1)
이 단계는 파티션이 지정된 복사본으로 파티션이 되지 않은 테이블을 대체하며, 이 작업은 다른 모든 마이그레이션 단계가 성공적으로 완료된 후에만 사용해야 합니다.
파티션 교체 작업을 수행하기 전이나 중에 주의해야 할 몇 가지 제한 사항이 있습니다:
- 보조 인덱스 및 외래 키는 파티션된 테이블에 자동으로 다시 생성되지 않습니다.
- (UNIQUE 및 EXCLUDE) 인덱스에 의존하는 일부 유형의 제한 사항은 파티션된 테이블에 자동으로 다시 생성되지 않습니다. 해당 기본 인덱스가 존재하지 않기 때문입니다.
- 기존의 파티션이 되지 않은 테이블을 참조하는 외래 키는 파티션이 되어 있는 테이블을 참조하도록 업데이트해야 합니다. 이는 PostgreSQL 11에서 지원되지 않습니다.
- 기존 테이블을 참조하는 뷰도 자동으로 파티션된 테이블을 참조하도록 업데이트되지 않습니다.
# frozen_string_literal: true
class SwapPartitionedAuditEvents < ActiveRecord::Migration[6.0]
include Gitlab::Database::PartitioningMigrationHelpers
def up
replace_with_partitioned_table :audit_events
end
def down
rollback_replace_with_partitioned_table :audit_events
end
end
이 마이그레이션이 완료되면:
- 파티션이 지정된 테이블이 파티션이 되지 않은 (원래) 테이블을 대체합니다.
- 이전에 생성된 동기화 트리거가 삭제됩니다.
파티션이 지정된 테이블은 이제 응용 프로그램에서 사용할 준비가 되었습니다.