9 min leitura • Guide 753 of 877
Melhores Práticas de Migração de Banco de Dados
As migrações de banco de dados requerem planejamento e execução cuidadosos. O GitScrum ajuda a rastrear tarefas de migração e coordenar implantações com segurança.
Planejamento de Migração
Estrutura de Tarefa de Migração
HISTÓRIA DE MIGRAÇÃO DE BANCO DE DADOS:
┌─────────────────────────────────────────────────────────────┐
│ DB-123: Adicionar Tabela user_preferences │
├─────────────────────────────────────────────────────────────┤
│ │
│ PROPÓSITO: │
│ Armazenar preferências de notificação e exibição do usuário│
│ Necessário para: USER-456 (funcionalidade de configurações)│
│ │
│ ═══════════════════════════════════════════════════════════ │
│ │
│ SCRIPT DE MIGRAÇÃO: │
│ ┌─────────────────────────────────────────────────────────┐│
│ │ CREATE TABLE user_preferences ( ││
│ │ id BIGSERIAL PRIMARY KEY, ││
│ │ user_id BIGINT NOT NULL REFERENCES users(id), ││
│ │ preference_key VARCHAR(100) NOT NULL, ││
│ │ preference_value JSONB NOT NULL DEFAULT '{}', ││
│ │ created_at TIMESTAMP DEFAULT NOW(), ││
│ │ updated_at TIMESTAMP DEFAULT NOW(), ││
│ │ UNIQUE(user_id, preference_key) ││
│ │ ); ││
│ │ ││
│ │ CREATE INDEX idx_user_prefs_user ON ││
│ │ user_preferences(user_id); ││
│ └─────────────────────────────────────────────────────────┘│
│ │
│ SCRIPT DE ROLLBACK: │
│ ┌─────────────────────────────────────────────────────────┐│
│ │ DROP TABLE IF EXISTS user_preferences; ││
│ └─────────────────────────────────────────────────────────┘│
│ │
│ ═══════════════════════════════════════════════════════════ │
│ │
│ CHECKLIST: │
│ ☐ Script de migração revisado │
│ ☐ Script de rollback testado │
│ ☐ Executado com sucesso em staging │
│ ☐ Impacto de performance avaliado │
│ ☐ Sem bloqueios de tabela em tabelas grandes │
│ ☐ Janela de implantação agendada │
│ ☐ Monitoramento em vigor │
└─────────────────────────────────────────────────────────────┘
Avaliação de Risco
NÍVEIS DE RISCO DE MIGRAÇÃO:
┌─────────────────────────────────────────────────────────────┐
│ │
│ RISCO BAIXO (luz verde): │
│ • Adicionando nova tabela │
│ • Adicionando coluna nullable │
│ • Adicionando índice (se tabela pequena) │
│ → Pode executar a qualquer momento │
│ │
│ RISCO MÉDIO (cuidado): │
│ • Adicionando índice a tabela grande │
│ • Modificando tipo de coluna (compatível) │
│ • Adicionando NOT NULL com padrão │
│ → Execute durante baixo tráfego │
│ → Monitore performance │
│ │
│ RISCO ALTO (cautela extra): │
│ • Modificando tipo de coluna (incompatível) │
│ • Removendo coluna │
│ • Removendo tabela │
│ • Grandes migrações de dados │
│ → Janela de manutenção necessária │
│ ☐ Equipe em standby para problemas │
│ ☐ Plano detalhado de rollback │
│ │
│ RISCO CRÍTICO (preparação completa): │
│ • Mudanças de esquema em tabelas enormes (100M+ linhas) │
│ • Mudanças de chave estrangeira │
│ • Modificações de chave primária │
│ → Janela de manutenção estendida │
│ → Backup completo antes │
│ → Aprovação executiva │
│ → Sala de guerra durante execução │
└─────────────────────────────────────────────────────────────┘
Padrões de Migração Segura
Mudanças Compatíveis com Versões Anteriores
PADRÕES DE MIGRAÇÃO SEGURA:
┌─────────────────────────────────────────────────────────────┐
│ │
│ PADRÃO 1: EXPANDIR-CONTRAIR │
│ │
│ OBJETIVO: Renomear coluna "name" para "full_name" │
│ │
│ ❌ ARRISCADO (uma etapa): │
│ ALTER TABLE users RENAME name TO full_name; │
│ → Quebra código antigo imediatamente │
│ │
│ ✅ SEGURO (expandir-contrair): │
│ │
│ Etapa 1 (Expandir): Adicionar nova coluna │
│ ALTER TABLE users ADD COLUMN full_name VARCHAR(255); │
│ │
│ Etapa 2: Dual-write no código │
│ Escrever em ambos name e full_name │
│ │
│ Etapa 3: Backfill de dados │
│ UPDATE users SET full_name = name WHERE full_name IS NULL; │
│ │
│ Etapa 4: Alternar leituras │
│ Ler de full_name │
│ │
│ Etapa 5 (Contrair): Remover coluna antiga (release posterior)│
│ ALTER TABLE users DROP COLUMN name; │
│ │
│ Cada etapa é reversível e não-quebrável │
│ │
└─────────────────────────────────────────────────────────────┘
Adicionando Colunas NOT NULL
ADIÇÃO SEGURA DE COLUNA NOT NULL:
┌─────────────────────────────────────────────────────────────┐
│ │
│ OBJETIVO: Adicionar coluna obrigatória "status" aos usuários│
│ │
│ ❌ ARRISCADO: │
│ ALTER TABLE users ADD COLUMN status VARCHAR(20) NOT NULL; │
│ → Falha se tabela tem linhas existentes │
│ │
│ ✅ ABORDAGEM SEGURA: │
│ │
│ Etapa 1: Adicionar coluna nullable com padrão │
│ ALTER TABLE users ADD COLUMN status VARCHAR(20) │
│ DEFAULT 'active'; │
│ │
│ Etapa 2: Backfill de linhas existentes (em lotes) │
│ UPDATE users SET status = 'active' │
│ WHERE status IS NULL │
│ AND id BETWEEN 1 AND 10000; │
│ │
│ Etapa 3: Adicionar restrição NOT NULL │
│ ALTER TABLE users ALTER COLUMN status SET NOT NULL; │
│ │
│ Etapa 4: Opcional - remover padrão │
│ ALTER TABLE users ALTER COLUMN status DROP DEFAULT; │
│ │
│ POR QUE LOTES: │
│ UPDATE grande bloqueia tabela │
│ Lotes de 10k-50k linhas minimizam tempo de bloqueio │
│ Execute durante períodos de baixo tráfego │
└─────────────────────────────────────────────────────────────┘
Migrações de Tabelas Grandes
Operações em Lotes
LIDANDO COM TABELAS GRANDES:
┌─────────────────────────────────────────────────────────────┐
│ │
│ PROBLEMA: │
│ Tabela: events (500M linhas) │
│ Necessário: Atualizar formato da coluna event_data │
│ │
│ ❌ RUIM: Um UPDATE gigante │
│ UPDATE events SET event_data = transform(event_data); │
│ → Bloqueia tabela por horas │
│ → Log de transação explode │
│ → Aplicação dá timeout │
│ │
│ ✅ BOM: Updates em lotes │
│ │
│ ABORDAGEM: │
│ ┌─────────────────────────────────────────────────────────┐│
│ │ -- Executar em loop, 10k linhas por vez ││
│ │ UPDATE events ││
│ │ SET event_data = transform(event_data) ││
│ │ WHERE id IN ( ││
│ │ SELECT id FROM events ││
│ │ WHERE needs_migration = true ││
│ │ LIMIT 10000 ││
│ │ ); ││
│ │ ││
│ │ -- Dormir entre lotes ││
│ │ SELECT pg_sleep(0.5); ││
│ └─────────────────────────────────────────────────────────┘│
│ │
│ MONITORAMENTO: │
│ • Linhas processadas: 150,000 / 500,000,000 │
│ • Tempo estimado: 8 horas │
│ • Carga do banco: Normal │
│ • Erros: 0 │
│ │
│ EXECUTAR COMO: Job em background, não implantação │
└─────────────────────────────────────────────────────────────┘
Criação de Índice com Zero Tempo de Inatividade
CRIANDO ÍNDICES COM SEGURANÇA:
┌─────────────────────────────────────────────────────────────┐
│ │
│ PROBLEMA: │
│ Necessário índice em tabela grande (100M linhas) │
│ CREATE INDEX bloqueia tabela durante criação │
│ │
│ ❌ RUIM: │
│ CREATE INDEX idx_users_email ON users(email); │
│ → Bloqueia tabela por minutos a horas │
│ │
│ ✅ BOM (PostgreSQL): │
│ CREATE INDEX CONCURRENTLY idx_users_email ON users(email); │
│ → Constrói em background │
│ → Sem bloqueio na tabela │
│ → Ligeiramente mais lento, mas seguro │
│ │
│ ✅ BOM (MySQL 5.6+): │
│ ALTER TABLE users ADD INDEX idx_email(email), │
│ ALGORITHM=INPLACE, LOCK=NONE; │
│ │
│ ─────────────────────────────────────────────────────────── │
│ │
│ CUIDADOS: │
│ │
│ • CONCURRENTLY não funciona em transações │
│ • Se falhar, índice é inválido - deve ser removido │
│ • Monitore espaço em disco (constrói índice ao lado) │
│ • Pode levar mais tempo que CREATE INDEX regular │
│ │
│ TAREFA GITSCRUM: │
│ Labels: database, low-risk │
│ Nota: Usando CONCURRENTLY, nenhum tempo de inatividade esperado│
└─────────────────────────────────────────────────────────────┘
Planejamento de Rollback
Toda Migração Precisa de Rollback
REQUISITOS DE ROLLBACK:
┌─────────────────────────────────────────────────────────────┐
│ │
│ REGRA: NENHUMA MIGRAÇÃO SEM ROLLBACK │
│ │
│ ESTRUTURA DE ARQUIVO DE MIGRAÇÃO: │
│ ┌─────────────────────────────────────────────────────────┐│
│ │ migrations/ ││
│ │ └── 2024_01_15_120000_add_preferences_table.sql ││
│ │ ├── up.sql (migração para frente) ││
│ │ └── down.sql (rollback) ││
│ └─────────────────────────────────────────────────────────┘│
│ │
│ EXEMPLO: │
│ │
│ up.sql: │
│ ┌─────────────────────────────────────────────────────────┐│
│ │ CREATE TABLE user_preferences (...); ││
│ │ CREATE INDEX idx_prefs_user ON user_preferences(...); ││
│ └─────────────────────────────────────────────────────────┘│
│ │
│ down.sql: │
│ ┌─────────────────────────────────────────────────────────┐│
│ │ DROP INDEX IF EXISTS idx_prefs_user; ││
│ │ DROP TABLE IF EXISTS user_preferences; ││
│ └─────────────────────────────────────────────────────────┘│
│ │
│ TESTANDO ROLLBACK: │
│ 1. Executar migração │
│ 2. Verificar sucesso │
│ 3. Executar rollback │
│ 4. Verificar estado limpo │
│ 5. Executar migração novamente │
│ 6. Deve funcionar limpo │
│ │
│ Se rollback for impossível (perda de dados), documente │
└─────────────────────────────────────────────────────────────┘
Coordenação de Implantação
Fluxo de Implantação de Migração
PROCESSO DE IMPLANTAÇÃO DE MIGRAÇÃO:
┌─────────────────────────────────────────────────────────────┐
│ │
│ PRÉ-IMPLANTAÇÃO: │
│ │
│ ☐ Migração testada em staging │
│ ☐ Rollback testado em staging │
│ ☐ Impacto de performance medido │
│ ☐ Janela de implantação agendada │
│ ☐ Equipe notificada │
│ ☐ Backup confirmado │
│ │
│ ─────────────────────────────────────────────────────────── │
│ │
│ ORDEM DE IMPLANTAÇÃO: │
│ │
│ 1. BACKUP │
│ Snapshot do banco antes da migração │
│ │
│ 2. MIGRAR │
│ Executar migração em produção │
│ │
│ 3. VERIFICAR │
│ Confirmar migração bem-sucedida │
│ Verificar estrutura da tabela │
│ Verificar dados se aplicável │
│ │
│ 4. IMPLANTAR CÓDIGO │
│ Implantar aplicação que usa novo esquema │
│ │
│ 5. MONITORAR │
│ Observar por erros │
│ Verificar performance de queries │
│ Verificar comportamento da aplicação │
│ │
│ 6. MARCAR CONCLUÍDO │
│ Atualizar tarefa GitScrum │
│ Documentar quaisquer problemas │
│ │
│ SE PROBLEMAS: │
│ → Fazer rollback da aplicação │
│ → Fazer rollback da migração │
│ → Investigar em staging │
└─────────────────────────────────────────────────────────────┘