5 pontos por GN⁺ 2024-04-29 | Ainda não há comentários. | Compartilhar no WhatsApp

Here is a summary of the common database schema change mistakes, translated and structured in Korean:

Erros relacionados à concorrência

  • Falha ao adquirir lock
  • Atualizar linhas demais de uma só vez
  • Manter a transação aberta por muito tempo após adquirir um lock exclusivo

Erros relacionados à correção das etapas - questões lógicas

  • Desvio de esquema inesperado
  • Incompatibilidade entre esquema e código da aplicação
  • Dados inesperados

Outros erros

  • Atingir statement_timeout
  • Usar chave primária inteira de 4 bytes em tabelas que podem crescer
  • Ignorar o funcionamento do VACUUM e o risco de bloat

Caso 1. Incompatibilidade de esquema

  • Funcionou em desenvolvimento/teste, mas falhou em QA/Staging/Produção
  • É preciso identificar a causa e resolver melhorando o fluxo de trabalho

Caso 2. Uso indevido de IF [NOT] EXISTS

  • Não tente ignorar erros de incompatibilidade de esquema com IF NOT EXISTS
  • É preciso identificar e resolver a causa raiz do problema

Caso 3. Atingir statement_timeout

  • Teste todas as mudanças com grandes volumes de dados para descobrir isso com antecedência

Caso 4. Alterações massivas sem limite

  • Alterar linhas demais em uma única transação afeta outras transações
  • Se o checkpointer não estiver ajustado, pode haver geração excessiva de dados WAL
  • Pode ocorrer degradação geral de desempenho por saturação de escrita em disco
  • Podem surgir problemas de VACUUM/bloat
  • Divida em lotes e faça a gestão do VACUUM

Caso 5. Espera dentro da transação após adquirir lock exclusivo

  • Se você fizer outras operações entre BEGIN/ALTER TABLE/COMMIT, o lock ficará retido por mais tempo
  • Depois de adquirir um lock exclusivo, a transação deve ser concluída o mais rápido possível

Caso 6. Transação com DDL + DML em grande volume

  • O lock adquirido na etapa de DDL permanece por muito tempo até a etapa de DML
  • Separe DDL e DML em transações/etapas de migração distintas

Caso 7. Bloqueio de outras sessões por espera na aquisição de lock exclusivo

  • Quando o autovacuum está no modo de prevenção de wraparound, ele não faz yield para DDL
  • Até mesmo SELECT fica bloqueado enquanto se espera pela aquisição do lock
  • Defina lock_timeout baixo e crie lógica de retry

Caso 8. Cuidados ao criar FK

  • Ao criar FK em tabelas grandes, a varredura da tabela referenciada consome tempo
  • Defina a FK com a opção not valid e valide em uma transação separada

Caso 9. Cuidados ao remover FK

  • Como é necessário lock nas duas tabelas, é preciso lógica de retry com lock_timeout

Caso 10. Cuidados ao adicionar restrição CHECK

  • Ocorre varredura da tabela inteira, então use uma abordagem em 2 etapas semelhante à de FK

Caso 11. Cuidados ao adicionar NOT NULL

  • Em versões anteriores ao Postgres 11, adicionar NOT NULL a uma nova coluna causa varredura da tabela
  • A partir do Postgres 11, isso pode ser resolvido com adição de coluna NOT NULL DEFAULT
  • A partir do Postgres 12, é possível definir NOT NULL adicionando uma restrição CHECK

Caso 12. Cuidados ao alterar o tipo de dado de uma coluna

  • Pode ocorrer regravação da tabela inteira
  • É necessária uma abordagem de adicionar nova coluna e copiar os dados com trigger

Caso 13. Cuidados ao usar CREATE INDEX

  • Em OLTP, deve-se usar CREATE INDEX CONCURRENTLY
  • Se a criação de índice único falhar, é preciso limpar o índice inválido

Caso 14. Cuidados ao usar DROP INDEX

  • Como há problema de aquisição de lock, use DROP INDEX CONCURRENLTY

Caso 15. Cuidados ao renomear objetos

  • É preciso ajustar a ordem de deploy para evitar incompatibilidade entre código da aplicação e esquema do banco

Caso 16. Adicionar coluna com valor DEFAULT

  • Antes do PG 11, ocorria regravação da tabela inteira
  • A partir do PG 11, ficou mais rápido adicionar coluna com valor DEFAULT

Caso 17. Limpeza de resíduos quando CREATE INDEX CONCURRENTLY falha

  • Se falhar, fica um índice inválido, então é preciso limpá-lo antes de tentar novamente

Caso 18. Uso de chave primária inteira de 4 bytes em tabelas grandes

  • Deve-se usar int8. A maioria dos frameworks já usa int8.

Recomendações

  • Testar com volumes de dados realistas
  • Verificar o tempo de retenção de locks exclusivos
  • Melhorar a automação de deploy
  • Aprender com outras pessoas e compartilhar conhecimento

Opinião do GN⁺

Este texto organiza muito bem vários erros e cuidados que podem surgir em alterações reais de esquema de banco de dados. Em especial, há muitas menções a problemas relacionados a locks exclusivos, algo que pode causar impactos ainda mais sérios em bancos de dados de grande porte.

Também explica de forma concreta os cuidados ao lidar com FK, NOT NULL, índices e outros pontos que os desenvolvedores costumam ignorar com facilidade. Entender e aproveitar as melhorias por versão do Postgres também parece bastante útil.

Acima de tudo, concordo com a ideia de que testar com volumes de dados realistas e melhorar a automação de deploy é o ponto-chave para minimizar os riscos de alterações de esquema. Para testes e automação de deploy, também pode ser interessante usar ferramentas como o Database Lab Engine.

Seria ótimo ver mais posts técnicos compartilhando dicas úteis como estas. Quanto mais esse tipo de informação se espalhar, mais isso certamente ajudará a elevar a capacidade dos desenvolvedores que trabalham com bancos de dados.

Ainda não há comentários.

Ainda não há comentários.