스키마 업데이트

Cloud Spanner를 사용하면 다운타임 없이 스키마 업데이트를 수행할 수 있습니다. 다음과 같은 여러 가지 방법으로 기존 데이터베이스의 스키마를 업데이트할 수 있습니다.

지원되는 스키마 업데이트

Cloud Spanner는 기존 데이터베이스에 대해 다음과 같은 스키마 업데이트를 지원합니다.

  • 새 테이블을 만듭니다. 새 테이블의 열은 NOT NULL일 수 있습니다.
  • 테이블을 삭제합니다(테이블 내에 인터리브 처리된 다른 테이블이 없고 보조 색인이 없는 경우).
  • 모든 테이블에 키 열이 아닌 열을 추가합니다. 새로운 키 열이 아닌 열은 NOT NULL일 수 없습니다.
  • ARRAY 열을 제외하고 키 열이 아닌 열에 NOT NULL을 추가합니다.
  • 키 열이 아닌 열에서 NOT NULL을 삭제합니다.
  • 모든 테이블에서 키 열이 아닌 열을 제거합니다(보조 색인에 사용되는 열이 아닌 경우).
  • STRING 열을 BYTES 열로 변경하거나 BYTES 열을 STRING 열로 변경합니다.
  • STRING 또는 BYTES 유형(MAX 포함)의 길이 제한을 늘리거나 줄입니다(하위 테이블 한 개 이상에 상속되는 기본 키 열이 아닌 경우).
  • 값 열과 기본 키 열에서 커밋 타임스탬프를 사용 설정하거나 중지합니다.
  • 보조 색인을 추가하거나 삭제합니다.

스키마 업데이트 성능

Cloud Spanner의 스키마 업데이트에는 다운타임이 필요 없습니다. Cloud Spanner 데이터베이스에 대해 일괄 DDL 문을 실행하면 Cloud Spanner가 장기 실행 작업으로 업데이트를 적용하는 동안 중단 없이 데이터베이스 쓰기 및 읽기를 계속할 수 있습니다.

DDL 문을 실행하는 데 걸리는 시간은 업데이트에 기존 데이터 유효성 검사 또는 데이터 백필이 필요한지 여부에 따라 다릅니다. 예를 들어 기존 열에 NOT NULL 주석을 추가하는 경우 Cloud Spanner는 해당 열의 모든 값을 읽어 열에 NULL 값이 없는지 확인해야 합니다. 유효성을 검사할 데이터가 많으면 이 단계에 오랜 시간이 걸릴 수 있습니다. 또 다른 예는 데이터베이스에 색인을 추가하는 경우입니다. Cloud Spanner는 기존 데이터를 사용하여 색인을 백필하는데, 색인 정의와 해당하는 기본 테이블의 크기에 따라 이 프로세스에 오랜 시간이 걸릴 수 있습니다. 그러나 테이블에 새 열을 추가하면 유효성을 검사할 기존 데이터가 없으므로, Cloud Spanner가 업데이트를 더 빠르게 수행할 수 있습니다.

요약하면, Cloud Spanner가 기존 데이터 유효성을 검사할 필요가 없는 스키마 업데이트는 수분 내에 수행될 수 있습니다. 유효성 검사가 필요한 스키마 업데이트는 유효성을 검사해야 하는 기존 데이터 양에 따라 시간이 오래 걸릴 수 있지만 데이터 유효성 검사는 프로덕션 트래픽보다 낮은 우선 순위로 백그라운드에서 실행됩니다. 다음 섹션에서 데이터 유효성 검사가 필요한 스키마 업데이트를 보다 자세히 설명합니다.

데이터 유효성 검사가 필요한 스키마 업데이트

기존 데이터가 새 제약 조건을 충족하는지 확인해야 하는 스키마 업데이트를 수행할 수 있습니다. 스키마 업데이트에 데이터 유효성 검사가 필요한 경우 Cloud Spanner는 영향을 받는 스키마 항목에 충돌하는 스키마 업데이트를 허용하지 않고 백그라운드에서 데이터 유효성을 검사합니다. 유효성 검사가 성공하면 스키마 업데이트가 성공합니다. 유효성 검사가 실패하면 스키마 업데이트가 실패합니다. 유효성 검사 작업은 장기 실행 작업으로 실행됩니다. 이러한 작업의 상태를 확인하여 작업 성공 또는 실패를 확인할 수 있습니다.

예를 들어 스키마에서 Songwriters 테이블을 정의했다고 가정합니다.

CREATE TABLE Songwriters (
  Id         INT64 NOT NULL,
  FirstName  STRING(1024),
  LastName   STRING(1024),
  Nickname   STRING(MAX),
  OpaqueData BYTES(MAX),
) PRIMARY KEY (Id);

다음 스키마 업데이트는 허용되지만 유효성 검사가 필요하며 기존 데이터 양에 따라 완료하는 데 시간이 오래 걸릴 수 있습니다.

  • 키 열이 아닌 열에 NOT NULL 주석을 추가합니다. 예를 들면 다음과 같습니다.

    ALTER TABLE Songwriters ALTER COLUMN Nickname STRING(MAX) NOT NULL;
    
  • 열의 길이를 줄입니다. 예를 들면 다음과 같습니다.

    ALTER TABLE Songwriters ALTER COLUMN FirstName STRING(10);
    
  • BYTES에서 STRING으로 변경합니다. 예를 들면 다음과 같습니다.

    ALTER TABLE Songwriters ALTER COLUMN OpaqueData STRING(MAX);
    
  • 기존 TIMESTAMP 열에 커밋 타임스탬프를 사용 설정합니다. 예를 들면 다음과 같습니다.

    ALTER TABLE Albums ALTER COLUMN LastUpdateTime SET OPTIONS (allow_commit_timestamp = true);
    

기본 데이터가 새 제약 조건을 충족하지 않으면 이러한 스키마 업데이트는 실패합니다. 예를 들어 기존 데이터가 새 정의의 NOT NULL 제약 조건을 충족하지 않으므로 Nickname 열에 있는 값이 NULL이면 위의 ALTER TABLE Songwriters ALTER COLUMN Nickname STRING(MAX) NOT NULL 문이 실패합니다.

데이터 유효성 검사는 몇 분에서 몇 시간까지 걸릴 수 있습니다. 데이터 유효성 검사를 완료하는 데 걸리는 시간은 다음에 따라 다릅니다.

  • 데이터 세트 크기
  • 인스턴스의 노드 수
  • 인스턴스의 부하

일부 스키마 업데이트의 경우 스키마 업데이트가 완료되기 전에 데이터베이스에 대한 요청 동작이 변경될 수 있습니다. 예를 들어 하나의 열에 NOT NULL을 추가하면 Cloud Spanner는 거의 즉각적으로 해당 열에 NULL을 사용하는 새 요청에 대해 쓰기를 거부하기 시작합니다. 새 스키마 업데이트가 결국 데이터 유효성 검사에 실패하면 이전 스키마에서 허용되었던 쓰기 작업이라도 일정 기간 동안 쓰기가 차단됩니다.

projects.instances.databases.operations.cancel 메서드 또는 gcloud spanner operations를 사용하여 장기 실행 데이터 유효성 검사 작업을 취소할 수 있습니다.

일괄 처리 시 문 실행 순서

gcloud 도구, REST API 또는 RPC API를 사용하는 경우 한 개 이상의 CREATE, ALTER 또는 DROP 을 일괄 실행할 수 있습니다.

Cloud Spanner는 동일한 배치의 구문을 순서대로 적용하고 첫 번째 오류에서 중단합니다. 구문 적용 시 오류가 발생하면 해당 국문은 롤백됩니다. 배치에서 이전에 적용된 문의 결과는 롤백되지 않습니다.

Cloud Spanner는 여러 배치의 문을 결합하고 재정렬함으로써 여러 배치의 문을 데이터베이스에 적용되는 하나의 원자적 변경사항으로 혼합할 수 있습니다. 각 원자적 변경사항 내에서 서로 다른 배치에 포함된 문은 임의의 순서로 발생합니다. 예를 들어 하나의 문 배치에 ALTER TABLE MyTable ALTER COLUMN MyColumn STRING(50)이 포함되어 있고 또 다른 문 배치에 ALTER TABLE MyTable ALTER COLUMN MyColumn STRING(20)이 포함되어 있는 경우, Cloud Spanner는 해당 열을 이러한 두 상태 중 하나로 두지만 특정 상태가 지정되지는 않습니다.

스키마 업데이트 중에 생성되는 스키마 버전

Cloud Spanner는 스키마 버전 관리를 사용하므로, 대규모 데이터베이스에 대한 스키마 업데이트 시 다운타임이 발생하지 않습니다. Cloud Spanner는 스키마 업데이트가 처리되는 동안 읽기를 지원하기 위해 이전 스키마 버전을 유지합니다. 그런 다음 Cloud Spanner는 새 스키마 버전을 하나 이상 만들어 스키마 업데이트를 처리합니다. 각 버전에는 위에 설명된 것처럼 단일한 원자적 변경사항을 구성하는 문 모음의 결과가 포함됩니다.

스키마 버전은 DDL 문 배치 또는 개별 DDL 문과 반드시 일대일로 대응하지는 않습니다. 예를 들어 인터리브 처리되지 않은 색인 생성이나 데이터 유효성 검사가 필요한 문과 같은 일부 개별 DDL 문의 경우 스키마 버전이 여러 개 생성됩니다. 다른 경우에는 몇 개의 DDL 문이 단일 버전에서 함께 일괄 처리될 수 있습니다. 이전 스키마 버전은 서버 및 스토리지 리소스를 상당히 소비할 수 있으며, 만료될 때까지 보관됩니다(이전 버전의 데이터를 읽을 필요가 없음).

다음 테이블은 Cloud Spanner에서 스키마를 업데이트하는 데 걸리는 시간을 보여줍니다.

스키마 작업 예상 기간
CREATE TABLE 수 분
CREATE INDEX

색인 전에 기본 테이블이 생성되는 경우 수 분에서 수 시간

해당 문이 기본 테이블의 CREATE TABLE 문과 동시에 실행되는 경우 수 분

DROP TABLE 수 분
DROP INDEX 수 분
ALTER TABLE ... ADD COLUMN 수 분
ALTER TABLE ... ALTER COLUMN

백그라운드 유효성 검사가 필요한 경우 수 분에서 수 시간

백그라운드 유효성 검사가 필요하지 않은 경우 수 분

ALTER TABLE ... DROP COLUMN 수 분

스키마 업데이트 권장사항

다음 섹션에서는 스키마 업데이트 권장사항을 설명합니다.

스키마 업데이트 실행 전 절차

스키마 업데이트를 실행하기 전에 다음을 수행해야 합니다.

  • 변경하려는 데이터베이스의 모든 기존 데이터가 스키마 업데이트에 필요한 제약 조건을 충족하는지 확인합니다. 일부 유형의 스키마 업데이트는 현재 스키마뿐만 아니라 데이터베이스의 데이터에 따라서도 성공 여부가 달라지기 때문에 테스트 데이터베이스의 스키마 업데이트에 성공하더라도 프로덕션 데이터베이스의 스키마 업데이트에는 성공하지 못할 수도 있습니다. 다음은 일반적인 몇 가지 예시입니다.

    • 기존 열에 NOT NULL 주석을 추가하는 경우 열에 기존 NULL 값이 없는지 확인합니다.
    • STRING 또는 BYTES 열의 허용 길이를 줄이는 경우, 해당 열에서 기존의 모든 값이 원하는 길이 제약 조건을 충족하는지 확인합니다.
  • 스키마 업데이트 중인 열, 테이블 또는 색인에 대해 쓰기를 수행할 경우 쓰는 값이 새 제약 조건을 충족하는지 확인해야 합니다.

  • 열, 테이블 또는 색인을 삭제하는 경우 삭제한 열, 테이블 또는 색인에서 계속 읽거나 쓰지 않도록 해야 합니다.

스키마 업데이트의 실행 빈도 제한

단기간에 지나치게 많은 스키마 업데이트를 수행하는 경우 Cloud Spanner는 큐에 추가된 스키마 업데이트 처리를 throttle할 수 있습니다. 이는 Cloud Spanner가 스키마 버전을 저장할 공간을 제한하기 때문입니다. 보관 기간 내에 오래된 스키마 버전이 지나치게 많으면 스키마 업데이트가 제한될 수 있습니다. 최대 스키마 변경 비율은 데이터베이스의 총 열 수를 비롯한 많은 요소에 따라 달라집니다. 예를 들어 2,000개의 열(INFORMATION_SCHEMA.COLUMNS에 대략 2,000개 행)이 있는 데이터베이스는 보관 기간 내에 최대 1500개의 간단한 스키마 변경을 수행할 수 있습니다(스키마 변경 시 여러 버전이 필요한 경우 더 적음). 진행 중인 스키마 업데이트의 상태를 보려면 gcloud spanner operations list 명령어를 사용하고 DATABASE_UPDATE_DDL 유형의 작업으로 필터링합니다. 진행 중인 스키마 업데이트를 취소하려면 gcloud spanner operations cancel 명령어를 사용하고 작업 ID를 지정합니다.

DDL 문을 일괄 처리할 수 없는 경우 보관 기간 동안 단일 데이터베이스의 스키마에 대해 스키마 업데이트를 여러 번 실행하지 않도록 할 수 있습니다. 새 버전이 생성되기 전에 Cloud Spanner가 이전 버전의 스키마를 삭제할 수 있도록 하려면 스키마 업데이트 기간을 늘립니다.

  • 일부 관계형 데이터베이스 관리 시스템의 경우, 프로덕션 배포 시마다 데이터베이스에 대해 끊임없이 일련의 업그레이드와 다운그레이드 스키마 업데이트를 수행하는 소프트웨어 패키지가 있습니다. 이러한 유형의 프로세스는 Cloud Spanner에 권장되지 않습니다.
  • Cloud Spanner는 기본 키를 사용하여 멀티테넌시 지원 솔루션에 적합하게 데이터를 분할하도록 최적화되어 있습니다. 각 고객에 대해 별도의 테이블을 사용하는 멀티테넌시 지원 솔루션으로 인해 완료 시간이 긴 대량의 스키마 업데이트 작업 백로그가 발생할 수 있습니다.
  • 각 문이 내부적으로 여러 버전의 스키마를 생성하므로, 유효성 검사 또는 색인 백필이 필요한 스키마 업데이트는 더 많은 서버 리소스를 사용합니다.

대규모 스키마 업데이트를 위한 옵션

테이블과 해당 테이블에서 대규모 색인을 만드는 가장 좋은 방법은 모두 한꺼번에 만드는 것입니다. 데이터베이스를 생성하거나 DDL 문의 단일 대규모 일괄 처리에서 테이블과 해당 색인을 만들 수 있습니다. 단일 요청에서 수천 개의 DDL 문을 일괄 처리할 수 있지만 10개 이하의 문에서는 유효성 검사 또는 백필이 필요할 수 있습니다.

DDL 문의 단일 대규모 일괄 처리에서 테이블과 해당 색인을 만들 수 없는 경우 매일 3개 이하의 새로운 색인을 추가해봅니다.

API 요청이 완료될 때까지 대기

projects.instances.databases.updateDdl(REST API) 또는 UpdateDatabaseDdl(RPC API) 요청을 실행하는 경우, 각각 projects.instances.databases.operations.get(REST API) 또는 GetOperation(RPC API)을 사용하여 각 요청이 완료될 때까지 기다린 후 새 요청을 시작합니다. 각 요청이 완료되기를 기다리면 애플리케이션에서 스키마 업데이트의 진행 상황을 추적할 수 있습니다. 그러면 대기 중인 스키마 업데이트의 백로그를 관리 가능한 크기로 유지할 수도 있습니다.

일괄 로드

테이블 작성 후 테이블에 데이터를 일괄 로드하는 경우, 데이터가 로드된 후 색인을 작성하는 것이 일반적으로 더 효율적입니다. 여러 색인을 추가하는 경우 대규모 업데이트 옵션에서 설명한 대로 초기 스키마의 모든 테이블과 색인을 사용하여 데이터베이스를 생성하는 것이 더 효율적일 수 있습니다.