MVCC e isolation levels de verdade (sem simplificação)
⏱ 14 min·⭐ 60 XP
Ao terminar: Você explica por que o Postgres não trava leitura, o que xmin/xmax fazem, e qual nível de isolamento sua transação realmente precisa.
MVCC em 1 query
-- Inspect xmin/xmax diretamente
SELECT xmin, xmax, * FROM users WHERE id = 1;
-- UPDATE cria NOVA versão
BEGIN;
UPDATE users SET email = 'new' WHERE id = 1;
-- Row antiga: xmax = current_xact
-- Row nova: xmin = current_xact
-- Outras txs ainda veem antiga até COMMIT
-- Dead tuples acumulam → vacuum periódico
VACUUM ANALYZE users;Transações
Transação Acomeçou antes
Transação Batualiza a linha
Versões da linha
Versão antigacriada por uma transação já concluída
Versão novacriada por B; invisível até B confirmar
Marcas de criação e remoçãocada versão sabe quem a criou e quem a apagou
Consequências
Leitura não trava escritae vice-versa
Versões mortasninguém mais as enxerga e elas ocupam disco
Limpezarecupera o espaço das versões mortas
- → cria
- → a antiga é marcada como removida
- → ainda enxerga
- → quando ninguém mais a vê
- Compute
- Conceito de arquitetura
Toda a mecânica sai de uma decisão: atualizar cria versão em vez de sobrescrever. Dela vêm a concorrência boa, o inchaço e o fato de uma transação esquecida ser capaz de degradar o banco inteiro.
- 1 · Atualizar não sobrescreve — cria versão. A linha antiga continua no disco, marcada como removida por aquela transação. É essa escolha que sustenta tudo o mais.
- 2 · Cada transação enxerga um instantâneo. A transação que começou antes continua vendo a versão antiga, mesmo depois de B confirmar. Não é dado velho por acidente: é a garantia de consistência dela.
- 3 · Leitor não bloqueia escritor. É a consequência prática mais importante. Uma consulta longa de relatório não trava as escritas, porque ela lê versões que ninguém está alterando.
- 4 · O nível de isolamento é quando o instantâneo é tirado. Por comando ou por transação — essa é a diferença essencial entre os níveis mais usados, e ela explica por que um vê mudança no meio da transação e o outro não.
- 5 · O custo é acumular versão morta. Toda atualização deixa lixo. Sem limpeza, a tabela cresce mesmo com o número de linhas estável, e a leitura fica mais lenta porque percorre versões que já não valem.
- 6 · Transação aberta e esquecida bloqueia a limpeza. A limpeza só remove o que NENHUMA transação ainda pode ver. Uma conexão ociosa com transação aberta segura versões antigas por horas — é a causa mais comum de inchaço.
Isolation levels em Postgres
| Level | Dirty read | Non-repeatable read | Phantom | Serialization anomaly |
|---|---|---|---|---|
| Read Uncommitted* | Possível em padrão | Sim | Sim | Sim |
| Read Committed (default) | Impossível | Sim | Sim | Sim |
| Repeatable Read | Impossível | Impossível | Impossível (em PG) | Sim |
| Serializable | Impossível | Impossível | Impossível | Impossível |
LevelRead Uncommitted*
Dirty readPossível em padrão
Non-repeatable readSim
PhantomSim
Serialization anomalySim
LevelRead Committed (default)
Dirty readImpossível
Non-repeatable readSim
PhantomSim
Serialization anomalySim
LevelRepeatable Read
Dirty readImpossível
Non-repeatable readImpossível
PhantomImpossível (em PG)
Serialization anomalySim
LevelSerializable
Dirty readImpossível
Non-repeatable readImpossível
PhantomImpossível
Serialization anomalyImpossível
💡
*No PG, Read Uncommitted é tratado como Read Committed — dirty read NUNCA acontece. Em MySQL/SQL Server dirty read é real em RU.
Quiz rápido
Qual anomalia o nível de isolamento padrão da maioria dos bancos NÃO previne?
Quando usar cada level
- Read Committed (default): web CRUD — 95% dos casos.
- Repeatable Read: report que faz múltiplas queries e quer snapshot consistente (ex: dashboard).
- Serializable + retry: transações financeiras sensíveis onde consistência > throughput.
- SELECT FOR UPDATE: locking explícito em Read Committed pra evitar lost update.
Perguntas frequentes
❓ O que o MVCC realmente faz?
Mantém versões da mesma linha para que leitura não espere escrita: cada transação vê a versão consistente com o instante em que começou. É o que dá leitura concorrente sem trava — e o preço é a versão antiga permanecer no disco até ser recolhida.
❓ Leitura nunca bloqueia no Postgres?
Leitura comum não bloqueia escrita nem é bloqueada por ela. Mas leitura com trava explícita bloqueia, e alteração de esquema pega trava que bloqueia tudo. Dizer "leitura nunca espera" é a simplificação que faz alguém rodar mudança de esquema em horário de pico.
❓ Por que a transação vê dado antigo?
Porque no nível de isolamento repetível ela fixa uma visão no início e mantém — é comportamento correto, não defeito. Aplicação que espera ver escrita de outra transação dentro de uma transação longa está usando o nível errado, ou deveria ter fechado a transação.
Fixando
Quiz rápido
Quando o nível serializável é a escolha certa, apesar do custo?
Quiz rápido
O que a aplicação precisa fazer ao usar o nível mais estrito?
Terminou de ler?
Marcar como concluído registra o XP, mantém sua sequência e coloca 3 cartas deste módulo na fila de revisão espaçada.
Próximos passos sugeridos
Temas deste módulo
Discussão
Carregando comentários…