Matheus Castiglioni

Migrando Banco de Dados Mantendo a Compatibilidade

Muitas vezes acabamos precisando aplicar migrações em nossos banco de dados, seja, para aplicar alguma alteração de schema ou alterações de dados. As alterações de schema podem ser:

Mas, como podemos fazer para que tais migrações não impactem o passado (backward) e nem o futuro (afterward)? Ou seja, versões antigas do sistema devem funcionar após a migração e versões novas do sistema devem funcionar antes da migração.

Uma pergunta que você pode estar se fazendo é:

Mas, porque preciso me preocupar com tal nível de compatibilidade?

Ter esse nível de compatibilidade possibita realizar migrações com zero tempo de inatividade (zero downtime).

A parte mais importante para atingir tal nível de complexidade é pegar uma única declaração de migração e dividí-la em pequenos e micro passos (baby steps), formando uma estratégia de migração, por exemplo:

alter table customers rename column name to first_name

Esse comando acima é perigoso, isso porque ele não possuí um bom nível de compatibilidade, ou seja:

  1. A versão antiga do sistema não vai funcionar quando aplicar a migração, pois, não irá existir a coluna name para ser lida.
  2. A nova versão do sistema não vai funcionar sem aplicar a migração, pois, não irá existir a coluna first_name para ser lida.

Dessa forma, podemos concluir que seu nível de compatibilidade (seja para para trás ou à frente) não é muito boa. Necessitando de uma sincronização de deploy e migração (além de haver um tempo de inatividade do sistema).

Uma possível estratégia de migração poderia ser:

alter table customers add column first_name varchar(120)
update customers set first_name = name where id between 1 and 100
update customers set first_name = name where id between 101 and 200
update customers set first_name = name where id between 201 and 300
alter table customers delete column name

Repare que a migração foi feita em várias partes, dessa forma:

  1. A versão antiga do sistema ainda funciona, pois, apenas uma nova coluna foi adicionada.
  2. A nova versão do sistema funciona, pois, a coluna nova já foi criada

Estratégias de migração

Vamos definir formalmente algumas estratégias de migração e seus casos de usos.

Evite locks utilizando particionamento

Particionamento no contexto de banco de dados é o processo de dividir uma grande base de dados em vários pedaços menores. Sendo assim, podemos pegar esse conceito de dividir algo maior em várias pequenas partes no contexto de migrações.

Nós, não podemos controlar a quantidade de tempo que um comando alter table vai levar para ser executado. Por mais que a maioria dos banco de dados atuais não irá conduzir tal comando para um lock, ainda vale, termos cuidados em tal necessidade.

Além do comando acima, também temos o update, cujo, seu tempo de execução é proporcional à quantidade de informação para ser atualizada e o número de linhas nas tabelas. Quanto mais linhas e informações, maior será o tempo de execução do mesmo.

Para minimizar o tempo de execução nós podemos dividir um único comando em vários menores, ou seja, podemos mudar disso:

update account set amount = amount * 10

Para isso:

update account set amount = amount * 10 where number between 1 and 100000
update account set amount = amount * 10 where number between 100001 and 200000
update account set amount = amount * 10 where number between 200001 and 300000

Adicionando uma coluna

Adicionar uma nova coluna é uma das migrações mais simples que nós podemos aplicar para nosso schema do banco de dados, podemos seguir tal estratégia:

  1. Adicionar uma nova coluna com alter table nome_da_tabela add column nome_da_coluna tipo (cuidado para não adicionar alguma restrição como not null).
  2. Código escreve para a nova coluna.
  3. Código lê a nova coluna, mas, quando a mesma não existir podemos utilizar um valor padrão ou derivar uma informação alternativa baseado em alguma já existente.
  4. Aplicar um update utilizando particionamento para a nova coluna estar consistente.
  5. Código lê e escreve para a nova coluna.

Renomeando uma coluna

Renomear uma coluna exige alguns passos a mais para ser bem sucedida, sendo:

  1. Adicionar uma nova coluna com alter table nome_da_tabela add column nome_da_coluna tipo (cuidado para não adicionar alguma restrição como not null).
  2. Código lê da coluna antiga e escreve para as duas (antiga e nova).
  3. Copia a informação para a nova coluna utilizando particionamento.
  4. Código lê da informação nova e continua escrevendo para as duas (antiga e nova).
  5. Código lê e escreve para a nova coluna.
  6. Deleta a nova coluna depois de um tempo.

Mudar o tipo ou formato de uma coluna

A estratégia e passos não são muito diferentes quando é necessário renomear uma coluna, sendo:

  1. Adicionar uma nova coluna com alter table nome_da_tabela add column nome_da_coluna tipo (cuidado para não adicionar alguma restrição como not null).
  2. Código lê da coluna antiga e escreve para as duas (antiga e nova).
  3. Copia a informação para a nova coluna utilizando particionamento.
  4. Código lê da informação nova e continua escrevendo para as duas (antiga e nova).
  5. Código lê e escreve para a nova coluna.
  6. Deleta a nova coluna depois de um tempo.

Deletar uma coluna

As vezes acabamos não precisando mais de uma coluna e sendo assim surge a necessidade de deletá-la, para isso podemos seguir tais passos:

  1. Nunca delete a coluna no banco de dados quando estiver liberando uma nova versão do sistema.
  2. Pare de ler da coluna, mas, continue escrevendo.
  3. Pare de escrever na coluna.
  4. Delete a coluna depois de um tempo.

Cuidado com o comando de delete, isso porque trata-se de um comando destrutivo que muitas vezes não poderá ser desfeito.

Conclusão

Nesse post vimos estratégias para aplicar migrações em banco de dados de uma forma mais tranquila, da qual possuí um bom nível de compatibilidade seja com o passado ou futuro.

Abraços, até a próxima.

Matheus Castiglioni

Matheus Castiglioni

Apaixonado pelo mundo dos códigos e um eterno estudante, gosto de aprender e saber um pouco de tudo, aquela curiosidade de saber como tudo funciona, tento compartilhar o máximo de conhecimentos adquiridos e ajudar todos aqueles que sou capaz.

comments powered by Disqus