정수 범위 파티셔닝

설명

정수 범위 파티셔닝은 큰 테이블을 정수 열을 기준으로 더 작고 관리 가능한 청크로 나누는 기술입니다.

이는 특히 많은 행을 가진 테이블에 유용할 수 있으며, 쿼리 성능을 크게 개선하고, 저장 요구 사항을 줄이며, 유지 관리 작업을 단순화할 수 있습니다.

이 유형의 파티셔닝이 잘 작동하려면 대부분의 쿼리가 특정 정수 범위에서 데이터를 액세스해야 합니다.

좀 더 자세히 살펴보면, 단순화된 merge_request_diff_files 스키마를 상상해 보세요:

CREATE TABLE merge_request_diff_files (
  merge_request_diff_id INT NOT NULL,
  relative_order INT NOT NULL,
  PRIMARY KEY (merge_request_diff_id, relative_order));

이제 UI에서 일반적인 쿼리가 특정 정수 범위에서 데이터를 표시할 것이라고 상상해 보세요:

SELECT *
FROM merge_request_diff_files
WHERE merge_request_diff_id > 1 AND merge_request_diff_id < 10
LIMIT 100

테이블이 merge_request_diff_id 열을 기준으로 파티셔닝되면 기본 테이블은 다음과 같이 보일 것입니다:

CREATE TABLE merge_request_diff_files (
  merge_request_diff_id INT NOT NULL,
  relative_order INT NOT NULL,
  PRIMARY KEY (merge_request_diff_id, relative_order))
PARTITION BY RANGE(merge_request_diff_id);

참고:
파티셔닝된 테이블의 기본 키는 기본 키 정의의 일부로 파티션 키를 포함해야 합니다.

그리고 우리는 테이블에 대한 파티션 목록을 가질 수 있습니다, 예를 들어:

merge_request_diff_files_1 FOR VALUES FROM (1) TO (20)
merge_request_diff_files_20 FOR VALUES FROM (20) TO (40)
merge_request_diff_files_40 FOR VALUES FROM (40) TO (60)

각 파티션은 기본 merge_request_diff_files 테이블과 동일한 구조를 가지는 별도의 물리적 테이블이며, 지정된 범위 내에서 파티션 키가 해당하는 행의 데이터만 포함합니다. 예를 들어, 파티션 merge_request_diff_files_1merge_request_diff_id 열이 1 이상이고 20 미만인 행을 포함합니다.

이제 이전 예제 쿼리를 다시 살펴보면, 데이터베이스는 WHERE를 사용하여 모든 일치하는 행이 merge_request_diff_files_1 파티션에 있음을 인식할 수 있습니다. 모든 파티션의 모든 데이터에서 검색하는 대신 말입니다. 큰 테이블의 경우, 이는 데이터베이스가 액세스해야 하는 데이터 양을 극적으로 줄일 수 있습니다.

예제

단계 1: 파티션된 복사본 만들기 (릴리스 N)

첫 번째 단계는 원본 테이블의 파티션된 복사본을 만들기 위한 마이그레이션을 추가하는 것입니다. 이 마이그레이션은 원본 테이블의 데이터에 따라 적절한 파티션을 생성하고, 원본 테이블에서 파티션된 복사본으로 쓰기를 동기화하는 트리거를 설치합니다.

merge_request_diff_commits 테이블을 merge_request_diff_id 열에 따라 파티셔닝하는 예제 마이그레이션은 다음과 같습니다:

class PartitionMergeRequestDiffCommits < Gitlab::Database::Migration[2.1]
  include Gitlab::Database::PartitioningMigrationHelpers

  disable_ddl_transaction!

  def up
    partition_table_by_int_range(
      'merge_request_diff_commits', 
      'merge_request_diff_id', 
      partition_size: 10_000_000,
      primary_key: %w[merge_request_diff_id relative_order]
    )
  end

  def down
    drop_partitioned_table_for('merge_request_diff_commits')
  end
end

이것이 실행된 후, 원본 테이블에서의 삽입, 업데이트 또는 삭제는 새로운 테이블에도 복제됩니다. 업데이트와 삭제의 경우, 해당 행이 파티션된 테이블에 존재하는 경우에만 효과가 있습니다.

Step 2: 파티션 복구 (릴리스 N)

두 번째 단계는 기존 데이터에 대한 백그라운드 작업을 예약하는 포스트 배포 마이그레이션을 추가하여 원래 테이블에서 파티션 복사본으로 데이터를 복구하는 것입니다.

위의 예를 계속하면 마이그레이션은 다음과 같습니다:

class BackfillPartitionMergeRequestDiffCommits < Gitlab::Database::Migration[2.2]
  include Gitlab::Database::PartitioningMigrationHelpers

  milestone '16.10'

  disable_ddl_transaction!

  restrict_gitlab_migration gitlab_schema: :gitlab_main

  def up
    enqueue_partitioning_data_migration :merge_request_diff_commits
  end

  def down
    cleanup_partitioning_data_migration :merge_request_diff_commits
  end
end

이 단계는 배치 백그라운드 마이그레이션을 큐에 추가하고 내부적으로 BATCH_SIZE와 SUB_BATCH_SIZE를 50,0002,500으로 설정합니다. 자세한 내용은 배치 백그라운드 마이그레이션 가이드를 참조하세요.

Step 3: 포스트 복구 정리 (릴리스 N+1)

이 단계는 단계 (2)를 포함하는 릴리스 이후 최소한 하나의 릴리스에서 실행되어야 합니다. 이는 백그라운드 마이그레이션이 자체 관리 설치에서 제대로 실행될 수 있도록 시간을 제공합니다. 이 단계에서는 백그라운드 마이그레이션 이후 정리 작업을 수행하는 또 다른 포스트 배포 마이그레이션을 추가합니다. 여기에는 남아 있는 작업을 실행하도록 강제하고, 중단되거나 실패한 작업으로 인해 누락된 데이터를 복사하는 작업이 포함됩니다.

경고: 단계 2와 3 사이에는 백그라운드 마이그레이션이 성공적으로 완료될 수 있도록 필요한 정지가 발생해야 합니다.

다시 위의 예를 계속하면 이 마이그레이션은 다음과 같습니다:

class CleanupPartitionMergeRequestDiffCommitsBackfill < 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 :merge_request_diff_commits
  end

  def down
    # no op
  end
end

이 마이그레이션이 완료되면 원래 테이블과 파티션 테이블에는 동일한 데이터가 포함되어야 합니다. 원래 테이블에 설치된 트리거는 데이터가 앞으로도 계속 동기화되도록 보장합니다.

Step 4: 파티션 테이블과 비파티션 테이블 교환 (릴리스 N+1)

이 단계는 비파티션 테이블을 파티션 복사본으로 교체하며, 이 작업은 모든 다른 마이그레이션 단계가 성공적으로 완료된 후에만 사용해야 합니다.

이 방법에는 교환 마이그레이션 이전이나 도중에 반드시 처리해야 하는 몇 가지 제한 사항이 있습니다:

  • 보조 인덱스 및 외래 키는 파티션 테이블에 자동으로 재생성되지 않습니다.
  • 인덱스에 의존하는 일부 유형의 제약 조건(UNIQUE 및 EXCLUDE)은 파티션 테이블에 자동으로 재생성되지 않으며, 기본 인덱스가 존재하지 않기 때문입니다.
  • 원래 비파티션 테이블을 참조하는 외래 키는 파티션 테이블을 참조하도록 업데이트해야 합니다. PostgreSQL 11에서는 지원되지 않습니다.
  • 원래 테이블을 참조하는 뷰는 파티션 테이블을 참조하도록 자동으로 업데이트되지 않습니다.
# frozen_string_literal: true

class SwapPartitionMergeRequestDiffCommits < 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

이 마이그레이션이 완료된 후:

  • 파티션 테이블이 비파티션(원래) 테이블을 교체합니다.
  • 이전에 생성된 동기화 트리거가 삭제됩니다.

파티션 테이블이 이제 애플리케이션에서 사용할 준비가 완료되었습니다.