⌘K

10 – SQL no PostgreSQL: Como usar o ALTER TABLE em Produção sem Causar Downtime

Last updated

Se existe um comando SQL capaz de acelerar os batimentos cardíacos de um profissional de DevOps, de Engenharia de Dados ou de um DBA, esse comando é o ALTER TABLE executado direto no ambiente de produção.

Conforme as aplicações evoluem, novas funcionalidades exigem que a estrutura do banco de dados mude. Precisamos adicionar colunas, alterar tipos de dados ou incluir restrições (constraints). O problema é que, em bancos de dados vivos (live environments), uma alteração mal planejada pode bloquear a tabela inteira, travar as requisições da aplicação e causar uma queda generalizada (downtime).

Neste post, vamos aprender a utilizar o comando ALTER TABLE de forma estratégica e segura no PostgreSQL, entendendo os impactos nos bastidores do banco.

O Perigo Invisível: Locks de Tabela

Quando você roda um ALTER TABLE, o PostgreSQL precisa garantir que nenhuma outra transação altere ou leia os dados enquanto a estrutura está sendo modificada. Para isso, ele aplica um bloqueio exclusivo chamado Access Exclusive Lock.

Enquanto esse lock estiver ativo, qualquer comando SELECT, INSERT, UPDATE ou DELETE vindo da sua aplicação ficará preso em uma fila de espera. Se a alteração demorar segundos ou minutos para rodar, sua aplicação vai esgotar o pool de conexões e cair.

Estratégias Seguras para Alterações Comuns

Vamos ver como realizar as alterações mais comuns do dia a dia minimizando ou zerando o tempo de bloqueio.

1. Adicionando uma Nova Coluna (O jeito certo)

Antigamente, adicionar uma coluna com um valor padrão (DEFAULT) forçava o Postgres a reescrever a tabela inteira no disco para preencher esse valor em cada linha existente. A partir do PostgreSQL 11, isso mudou: adicionar uma coluna com valor padrão é uma operação puramente de catálogo (instantânea!).

No entanto, o perigo está em colunas com restrição NOT NULL sem um valor padrão em tabelas populadas. O ideal é quebrar o processo em etapas:

-- Passo 1: Adicionar a coluna permitindo valores nulos (instantâneo)
ALTER TABLE servidores ADD COLUMN regiao_cloud VARCHAR(50);

-- Passo 2: Alimentar os dados gradativamente ou via script em lotes
-- ... (UPDATE em background para preencher as linhas antigas)

-- Passo 3: Aplicar a restrição NOT NULL após garantir que tudo está preenchido
ALTER TABLE servidores ALTER COLUMN regiao_cloud SET NOT NULL;

2. Adicionando Chaves Estrangeiras (FOREIGN KEY) de forma segura

Criar uma chave estrangeira comum valida todas as linhas existentes imediatamente, bloqueando a tabela. Para evitar isso, use o recurso NOT VALID:

-- Passo 1: Cria a relação, mas não valida os dados antigos (o lock é liberado rápido)
ALTER TABLE servidores 
ADD CONSTRAINT fk_servidores_clusters 
FOREIGN KEY (id_cluster) REFERENCES clusters(id) NOT VALID;

-- Passo 2: Valida os dados existentes em background sem bloquear escritas ou leituras
ALTER TABLE servidores VALIDATE CONSTRAINT fk_servidores_clusters;

3. Alterando o Tipo de Dado de uma Coluna

Mudar uma coluna de INT para BIGINT porque os IDs da sua aplicação explodiram é uma operação que exige reescrever a tabela inteira, causando um lock massivo.

Em ambientes de alta disponibilidade, a melhor estratégia DevOps é:

  1. Criar uma coluna nova com o tipo correto (id_novo BIGINT).
  2. Criar uma Trigger no banco para espelhar os novos inserts/updates da coluna antiga para a nova.
  3. Rodar um script de migração em background para copiar os dados antigos.
  4. Alterar a aplicação para apontar para a nova coluna e dropar a antiga.

Defesa em Profundidade: Configurando Timeouts

Nunca rode um ALTER TABLE em produção sem definir um limite de tempo para a aquisição do lock. Se o banco estiver muito ocupado, é melhor que a sua migração falhe por timeout do que derrube a aplicação por ficar esperando o lock infinitamente.

Antes de rodar a migração em seu script de CI/CD ou CLI, configure o lock_timeout:

-- Define que se o comando não conseguir o lock em até 2 segundos, ele aborta
SET lock_timeout = '2s';

ALTER TABLE servidores ADD COLUMN tags JSONB;

Conclusão

Modificar estruturas em produção faz parte da evolução natural de qualquer ecossistema de tecnologia. O segredo para não causar incidentes não é evitar o ALTER TABLE, mas sim entender o tipo de lock que ele gera e desenhar estratégias para que a alteração aconteça em frações de segundo ou de forma assíncrona em background.

Com este artigo, encerramos nossa jornada pelos comandos fundamentais de manipulação e gerenciamento estrutural de dados no PostgreSQL!

No próximo post, mudaremos o foco para um tema crucial na governança e segurança de dados: DCL (Data Control Language). Vamos aprender como gerenciar usuários, criar papéis funcionais (Roles) e aplicar a política de privilégios mínimos usando os comandos GRANT e REVOKE. Até lá!

Você já passou pelo sufoco de rodar um ALTER TABLE que travou o banco da empresa? Como foi a estratégia para recuperar o ambiente? Deixe seu relato aqui nos comentários!

Still stuck? How can we help? Get Help