O Spanner permite fazer atualizações de esquema sem inatividade. É possível atualizar o esquema de um banco de dados de várias maneiras:
No console do Google Cloud
Envie um comando
ALTER TABLE
na página do Spanner Studio.Para acessar a página Spanner Studio, clique em Spanner Studio na página de visão geral do banco de dados ou da tabela.
Como usar a ferramenta de linha de comando
gcloud spanner
Envie um comando
ALTER TABLE
usando ogcloud spanner databases ddl update
kubectl.com as bibliotecas de cliente
Como usar a API REST
projects.instances.databases.updateDdl
Como usar a API RPC
UpdateDatabaseDdl
Atualizações de esquema compatíveis
O Spanner é compatível com as seguintes atualizações de esquema de um banco de dados atual:
- Adicione ou exclua um esquema nomeado.
- criar uma nova tabela; As colunas em novas tabelas podem ser
NOT NULL
. - Excluir uma tabela, se nenhuma outra estiver intercalada nela e ela não tiver índices secundários.
- Crie ou exclua uma tabela com uma chave estrangeira.
- Adicionar ou remover uma chave externa de uma tabela atual
- Adicionar uma coluna sem chave a qualquer tabela. As novas colunas sem chave não podem ser
NOT NULL
. - Solte uma coluna sem chave de qualquer tabela, a menos que seja usada por um índice secundário, uma chave externa, uma coluna armazenada ou uma restrição de verificação.
- Adicione
NOT NULL
a uma coluna sem chave, excluindo colunasARRAY
. - Remova
NOT NULL
de uma coluna sem chave. - Alterar uma coluna
STRING
para uma colunaBYTES
ou uma colunaBYTES
para uma colunaSTRING
. - Alterar uma coluna
PROTO
para uma colunaBYTES
ou uma colunaBYTES
para uma colunaPROTO
. - Mude o tipo de mensagem proto de uma coluna
PROTO
. - Adicione novos valores a uma definição
ENUM
e renomeie os valores existentes usandoALTER PROTO BUNDLE
. - Altere as mensagens definidas em um
PROTO BUNDLE
de maneira arbitrária, desde que os campos modificados dessas mensagens não sejam usados como chaves em nenhuma tabela e que os dados atuais satisfaçam as novas restrições. - Aumentar ou diminuir o limite de comprimento para um tipo
STRING
ouBYTES
(incluindo paraMAX
), a menos que seja uma coluna de chave primária herdada por uma ou mais tabelas filho. - Aumente ou diminua o limite de comprimento de uma coluna
ARRAY<STRING>
,ARRAY<BYTES>
ouARRAY<PROTO>
para o máximo permitido. - Ativar ou desativar carimbos de data/hora de confirmação em colunas de valor e chave principal.
- Adicione ou remova um índice secundário.
- Adicionar ou remover uma restrição de verificação de uma tabela existente
- Adicionar ou remover uma coluna gerada armazenada de uma tabela existente
- Crie um novo pacote de estatísticas do otimizador.
- Crie e gerencie visualizações.
- Crie e gerencie sequências.
- Criar funções de banco de dados e conceder privilégios.
- Defina, altere ou elimine o valor padrão de uma coluna.
- Mude as opções do banco de dados (
default_leader
ouversion_retention_period
, por exemplo). - Crie e gerencie fluxos de alterações.
- Crie e gerencie modelos de ML.
Atualizações de esquema sem suporte
O Spanner não é compatível com as seguintes atualizações de esquema de um banco de dados existente:
- Se houver um campo
PROTO
do tipoENUM
que seja referenciado por uma chave de tabela ou índice, não será possível remover valoresENUM
dos tipos enum de proto. Remoção de valoresENUM
dos tipos enumerados usados porENUM<>
colunas são aceitas, inclusive quando elas são usadas como chaves.
Desempenho de atualização do esquema
As atualizações de esquema no Spanner não exigem tempo de inatividade. Quando você emite uma em lote de instruções DDL em um banco de dados do Spanner, é possível continuar gravando e leitura do banco de dados sem interrupção enquanto o Spanner é aplicado a atualização como operação de longa duração.
O tempo necessário para executar uma instrução de DDL depende de a atualização exigir a validação dos dados existentes ou o preenchimento de dados. Por exemplo:
se você adicionar a anotação NOT NULL
a uma coluna existente, o Spanner precisará
ler todos os valores na coluna para se certificar de que ela não contenha
valores NULL
. Essa etapa poderá levar muito tempo se houver muitos dados para validar. Outro exemplo é se você estiver adicionando um índice a um banco de dados:
O Spanner preenche o índice usando dados atuais, e esse processo pode
levar muito tempo, dependendo de como a definição do índice e do tamanho
tabela base correspondente. No entanto, se você adicionar uma nova coluna a uma tabela, não haverá dados existentes para validar, então o Spanner poderá fazer a atualização em minutos.
Em resumo, as atualizações de esquema que não exigem que o Spanner valide dados existentes podem acontecer em minutos. As atualizações de esquema que necessitam de validação podem demorar mais, dependendo da quantidade de dados existentes que precisam ser validados. Porém, a validação de dados acontece em segundo plano sem afetar o tráfego de produção. As atualizações de esquema que requerem validação de dados são discutidas com mais detalhes na próxima seção.
Atualizações de esquema validadas em relação às definições de visualização
Quando você faz uma atualização de esquema, o Spanner valida que ela não vai invalidar as consultas usadas para definir as visualizações atuais. Se a validação for bem-sucedida, a atualização do esquema será bem-sucedida. Caso contrário, a atualização do esquema falhará. Consulte Práticas recomendadas ao criar visualizações para detalhes.
Atualizações de esquema que exigem validação de dados
É possível fazer atualizações de esquema que exigem a validação de que os dados existentes atendem às novas restrições. Quando uma atualização de esquema exige validação de dados, o Spanner não permite atualizações conflitantes do esquema nas entidades de esquema afetadas e valida os dados em segundo plano. Se a validação for bem-sucedida, a atualização do esquema será bem-sucedida. Se a validação não for bem-sucedida, a atualização do esquema não será bem-sucedida. As operações de validação são executadas como operações de longa duração. Verifique o status dessas operações para determinar se elas foram bem-sucedidas ou falharam.
Por exemplo, suponha que você tenha definido o arquivo music.proto
a seguir com um
tipo enumerado RecordLabel
e uma mensagem de protocolo Songwriter
:
enum RecordLabel {
COOL_MUSIC_INC = 0;
PACIFIC_ENTERTAINMENT = 1;
XYZ_RECORDS = 2;
}
message Songwriter {
required string nationality = 1;
optional int64 year_of_birth = 2;
}
Para adicionar uma tabela Songwriters
no esquema:
GoogleSQL
CREATE PROTO BUNDLE (
googlesql.example.music.Songwriter,
googlesql.example.music.RecordLabel,
);
CREATE TABLE Songwriters (
Id INT64 NOT NULL,
FirstName STRING(1024),
LastName STRING(1024),
Nickname STRING(MAX),
OpaqueData BYTES(MAX),
SongWriter googlesql.example.music.Songwriter
) PRIMARY KEY (Id);
CREATE TABLE Albums (
SongwriterId INT64 NOT NULL,
AlbumId INT64 NOT NULL,
AlbumTitle STRING(MAX),
Label INT32
) PRIMARY KEY (SongwriterId, AlbumId);
As seguintes atualizações de esquema são permitidas, mas exigem validação e podem levar mais tempo para serem concluídas, dependendo da quantidade de dados existentes:
Adição da anotação
NOT NULL
a uma coluna sem chave Por exemplo:ALTER TABLE Songwriters ALTER COLUMN Nickname STRING(MAX) NOT NULL;
Redução do comprimento de uma coluna Por exemplo:
ALTER TABLE Songwriters ALTER COLUMN FirstName STRING(10);
Alteração de
BYTES
paraSTRING
Exemplo:ALTER TABLE Songwriters ALTER COLUMN OpaqueData STRING(MAX);
Alteração de
INT64/INT32
paraENUM
Exemplo:ALTER TABLE Albums ALTER COLUMN Label googlesql.example.music.RecordLabel;
Removemos os valores atuais da definição de tipo enumerado
RecordLabel
.Ativação de carimbos de data/hora de confirmação em uma coluna
TIMESTAMP
atual Exemplo:ALTER TABLE Albums ALTER COLUMN LastUpdateTime SET OPTIONS (allow_commit_timestamp = true);
Como adicionar uma restrição de verificação a uma tabela atual.
Como adicionar uma coluna armazenada gerada a uma tabela atual.
Criação de uma nova tabela com uma chave estrangeira.
Como adicionar uma chave externa a uma tabela existente.
Essas atualizações de esquema falharão se os dados subjacentes não satisfizerem as novas restrições. Por exemplo, a instrução ALTER TABLE Songwriters ALTER COLUMN Nickname
STRING(MAX) NOT NULL
falhará se algum valor em Nickname
coluna é NULL
, porque os dados existentes não atendem ao NOT NULL
da nova definição.
A validação de dados pode demorar de vários minutos a muitas horas. O tempo para completar a validação de dados depende:
- O tamanho do conjunto de dados
- A capacidade de computação da instância
- da carga na instância.
Algumas atualizações de esquema podem alterar o comportamento das solicitações no banco de dados antes que a atualização do esquema seja concluída. Por exemplo, se você estiver adicionando NOT NULL
a uma
o Spanner quase imediatamente começa a rejeitar gravações para novos
solicitações que usam NULL
para a coluna. Se a nova atualização de esquema acabar falhando na validação de dados, haverá um período de tempo em que as gravações serão bloqueadas, mesmo que elas tenham sido aceitas pelo esquema antigo.
É possível cancelar uma operação de validação de dados de longa duração usando o método projects.instances.databases.operations.cancel
ou gcloud spanner operations
.
Ordem de execução de instruções em lotes
Se você usar a Google Cloud CLI, a API REST ou a API RPC, emita um lote
de um ou mais comandos CREATE
, ALTER
ou DROP
.
O Spanner aplica instruções do mesmo lote em ordem, parando no primeiro erro. Se a aplicação de uma instrução resultar em um erro, essa instrução será revertida. Os resultados de quaisquer instruções aplicadas anteriormente no lote não são revertidos.
O Spanner pode combinar e reordenar instruções de diferentes lotes,
misturando potencialmente instruções de diferentes lotes para a mesma alteração atômica aplicada ao banco de dados. Dentro de cada alteração atômica, as instruções de diferentes lotes ocorrem em uma ordem arbitrária. Por exemplo, se um lote de instruções
contiver ALTER TABLE MyTable ALTER COLUMN MyColumn STRING(50)
e outro
lote de instruções contiver ALTER TABLE MyTable ALTER COLUMN MyColumn
STRING(20)
, o Spanner vai deixar essa coluna em um desses dois estados,
mas não vai especificar em qual.
Versões de esquema criadas durante atualizações de esquema
O Spanner usa o controle de versão do esquema para que não haja tempo de inatividade durante uma atualização de esquema para um banco de dados grande. O Spanner mantém a versão antiga do esquema para oferecer suporte a leituras enquanto a atualização do esquema é processada. O Spanner cria uma ou mais novas versões do esquema para processar a atualização do esquema. Cada versão contém o resultado de uma coleção de instruções em uma única alteração atômica.
As versões do esquema não correspondem necessariamente um para um com lotes de instruções de DDL ou instruções de DDL individuais. Algumas instruções DDL individuais, como a criação de índices para tabelas base ou instruções existentes que exigem validação de dados, resultam em várias versões de esquema. Em outros casos, várias instruções DDL podem ser agrupadas em uma única versão. As versões antigas do esquema podem consomem muitos recursos de servidor e armazenamento, que são retidos eles expiram (não são mais necessários para atender a leituras de versões anteriores dos dados).
A tabela a seguir mostra quanto tempo o Spanner leva para atualizar um esquema.
Operação de esquema | Duração estimada |
---|---|
CREATE TABLE |
Minutos |
CREATE INDEX |
Minutos para horas, se a tabela base for criada antes do índice. Minutos, se a instrução for executada ao mesmo tempo que a instrução |
DROP TABLE |
Minutos |
DROP INDEX |
Minutos |
ALTER TABLE ... ADD COLUMN |
Minutos |
ALTER TABLE ... ALTER COLUMN |
Minutos para horas, se a validação de segundo plano for obrigatória. Minutos, se a validação de segundo plano não for obrigatória. |
ALTER TABLE ... DROP COLUMN |
Minutos |
ANALYZE |
Minutos a horas, dependendo do tamanho do banco de dados. |
Mudanças de tipo de dados e fluxos de mudanças
Se você mudar o tipo de dados de uma coluna que um fluxo de
mudanças monitora, o campo column_types
dos registros de fluxo de mudanças
relevantes refletirá o novo tipo, assim como os dados JSON old_values
no
campo mods
dos registros.
O new_values
do campo mods
de um registro de fluxo de mudanças sempre corresponde
o tipo atual de uma coluna. Mudar o tipo de dados de uma coluna monitorada não
afeta os registros de fluxo de mudanças anteriores a essa mudança.
No caso específico de uma mudança de BYTES
para STRING
,
o Spanner valida os valores antigos
da coluna como parte da atualização do esquema.
Como resultado, o Spanner decodificou com segurança os valores antigos
do tipo BYTES
em strings no momento em que gravou qualquer registro
de fluxo de mudança subsequente.
Práticas recomendadas para atualizações de esquema
As seções a seguir descrevem as práticas recomendadas para a atualização de esquemas.
Procedimentos antes da emissão da atualização do esquema
Antes de emitir uma atualização de esquema, realize as seguintes ações:
Verifique se todos os dados existentes no banco de dados que você está alterando atendem às restrições que a atualização do esquema está impondo. Como o sucesso de alguns tipos de atualizações de esquema depende dos dados no banco de dados e não apenas do esquema atual, uma atualização de esquema bem-sucedida de um banco de dados de teste não garante uma atualização de esquema bem-sucedida de um banco de dados de produção. Veja alguns exemplos comuns:
- Caso esteja adicionando uma anotação
NOT NULL
a uma coluna existente, verifique se a coluna não contém valoresNULL
. - Se você estiver encurtando o comprimento permitido de uma coluna
STRING
ouBYTES
, verificar se todos os valores existentes nessa coluna atendem ao comprimento restrição.
- Caso esteja adicionando uma anotação
Se você estiver gravando em uma coluna, tabela ou índice que estiver passando por uma atualização de esquema, verifique se os valores que estão sendo gravados atendem às novas restrições.
Se você estiver excluindo uma coluna, uma tabela ou um índice, confira se eles ainda não estão sendo usados para gravação ou leitura.
Limitar a frequência das atualizações de esquema
Se você executar muitas atualizações de esquema em um curto período, o Spanner
pode throttle
o
o processamento de atualizações de esquema
na fila. Isso acontece porque o Spanner limita o
volume de espaço para armazenar versões de esquema. A atualização do esquema poderá ser limitada se houver muitas versões antigas do esquema no período de armazenamento. A taxa máxima de alterações do esquema depende de muitos fatores, sendo um deles o número total de colunas no banco de dados. Por exemplo, um
banco de dados com 2.000 colunas (aproximadamente 2.000 linhas em
INFORMATION_SCHEMA.COLUMNS
)
pode realizar no máximo 1.500 alterações de esquema (menos se a mudança de esquema
exigir várias versões) no período de retenção. Para ver o estado
de atualizações de esquema em andamento, use o
comando gcloud spanner operations list
e filtre por operações do tipo DATABASE_UPDATE_DDL
. Para cancelar uma
atualização contínua do esquema, use o
comando gcloud spanner operations cancel
e especifique o ID da operação.
A maneira como as instruções DDL são agrupadas e a ordem em cada lote pode afetar o número de versões de esquema resultantes. Para maximizar o número de atualizações de esquema que podem ser realizadas em qualquer período, use lotes que minimizem o número de versões de esquema. Algumas regras gerais são descritas em grandes atualizações.
Conforme descrito em versões de esquema, algumas instruções de DDL criarão várias versões de esquema, e essas são importantes ao considerar a criação de lotes e a ordem em cada lote. Há dois tipos principais de instruções que podem criar várias versões de esquema:
- Instruções que podem precisar preencher dados de índice, como
CREATE INDEX
- Instruções que podem precisar validar dados existentes, como adicionar
NOT NULL
No entanto, esses tipos de instruções nem sempre criam várias versões de esquema. O Spanner tentará detectar quando esses tipos de instruções podem ser
otimizados para evitar o uso de várias versões de esquema, o que depende do agrupamento.
Por exemplo, uma instrução CREATE INDEX
que ocorre no mesmo lote que uma
Instrução CREATE TABLE
para a tabela base do índice, sem nenhuma intervenção
para outras tabelas, pode evitar a necessidade de preencher os dados do índice
porque o Spanner pode garantir que a tabela base esteja vazia no momento
o índice é criado. A seção de grandes atualizações descreve como usar essa propriedade para criar muitos índices com eficiência.
Se não for possível agrupar as instruções DDL em lotes para evitar a criação de muitas versões de esquema, limite o número de atualizações de esquema a um único esquema de banco de dados no período de armazenamento. Aumente o tempo no qual você faz atualizações de esquema para permitir que o Spanner remova versões anteriores do esquema antes que novas versões sejam criadas.
- Para alguns sistemas de gerenciamento de banco de dados relacional, há pacotes de software que fazem uma longa série de atualizações de esquema de atualização e downgrade do banco de dados em cada implantação de produção. Esses tipos de processos não são recomendados para o Spanner.
- O Spanner é otimizado para usar chaves primárias para particionar dados de soluções de multilocação. As soluções de multilocação que usam tabelas separadas para cada cliente podem resultar em um grande backlog de operações de atualização de esquema que levam muito tempo para conclusão.
- As atualizações de esquema que exigem validação ou preenchimento de índice usam mais recursos do servidor, porque cada instrução cria várias versões do esquema internamente.
Opções para grandes atualizações de esquema
A melhor maneira de criar uma tabela e um grande número de índices nela é criar todos eles ao mesmo tempo, para que apenas uma versão de esquema seja criada. A prática recomendada é criar os índices imediatamente após a tabela na lista de instruções DDL. É possível criar a tabela e seus índices durante a criação do banco de dados ou em um único lote grande de instruções. Se você precisar criar muitas tabelas, cada uma com muitos índices, será possível incluir todas as instruções em um único lote. É possível incluir milhares de instruções em um único lote quando todas elas puderem ser executadas em conjunto usando uma única versão de esquema.
Quando uma instrução exige o preenchimento de dados de índice ou a realização de uma validação de dados,
não é possível executá-la em uma única versão de esquema. Isso acontece com instruções CREATE INDEX
quando a tabela base do índice já existe, seja porque foi criada em um lote anterior de instruções DDL ou porque havia uma instrução no lote entre o CREATE TABLE
e CREATE INDEX
que
exigiam várias versões de esquema. O Spanner exige que não haja
mais de 10 instruções em um único lote. A criação de índices que requer preenchimento, usa várias versões de esquema por índice e, por isso, é uma boa regra criar todos os três novos índices que exigem preenchimento por dia, independentemente de como elas são agrupadas, a menos que
esse lote possa evitar o preenchimento.
Por exemplo, este lote de instruções usará uma única versão de esquema:
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);
Por outro lado, esse lote usará muitas versões do esquema, porque UnrelatedIndex
requer preenchimento (já que sua tabela base precisa ter sido existente) e isso força todos os índices a seguir a exigir também o preenchimento (mesmo que eles estejam no mesmo lote que as tabelas de base):
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);
Seria melhor mover a criação de UnrelatedIndex
para o final do lote ou para um lote diferente, para minimizar as versões de esquema.
Aguardar a conclusão das solicitações da API
Ao fazer as solicitações projects.instances.databases.updateDdl
(API REST) ou UpdateDatabaseDdl
(API RPC), use projects.instances.databases.operations.get
(API REST) ou GetOperation
(API RPC), respectivamente, para aguardar a conclusão de cada solicitação antes de iniciar uma nova solicitação. Aguardar a conclusão de cada solicitação permite que seu aplicativo acompanhe o andamento das atualizações de esquema. Ele também mantém o backlog de atualizações de esquema pendentes em um tamanho gerenciável.
Carregamento em massa
Se você estiver carregando nas tabelas dados em massa depois de criados, geralmente é mais eficiente criar índices após os dados serem carregados. Caso esteja adicionando diversos índices, pode ser mais eficiente criar o banco de dados com todas as tabelas e índices no esquema inicial, como descrito nas opções para grandes atualizações.