이 문서에서는 스키마 업데이트 권장사항을 설명합니다.
스키마 업데이트 시작 전 절차
스키마 업데이트를 실행하기 전에 다음을 수행해야 합니다.
데이터베이스의 모든 기존 데이터가 스키마 업데이트로 도입된 제약 조건을 준수하는지 확인합니다. 일부 스키마 업데이트는 현재 스키마뿐만 아니라 실제 데이터에 따라 달라지기 때문에 테스트 데이터베이스의 업데이트에 성공하더라도 프로덕션 데이터베이스의 업데이트에는 성공하지 못할 수도 있습니다. 다음은 일반적인 몇 가지 예시입니다.
- 기존 열에
NOT NULL주석을 추가하는 경우 열에 기존NULL값이 없는지 확인합니다. STRING또는BYTES열의 허용 길이를 줄이는 경우, 해당 열에서 기존의 모든 값이 길이 제약 조건을 충족하는지 확인합니다.
- 기존 열에
스키마 업데이트 중인 열, 테이블 또는 색인에 대해 쓰기를 수행할 경우 쓰는 값이 새 제약 조건을 충족하는지 확인해야 합니다.
열, 테이블 또는 색인을 삭제하는 경우 삭제한 열, 테이블 또는 색인에서 계속 읽거나 쓰지 않도록 해야 합니다.
스키마 업데이트의 실행 빈도를 제한합니다.
단기간에 지나치게 많은 스키마 업데이트를 수행하면 Spanner는 큐에 추가된 스키마 업데이트 처리를 throttle할 수 있습니다. 이는 Spanner가 스키마 버전을 저장할 공간 양을 제한하기 때문입니다. 보관 기간 내에 오래된 스키마 버전이 지나치게 많으면 스키마 업데이트가 제한될 수 있습니다. 최대 스키마 변경 비율은 데이터베이스의 총 열 수를 비롯한 많은 요소에 따라 달라집니다. 예를 들어 열이 2,000개(INFORMATION_SCHEMA.COLUMNS에 대략 행 2,000개)가 있는 데이터베이스는 보관 기간 내에 스키마 변경을 최대 1500회까지 수행할 수 있습니다(스키마 변경에 버전이 여러 개 필요한 경우 더 적음). 진행 중인 스키마 업데이트의 상태를 보려면 gcloud spanner operations
list 명령어를 사용하고 DATABASE_UPDATE_DDL 유형의 작업으로 필터링합니다. 진행 중인 스키마 업데이트를 취소하려면 gcloud spanner operations
cancel 명령어를 사용하고 작업 ID를 지정합니다.
DDL 문이 일괄 처리되는 방식과 각 일괄 처리 내의 순서는 결과 스키마 버전 수에 영향을 미칠 수 있습니다. 일정 기간 동안 수행할 수 있는 스키마 업데이트 수를 극대화하려면 스키마 버전 수를 최소화하는 일괄 처리를 사용해야 합니다. 일부 가이드라인은 대규모 업데이트에 설명되어 있습니다.
스키마 버전에 설명된 대로 일부 DDL 문은 여러 스키마 버전을 생성하며, 이러한 버전은 각 배치 내의 일괄 처리 및 순서를 고려할 때 중요합니다. 여러 스키마 버전을 만들 수 있는 문 유형에는 다음과 같은 두 가지 주요 유형이 있습니다.
CREATE INDEX와 같이 색인 데이터를 백필해야 할 수 있는 문NOT NULL또는 길이 제약 조건을 추가하는 등 Spanner가 기존 데이터를 검증하도록 강제하는 문
하지만 이러한 유형의 문이 항상 여러 스키마 버전을 만드는 것은 아닙니다. Spanner는 일괄 처리의 영향을 받는 여러 스키마 버전 사용을 방지하도록 이러한 유형의 문을 최적화할 수 있는 시기를 감지하려고 합니다. 예를 들어 다른 테이블의 개입 문 없이 색인의 기본 테이블의 CREATE TABLE 문과 동일한 배치에서 발생하는 CREATE INDEX 문은 색인 데이터를 백필할 필요가 없습니다. Spanner는 색인이 생성될 때 기본 테이블이 비어 있다고 보장할 수 있기 때문입니다. 대규모 업데이트 섹션에서는 이 속성을 사용하여 여러 색인을 효율적으로 만드는 방법을 설명합니다.
여러 스키마 버전을 만들지 않도록 DDL 문을 일괄 처리할 수 없는 경우 보관 기간 내에 단일 데이터베이스의 스키마에 대해 스키마 업데이트 수를 제한해야 합니다. 새 버전이 생성되기 전에 Spanner에서 이전 버전의 스키마를 삭제할 수 있도록 스키마 업데이트 기간을 늘립니다.
- 일부 관계형 데이터베이스 관리 시스템의 경우, 프로덕션 배포 시마다 데이터베이스에 대해 끊임없이 일련의 업그레이드와 다운그레이드 스키마 업데이트를 수행하는 소프트웨어 패키지가 있습니다. 이러한 유형의 프로세스는 Spanner에 권장되지 않습니다.
- Spanner는 기본 키를 사용하여 멀티테넌시 솔루션의 데이터 파티션을 나누도록 최적화되어 있습니다. 각 고객에 대해 별도의 테이블을 사용하는 멀티테넌시 지원 솔루션을 사용하는 경우 여러 고객에 걸쳐 스키마를 한 번에 업데이트하면 완료 시간이 긴 대량의 스키마 업데이트 작업 백로그가 발생할 수 있습니다.
- 각 문이 내부적으로 여러 버전의 스키마를 생성하므로, 유효성 검사 또는 색인 백필이 필요한 스키마 업데이트는 더 많은 서버 리소스를 사용합니다.
일괄 처리 시 문 실행 순서
Google Cloud CLI, REST API 또는 RPC API를 사용하는 경우 CREATE, ALTER 또는 DROP 문 하나 이상을 일괄 실행할 수 있습니다.
Spanner는 동일한 배치의 문을 순서대로 적용하고 첫 번째 오류에서 중지합니다. 문 적용 시 오류가 발생하면 해당 문은 롤백됩니다. 배치에서 이전에 적용된 문의 결과는 롤백되지 않습니다. 이 순서대로 문 적용은 피할 수 없는 백필이 필요한 문을 동시에 실행하려면 (예: 기존 대형 테이블에 여러 색인 생성) 해당 문을 별도의 배치로 제출해야 함을 의미합니다. 각 백필에 시간이 오래 걸릴 수 있기 때문입니다. 반면 색인이 있는 새 테이블을 만드는 경우 백필을 완전히 방지하기 위해 단일 배치에서 함께 배치 (CREATE TABLE 다음에 CREATE INDEX)하는 것이 좋습니다.
Spanner는 여러 배치의 문을 결합하고 재정렬하므로 여러 배치의 문을 데이터베이스에 적용되는 원자적 변경사항 하나에 혼합할 수 있습니다. 각 원자적 변경사항 내에서 서로 다른 배치에 포함된 문은 임의의 순서로 발생합니다. 예를 들어 문 배치 하나에 ALTER TABLE table_name ALTER COLUMN column_name STRING(50)이 포함되어 있고 또 다른 문 배치에 ALTER TABLE table_name ALTER COLUMN
column_name STRING(20)이 포함되어 있는 경우 Spanner는 이러한 두 열 중 하나에서 해당 열을 그대로 두지만 특정 상태를 지정하지는 않습니다.
대규모 스키마 업데이트를 위한 옵션
테이블과 해당 테이블에서 대규모 색인을 만드는 가장 좋은 방법은 모든 색인을 동시에 만들어 단일 스키마 버전만 만드는 것입니다. DDL 문 목록의 테이블 바로 다음에 색인을 만드는 것이 좋습니다. 데이터베이스를 생성하거나 문의 단일 대규모 일괄 처리에서 테이블과 해당 색인을 만들 수 있습니다. 각각 많은 색인이 있는 테이블을 여러 개 만들어야 하는 경우 모든 문을 단일 배치로 포함할 수 있습니다. 단일 스키마 버전을 사용하여 모든 문을 함께 실행할 수 있는 경우 단일 배치에 수천 개의 문을 포함할 수 있습니다.
문에서 색인 데이터를 백필하거나 데이터 유효성 검사를 수행해야 하는 경우 단일 스키마 버전으로 실행할 수 없습니다. 이는 색인의 기본 테이블이 이미 존재하는 경우 CREATE INDEX 문에 대해 발생합니다. 이전 DDL 문의 배치에서 생성되었거나 여러 스키마 버전이 필요한 CREATE TABLE 및 CREATE INDEX 문 사이의 배치에 명령문이 있었기 때문입니다. Spanner에서는 단일 배치에 이러한 문이 10개 이하여야 합니다. 특히 백필이 필요한 색인 생성은 색인당 여러 스키마 버전을 사용하므로, 하루에 백필이 필요한 새 색인을 3개 이하로 만드는 것이 좋습니다. 일괄 처리의 경우 백필을 피할 수 없는 경우가 이에 해당합니다.
예를 들어 이 문의 배치는 단일 스키마 버전을 사용합니다.
GoogleSQL
CREATE TABLE Singers ( SingerId INT64 NOT NULL, FirstName STRING(1024), LastName STRING(1024), ) PRIMARY KEY (SingerId); CREATE INDEX SingersByFirstName ON Singers(FirstName); CREATE INDEX SingersByLastName ON Singers(LastName); CREATE TABLE Albums ( SingerId INT64 NOT NULL, AlbumId INT64 NOT NULL, AlbumTitle STRING(MAX), ) PRIMARY KEY (SingerId, AlbumId); CREATE INDEX AlbumsByTitle ON Albums(AlbumTitle);
반대로 이 배치에서는 여러 스키마 버전을 사용합니다. 그 이유는 UnrelatedIndex에 기본 테이블이 이미 있어야 하므로 백필이 필요하며 다음 모든 색인에서는 백필이 필요합니다(기본 테이블과 동일한 배치에 있는 경우 포함).
GoogleSQL
CREATE TABLE Singers ( SingerId INT64 NOT NULL, FirstName STRING(1024), LastName STRING(1024), ) PRIMARY KEY (SingerId); CREATE TABLE Albums ( SingerId INT64 NOT NULL, AlbumId INT64 NOT NULL, AlbumTitle STRING(MAX), ) PRIMARY KEY (SingerId, AlbumId); CREATE INDEX UnrelatedIndex ON UnrelatedTable(UnrelatedIndexKey); CREATE INDEX SingersByFirstName ON Singers(FirstName); CREATE INDEX SingersByLastName ON Singers(LastName); CREATE INDEX AlbumsByTitle ON Albums(AlbumTitle);
스키마 버전을 최소화하려면 UnrelatedIndex 생성을 해당 배치의 끝이나 다른 배치로 이동하는 것이 좋습니다.
API 요청이 완료될 때까지 대기
projects.instances.databases.updateDdl(REST API) 또는 UpdateDatabaseDdl(RPC API) 요청을 실행하는 경우, 각각 projects.instances.databases.operations.get(REST API) 또는 GetOperation(RPC API)을 사용하여 각 요청이 완료될 때까지 기다린 후 새 요청을 시작합니다. 각 요청이 완료되기를 기다리면 애플리케이션에서 스키마 업데이트의 진행 상황을 추적할 수 있습니다. 그러면 대기 중인 스키마 업데이트의 백로그를 관리 가능한 크기로 유지할 수도 있습니다.
일괄 로드
새 테이블에 데이터를 일괄 로드할 때 데이터를 로드하기 전이나 후에 보조 색인을 만들 수 있습니다. 로드 후 색인을 만들면 데이터 로드가 더 빠르지만 색인을 백필해야 합니다.
데이터를 먼저 로드한 다음 색인을 생성하면 테이블만 작성되므로 데이터 수집이 더 빠릅니다. 나중에 색인 백필을 통해 테이블 데이터와 함께 색인 데이터를 작성하는 것보다 더 효율적인 최적화된 배치로 색인 데이터를 작성할 수 있습니다. 하지만 색인 백필에는 여러 스키마 버전이 필요하며 제한이 있습니다. 대규모 업데이트 옵션에 설명된 대로 단일 배치에서 백필이 필요한 색인을 10개 이하로 만들어야 하며, 하루에 이러한 색인을 3개 이하로 만드는 것이 가장 좋습니다.
또는 대규모 업데이트 옵션에 설명된 대로 동일한 일괄 처리에서 테이블과 색인을 만들 수 있습니다. 이렇게 하면 색인 백필이 방지되지만 데이터를 로드할 때 각 색인을 업데이트해야 하므로 데이터 일괄 로드가 느려집니다.
특정 상황에서 어떤 선택이 더 나은지는 로드할 데이터의 양, 특정 테이블 및 색인 키, 필요한 색인의 수, 동일한 데이터베이스에서 대량 로드 작업이 얼마나 자주 필요한지에 따라 달라집니다. 일반적으로 각 테이블에 많은 양의 데이터를 로드해야 하고 몇 개의 색인만 필요한 경우 색인을 별도로 만드는 것이 좋습니다.