A migração que trava a tabela
A maioria das migrações é instantânea, e é por isso que as que não são pegam de surpresa. O que decide isso não é o tamanho da tabela. É se o banco precisa reescrevê-la.
O que é instantâneo no Postgres
Adicionar uma coluna anulável é instantâneo. Desde o Postgres 11, adicionar uma coluna com valor padrão constante também é: o padrão fica registrado no catálogo e não é escrito em cada linha existente.
Remover uma coluna é instantâneo. A coluna é marcada como morta, e o espaço é recuperado depois.
Renomear uma coluna ou uma tabela é instantâneo, porque só o catálogo muda.
Isso cobre a maior parte do que um arquivo de migração contém, e é por isso que as mudanças de esquema do dia a dia parecem de graça.
O que reescreve a tabela
Mudar o tipo de uma coluna geralmente reescreve a tabela, porque cada valor existente precisa ser convertido.
Adicionar uma restrição NOT NULL a uma coluna existente exige uma varredura completa, para provar que não há nulos.
Adicionar um índice sem CONCURRENTLY toma um lock que bloqueia as escritas durante toda a construção.
Mudar um valor padrão é instantâneo, mas preencher as linhas existentes para combinar com ele não é, e essa diferença pega as pessoas o tempo todo.
flowchart TB
M["uma migração"] --> C{"ela reescreve linhas?"}
C -->|não| I["só catálogo. instantânea, em qualquer tamanho"]
C -->|sim| L["uma reescrita sob ACCESS EXCLUSIVE"]
L --> B["toda leitura e escrita na tabela espera"]
B --> S["a duração escala com o número de linhas"]
O problema é o lock, mais que a duração
Uma reescrita segura um lock ACCESS EXCLUSIVE, que bloqueia toda leitura e toda escrita naquela tabela até terminar.
Dez segundos disso numa tabela movimentada são uma queda. As requisições se enfileiram atrás, as conexões se acumulam, e o pool se esgota muito antes de a migração terminar.
É pior do que parece. O Postgres enfileira os pedidos de lock em ordem, então um ALTER TABLE esperando o próprio lock bloqueia toda query que chega depois dele. Isso inclui leituras simples que não teriam conflito. Uma migração lenta pode travar uma tabela que ela ainda nem começou a modificar.
Onde esta aplicação está
Em setembro de 2026, a maior tabela aqui era quiz_options, com cerca de 40.000 linhas, e lessons tinha 2519. Forçar uma reescrita completa de qualquer uma delas levou menos de 200 milissegundos localmente.
Então este curso não descreve um problema que esta aplicação tem. Ele descreve o problema que ela teria com cem vezes o tamanho, e as ferramentas que existem porque outras pessoas o encontraram primeiro.
Saber quais migrações são seguras é útil em qualquer escala. Saber por que as inseguras são inseguras é o que dá sentido às ferramentas das próximas lições.
Pontos-chave
- Adicionar colunas anuláveis, adicionar padrões constantes, remover e renomear só mexem no catálogo, então são instantâneos.
- Mudanças de tipo,
NOT NULLem colunas existentes e índices não concorrentes reescrevem ou varrem a tabela. - Uma reescrita segura
ACCESS EXCLUSIVE, bloqueando toda leitura e escrita até terminar. - Um
ALTER TABLEem espera bloqueia as queries que chegam atrás dele, inclusive leituras inofensivas. - As tabelas desta aplicação são pequenas, e o raciocínio importa em qualquer tamanho.
Continue com a aula 2
Como o gh-ost funciona
Como o gh-ost cria uma tabela sombra, copia em lotes, lê o log binário e troca os nomes.
Com uma conta grátis você também tem os quizzes, seu progresso e suas anotações, e a discussão.