InfoGrab DocsInfoGrab Docs

데이터베이스 테이블 파티셔닝

요약

아래에서 답을 찾지 못한 질문이 있다면 이 이슈에 해당 질문이 있는지 확인하고 없으면 추가합니다. 테이블 파티셔닝은 테이블의 데이터를 더 작은 물리 테이블로 나누되 하나의 큰 테이블처럼 동작하게 하는 데이터베이스 기능입니다.

Warning

아래에서 답을 찾지 못한 질문이 있다면 이 이슈에 해당 질문이 있는지 확인하고 없으면 추가합니다. @gitlab-org/database-team/triage를 태그하면 가능한 한 빨리 답변을 드립니다. Slack에서 답을 받았다면 앞으로 이 문서를 업데이트할 수 있도록 그 내용도 이슈에 기록합니다.

테이블 파티셔닝은 테이블의 데이터를 더 작은 물리 테이블로 나누되 하나의 큰 테이블처럼 동작하게 하는 데이터베이스 기능입니다. 애플리케이션을 파티셔닝을 염두에 두고 설계하면 다음과 같은 여러 이점을 얻을 수 있습니다.

  • 데이터베이스가 검색 대상에서 많은 데이터를 저렴하게 걸러내면서도 SQL 기능을 온전히 제공하므로, 쿼리 성능을 크게 개선할 수 있습니다.
  • 파티션 전체를 삭제하는 방식으로 데이터베이스에 최소한의 영향만 주면서 대량 삭제를 수행할 수 있습니다. 보존 기간을 벗어난 데이터를 주기적으로 삭제해야 하는 기능에 자연스럽게 들어맞습니다.
  • VACUUM 이나 인덱스 재구축 같은 관리 작업을 하나의 거대한 테이블 전체가 아니라 개별 파티션 단위로 수행할 수 있습니다.

다만 모든 모델이 파티셔닝 방식에 맞는 것은 아니며, 잘못 구현하면 상당한 단점이 따릅니다. 또한 테이블은 생성 시점에만 파티셔닝할 수 있으므로, 사용량이 많은 데이터베이스에 파티셔닝을 적용하기는 쉽지 않습니다. 백엔드 개발자가 기존 테이블을 파티셔닝할 수 있도록 마이그레이션 도구 모음을 제공하지만, 마이그레이션 과정 자체가 상당히 무겁고 여러 릴리스에 걸쳐 여러 단계를 거칩니다. 파티셔닝과 관련 마이그레이션에는 제약이 있으므로, 이 기능을 활용하기 전에 파티셔닝이 자신의 사용 사례에 어떻게 들어맞는지 이해해야 합니다.

파티셔닝 마이그레이션 헬퍼는 원본 테이블의 파티셔닝된 복제본을 만들고 트리거와 백그라운드 마이그레이션을 조합하여 새 테이블로 데이터를 복사하는 방식으로 동작합니다. 원본 테이블 스키마 변경은 파티셔닝 마이그레이션과 병행할 수 있지만, 마이그레이션을 동작하게 하는 기반 메커니즘이 깨지지 않도록 주의해야 합니다. 예를 들어 파티셔닝 대상 테이블에 칼럼을 추가하면 파티셔닝된 테이블과 트리거 정의도 함께 업데이트해야 합니다.

파티셔닝 사용 시점 결정#

파티셔닝은 제대로 적용하면 매우 유용하지만, 테이블의 데이터와 워크로드가 파티셔닝 방식에 자연스럽게 맞는지 먼저 확인해야 합니다. 파티셔닝이 자신의 문제에 적합한지 판단하려면 다음 몇 가지를 이해해야 합니다.

  • 테이블 파티셔닝. 테이블은 파티션 키를 기준으로 파티셔닝하며, 파티션 키는 데이터를 파티션에 어떻게 나눌지 결정하는 칼럼 또는 칼럼의 집합입니다. 데이터베이스는 데이터를 읽거나 쓸 때 파티션 키로 어떤 파티션에 접근할지 판단합니다. 파티션 키는 해당 테이블에 접근하는 거의 모든 쿼리의 WHERE 절에 포함될 만한 칼럼이어야 합니다.
  • 데이터를 나누는 방식. 데이터베이스가 데이터를 파티션에 나눌 때 어떤 전략을 사용하는지 확인합니다.

복합 기본 키가 있는 파티셔닝된 테이블을 사용하는 Rails 모델#

PostgreSQL은 파티셔닝된 테이블에서 기본 키를 포함한 모든 고유 제약 조건에 파티션 키가 들어가도록 요구합니다. 테이블을 partition_id 나 created_at 같은 칼럼으로 파티셔닝하면, 데이터베이스 수준의 기본 키는 예를 들어 (id, partition_id) 같은 복합 키가 됩니다.

Rails는 복합 기본 키를 지원합니다. 그러나 복합 키가 PostgreSQL 파티셔닝 요건 때문에만 존재하고 애플리케이션 수준의 행 식별자는 여전히 id 인 경우, ActiveRecord는 올바른 동작을 자동으로 추론하지 못합니다. 명시적으로 선언하지 않으면 ActiveRecord는 기본 키를 ["id", "partition_id"]로 취급하고 여러 동작이 잘못된 결과를 냅니다.

작업 self.primary_key = :id 없을 때의 동작
Model.find(integer) ActiveRecord::RecordNotFound 발생
record.id 정수 대신 [id, partition_id] 배열 반환
record.id == integer 항상 false
to_param / URL 헬퍼 잘못된 경로 세그먼트 생성, 예: "42_100"
as_json["id"] / API 응답 id를 정수 대신 배열로 직렬화

이를 피하려면 모델에 기본 키를 명시적으로 설정합니다.

class MyModel < ApplicationRecord
  self.primary_key = :id
end

이렇게 하면 ActiveRecord는 레코드 조회에 id만 사용하고, 데이터베이스는 파티셔닝을 위해 복합 기본 키를 그대로 강제합니다.

Warning

self.primary_key = :id를 설정하면 ActiveRecord 동작은 바로잡히지만 쿼리에서 파티션 프루닝이 일어난다는 보장은 없습니다. PostgreSQL은 쿼리의 WHERE 절에 파티션 키가 포함될 때만 파티션을 잘라낼 수 있습니다. 성능에 민감한 모든 쿼리가 파티션 키 칼럼으로 필터링하는지 확인합니다. 그렇지 않으면 PostgreSQL 이 모든 파티션을 스캔합니다.

id가 파티션 내에서만 고유한 경우#

위 패턴은 id가 단일 시퀀스에서 나오는 경우처럼 모든 파티션에 걸쳐 전역적으로 고유할 때는 충분합니다. 이 경우 id 만으로 수행하는 UPDATE와 DELETE도 올바른 행에 도달합니다.

id가 전역이 아니라 파티션 내에서만 고유한 경우, id 만으로 필터링하는 UPDATE 나 DELETE는 행을 찾기 위해 모든 파티션을 스캔해야 합니다. 이런 경우에는 ActiveRecord가 쓰기 작업의 WHERE 절에 파티션 키를 포함하도록 두 칼럼을 모두 지정한 query_constraints도 함께 선언합니다.

class MyModel < ApplicationRecord
  self.primary_key = :id
  query_constraints :id, :partition_id
end

query_constraints는 primary_key로 수행되는 SELECT 조회에는 영향을 주지 않습니다. 지정한 칼럼을 UPDATE와 DELETE 문의 WHERE 절에만 추가하여, PostgreSQL 이 쓰기 작업에서 파티션을 잘라낼 수 있게 합니다.

Note

이 지침은 PostgreSQL 파티셔닝 요건 때문에 복합 기본 키가 존재하면서 id가 여전히 논리적인 애플리케이션 수준 식별자인 테이블에만 해당합니다. 모든 복합 기본 키 상황에 적용되는 일반 지침은 아닙니다.

적합한 파티셔닝 전략 결정#

선택할 수 있는 파티셔닝 전략은 date range, int range, hash, list 입니다.

데이터베이스 테이블 파티셔닝

GitLab v19.4
원문 보기

요약

아래에서 답을 찾지 못한 질문이 있다면 이 이슈에 해당 질문이 있는지 확인하고 없으면 추가합니다. 테이블 파티셔닝은 테이블의 데이터를 더 작은 물리 테이블로 나누되 하나의 큰 테이블처럼 동작하게 하는 데이터베이스 기능입니다.

Warning

아래에서 답을 찾지 못한 질문이 있다면 이 이슈에 해당 질문이 있는지 확인하고 없으면 추가합니다. @gitlab-org/database-team/triage를 태그하면 가능한 한 빨리 답변을 드립니다. Slack에서 답을 받았다면 앞으로 이 문서를 업데이트할 수 있도록 그 내용도 이슈에 기록합니다.

테이블 파티셔닝은 테이블의 데이터를 더 작은 물리 테이블로 나누되 하나의 큰 테이블처럼 동작하게 하는 데이터베이스 기능입니다. 애플리케이션을 파티셔닝을 염두에 두고 설계하면 다음과 같은 여러 이점을 얻을 수 있습니다.

  • 데이터베이스가 검색 대상에서 많은 데이터를 저렴하게 걸러내면서도 SQL 기능을 온전히 제공하므로, 쿼리 성능을 크게 개선할 수 있습니다.
  • 파티션 전체를 삭제하는 방식으로 데이터베이스에 최소한의 영향만 주면서 대량 삭제를 수행할 수 있습니다. 보존 기간을 벗어난 데이터를 주기적으로 삭제해야 하는 기능에 자연스럽게 들어맞습니다.
  • VACUUM 이나 인덱스 재구축 같은 관리 작업을 하나의 거대한 테이블 전체가 아니라 개별 파티션 단위로 수행할 수 있습니다.

다만 모든 모델이 파티셔닝 방식에 맞는 것은 아니며, 잘못 구현하면 상당한 단점이 따릅니다. 또한 테이블은 생성 시점에만 파티셔닝할 수 있으므로, 사용량이 많은 데이터베이스에 파티셔닝을 적용하기는 쉽지 않습니다. 백엔드 개발자가 기존 테이블을 파티셔닝할 수 있도록 마이그레이션 도구 모음을 제공하지만, 마이그레이션 과정 자체가 상당히 무겁고 여러 릴리스에 걸쳐 여러 단계를 거칩니다. 파티셔닝과 관련 마이그레이션에는 제약이 있으므로, 이 기능을 활용하기 전에 파티셔닝이 자신의 사용 사례에 어떻게 들어맞는지 이해해야 합니다.

파티셔닝 마이그레이션 헬퍼는 원본 테이블의 파티셔닝된 복제본을 만들고 트리거와 백그라운드 마이그레이션을 조합하여 새 테이블로 데이터를 복사하는 방식으로 동작합니다. 원본 테이블 스키마 변경은 파티셔닝 마이그레이션과 병행할 수 있지만, 마이그레이션을 동작하게 하는 기반 메커니즘이 깨지지 않도록 주의해야 합니다. 예를 들어 파티셔닝 대상 테이블에 칼럼을 추가하면 파티셔닝된 테이블과 트리거 정의도 함께 업데이트해야 합니다.

파티셔닝 사용 시점 결정#

파티셔닝은 제대로 적용하면 매우 유용하지만, 테이블의 데이터와 워크로드가 파티셔닝 방식에 자연스럽게 맞는지 먼저 확인해야 합니다. 파티셔닝이 자신의 문제에 적합한지 판단하려면 다음 몇 가지를 이해해야 합니다.

  • 테이블 파티셔닝. 테이블은 파티션 키를 기준으로 파티셔닝하며, 파티션 키는 데이터를 파티션에 어떻게 나눌지 결정하는 칼럼 또는 칼럼의 집합입니다. 데이터베이스는 데이터를 읽거나 쓸 때 파티션 키로 어떤 파티션에 접근할지 판단합니다. 파티션 키는 해당 테이블에 접근하는 거의 모든 쿼리의 WHERE 절에 포함될 만한 칼럼이어야 합니다.
  • 데이터를 나누는 방식. 데이터베이스가 데이터를 파티션에 나눌 때 어떤 전략을 사용하는지 확인합니다.

복합 기본 키가 있는 파티셔닝된 테이블을 사용하는 Rails 모델#

PostgreSQL은 파티셔닝된 테이블에서 기본 키를 포함한 모든 고유 제약 조건에 파티션 키가 들어가도록 요구합니다. 테이블을 partition_id 나 created_at 같은 칼럼으로 파티셔닝하면, 데이터베이스 수준의 기본 키는 예를 들어 (id, partition_id) 같은 복합 키가 됩니다.

Rails는 복합 기본 키를 지원합니다. 그러나 복합 키가 PostgreSQL 파티셔닝 요건 때문에만 존재하고 애플리케이션 수준의 행 식별자는 여전히 id 인 경우, ActiveRecord는 올바른 동작을 자동으로 추론하지 못합니다. 명시적으로 선언하지 않으면 ActiveRecord는 기본 키를 ["id", "partition_id"]로 취급하고 여러 동작이 잘못된 결과를 냅니다.

작업 self.primary_key = :id 없을 때의 동작
Model.find(integer) ActiveRecord::RecordNotFound 발생
record.id 정수 대신 [id, partition_id] 배열 반환
record.id == integer 항상 false
to_param / URL 헬퍼 잘못된 경로 세그먼트 생성, 예: "42_100"
as_json["id"] / API 응답 id를 정수 대신 배열로 직렬화

이를 피하려면 모델에 기본 키를 명시적으로 설정합니다.

class MyModel < ApplicationRecord
  self.primary_key = :id
end

이렇게 하면 ActiveRecord는 레코드 조회에 id만 사용하고, 데이터베이스는 파티셔닝을 위해 복합 기본 키를 그대로 강제합니다.

Warning

self.primary_key = :id를 설정하면 ActiveRecord 동작은 바로잡히지만 쿼리에서 파티션 프루닝이 일어난다는 보장은 없습니다. PostgreSQL은 쿼리의 WHERE 절에 파티션 키가 포함될 때만 파티션을 잘라낼 수 있습니다. 성능에 민감한 모든 쿼리가 파티션 키 칼럼으로 필터링하는지 확인합니다. 그렇지 않으면 PostgreSQL 이 모든 파티션을 스캔합니다.

id가 파티션 내에서만 고유한 경우#

위 패턴은 id가 단일 시퀀스에서 나오는 경우처럼 모든 파티션에 걸쳐 전역적으로 고유할 때는 충분합니다. 이 경우 id 만으로 수행하는 UPDATE와 DELETE도 올바른 행에 도달합니다.

id가 전역이 아니라 파티션 내에서만 고유한 경우, id 만으로 필터링하는 UPDATE 나 DELETE는 행을 찾기 위해 모든 파티션을 스캔해야 합니다. 이런 경우에는 ActiveRecord가 쓰기 작업의 WHERE 절에 파티션 키를 포함하도록 두 칼럼을 모두 지정한 query_constraints도 함께 선언합니다.

class MyModel < ApplicationRecord
  self.primary_key = :id
  query_constraints :id, :partition_id
end

query_constraints는 primary_key로 수행되는 SELECT 조회에는 영향을 주지 않습니다. 지정한 칼럼을 UPDATE와 DELETE 문의 WHERE 절에만 추가하여, PostgreSQL 이 쓰기 작업에서 파티션을 잘라낼 수 있게 합니다.

Note

이 지침은 PostgreSQL 파티셔닝 요건 때문에 복합 기본 키가 존재하면서 id가 여전히 논리적인 애플리케이션 수준 식별자인 테이블에만 해당합니다. 모든 복합 기본 키 상황에 적용되는 일반 지침은 아닙니다.

적합한 파티셔닝 전략 결정#

선택할 수 있는 파티셔닝 전략은 date range, int range, hash, list 입니다.