Documentação PostgreSQL
Regras da documentação do PostgreSQL 18 que um modelo provavelmente errará: padrões surpreendentes, armadilhas de lock e concorrência, mudanças do PostgreSQL 18 e os padrões que a documentação recomenda. Cada regra termina com o URL da documentação que a fundamenta.
Versão coberta
As referências seguem a documentação do PostgreSQL 18 (versão menor 18.6). Fatos que só valem a partir da versão 18 dizem "PostgreSQL 18". Verifique primeiro a versão do servidor. Em um servidor mais antigo, trate toda regra "PostgreSQL 18" como indisponível.
Como navegar
Leia apenas a referência necessária para a tarefa, na tabela abaixo. Fontes: SOURCES.md.
Regras rápidas
- No PostgreSQL 18, uma coluna gerada sem palavra-chave é VIRTUAL, computada na leitura. Escreva
STOREDpara estatísticas ou replicação lógica. https://www.postgresql.org/docs/18/ddl-generated-columns.html https://www.postgresql.org/docs/18/sql-altertable.html - Use colunas de identidade, não
serial. Uma coluna de identidade é NOT NULL, mas não é única: adicione a PRIMARY KEY. https://www.postgresql.org/docs/18/ddl-identity-columns.html - Indexe as colunas de referência de cada chave estrangeira você mesmo. O PostgreSQL indexa apenas o lado referenciado. https://www.postgresql.org/docs/18/ddl-constraints.html
CREATE INDEXsimples bloqueia escritas durante toda a construção. Em tabelas ativas, useCREATE INDEX CONCURRENTLYfora de um bloco de transação e descarte o índice INVALID que ele deixa em caso de falha. https://www.postgresql.org/docs/18/sql-createindex.html- Adicione restrições a tabelas grandes como
NOT VALIDe depoisVALIDATE CONSTRAINT, que não bloqueia escritas. O PostgreSQL 18 aceita isso também para NOT NULL. https://www.postgresql.org/docs/18/sql-altertable.html ADD COLUMNcom um valor padrão volátil, uma coluna gerada armazenada ou uma identidade reescreve toda a tabela sob ACCESS EXCLUSIVE. Um valor padrão não volátil não faz isso. https://www.postgresql.org/docs/18/sql-altertable.html- Defina
lock_timeoutem sessões de migração, estatement_timeout,lock_timeoutetransaction_timeoutpor papel ou sessão, nunca globalmente. https://www.postgresql.org/docs/18/runtime-config-client.html - Upsert com
INSERT ... ON CONFLICT (cols) DO UPDATE, que no READ COMMITTED sempre insere ou atualiza sob concorrência. MERGE pode falhar com uma violação de unicidade quando outra sessão insere a mesma chave. https://www.postgresql.org/docs/18/transaction-iso.html - Repita a transação inteira em caso de SQLSTATE 40001 e 40P01. O PostgreSQL nunca repete por conta própria. Teste o SQLSTATE, não a mensagem. https://www.postgresql.org/docs/18/mvcc-serialization-failure-handling.html
- O isolamento padrão é READ COMMITTED: cada declaração vê um novo snapshot. Regras de negócio com várias linhas precisam de SERIALIZABLE ou locks explícitos. https://www.postgresql.org/docs/18/transaction-iso.html https://www.postgresql.org/docs/18/applevel-consistency.html
- Para filas de trabalho, use
SELECT ... FOR UPDATE SKIP LOCKEDeFOR NO KEY UPDATEquando as chaves permanecerem inalteradas. https://www.postgresql.org/docs/18/sql-select.html https://www.postgresql.org/docs/18/explicit-locking.html NOT INcom um NULL na lista ou subconsulta nunca é verdadeiro. Agregações diferentes decountretornam NULL para zero linhas. https://www.postgresql.org/docs/18/functions-comparisons.html https://www.postgresql.org/docs/18/functions-aggregate.html- Paginação e
LIMITprecisam de um ORDER BY em uma chave única, caso contrário os resultados diferem entre execuções. https://www.postgresql.org/docs/18/queries-limit.html - Armazene instantes como
timestamptz.TIMESTAMP '2004-10-19 10:23:54+02'é um timestamp sem fuso horário e o offset é descartado. https://www.postgresql.org/docs/18/datatype-datetime.html now()é a hora de início da transação. Useclock_timestamp()para a hora real. Nunca use o padrão da string'now'. https://www.postgresql.org/docs/18/functions-datetime.html- Use
jsonb, indexado comGIN (col jsonb_path_ops)para consultas@>. O operador deve se aplicar à expressão indexada para que o índice seja usado. https://www.postgresql.org/docs/18/datatype-json.html - O PostgreSQL 18 adiciona
uuidv7(), um UUID ordenado por tempo, ao lado degen_random_uuid(). https://www.postgresql.org/docs/18/functions-uuid.html - O
RETURNINGdo PostgreSQL 18 lêold.colenew.colem INSERT, UPDATE, DELETE e MERGE. https://www.postgresql.org/docs/18/dml-returning.html EXPLAIN ANALYZEexecuta a declaração: envolva escritas emBEGIN ... ROLLBACK. No PostgreSQL 18, ele inclui BUFFERS automaticamente. https://www.postgresql.org/docs/18/sql-explain.html https://www.postgresql.org/docs/18/using-explain.html- Uma árvore B de várias colunas pode atender uma consulta sem sua coluna principal no PostgreSQL 18 (skip scan), mas apenas quando essa coluna tem poucos valores distintos. https://www.postgresql.org/docs/18/indexes-multicolumn.html
- Mantenha o autovacuum ligado e evite VACUUM FULL. O autovacuum nunca analisa tabelas particionadas ou tabelas temporárias: ANALYSE-as você mesmo. https://www.postgresql.org/docs/18/routine-vacuuming.html
- A segurança em nível de linha não faz nada até
ENABLE ROW LEVEL SECURITY, e os proprietários da tabela a ignoram a menos que hajaFORCE ROW LEVEL SECURITY. https://www.postgresql.org/docs/18/ddl-rowsecurity.html - Uma função SECURITY DEFINER precisa de
SET search_path = trusted_schema, pg_tempe EXECUTE revogado de PUBLIC na mesma transação. https://www.postgresql.org/docs/18/sql-createfunction.html - Conceder uma tabela não se estende às sequências que ela usa, incluindo as de colunas
serial. Defina privilégios de sequência separadamente. https://www.postgresql.org/docs/18/sql-grant.html - Os clientes usam
sslmode=preferpor padrão, que não verifica o servidor. Usesslmode=verify-full. https://www.postgresql.org/docs/18/libpq-ssl.html - Construa SQL dinâmico com
format('%I', ident)eEXECUTE ... USINGpara valores, nunca por concatenação. https://www.postgresql.org/docs/18/plpgsql-statements.html - Índices de expressão de busca em texto completo devem usar
to_tsvector('english', col)com 2 argumentos, e as consultas devem repetir essa forma exata. https://www.postgresql.org/docs/18/textsearch-tables.html
Referências
| Referência | Leia quando |
|---|---|
| schema-design.md | Criar tabelas: identidade e sequências, colunas geradas, restrições, chaves temporais, domínios, esquemas e search_path, design de particionamento |
| migrations-and-locks.md | Escrever uma migração: níveis de lock e reescritas de ALTER TABLE, NOT VALID, construções de índice concorrente, REINDEX, attach e detach de partição |
| data-types.md | Escolher tipos numéricos, text, bytea, enum, UUID, array ou range, restrições de exclusão em ranges |
| datetime.md | Qualquer coisa com timestamps, fusos horários, intervalos, extract, date_trunc, to_char, to_timestamp |
| json.md | Armazenar, consultar, indexar ou atualizar JSONB, jsonpath, JSON_VALUE, JSON_TABLE, agregações JSON |
| queries.md | Lógica SELECT: semântica de NULL, joins, LATERAL, agrupamento, agregações, funções de janela, paginação, UNION, CTEs |
| writes.md | INSERT ON CONFLICT, UPDATE e DELETE com joins, lotes de grandes alterações, RETURNING, MERGE, COPY, carregamento em massa |
| indexes.md | Escolher ou revisar um índice: tipos, ordem das colunas, skip scan, parcial, expressão, INCLUDE, pattern_ops, GIN, BRIN |
| concurrency.md | Níveis de isolamento, retentativas, locks de linha e tabela, deadlocks, locks consultivos, timeouts, LISTEN e NOTIFY |
| performance.md | Ler EXPLAIN, estatísticas e estatísticas estendidas, vacuum, configurações de memória e planner, consulta paralela, pg_stat_statements |
| security.md | GRANT e privilégios padrão, papéis, segurança em nível de linha, SECURITY DEFINER, senhas, TLS e parâmetros de conexão libpq |
| plpgsql-triggers.md | Escrever funções, PL/pgSQL, SQL dinâmico, exceções, triggers, procedimentos |
| text-search.md | Funções de string, LIKE e regex, citação, busca em texto completo com tsvector, ranking, ts_headline |
Mudanças do PostgreSQL 18 a serem lembradas ao atualizar
initdbhabilita checksums de dados por padrão, epg_upgradeprecisa de configurações correspondentes. https://www.postgresql.org/docs/18/release-18.html- VACUUM e ANALYZE em uma tabela particionada também processam suas partições. Escreva
ONLYpara o pai sozinho. https://www.postgresql.org/docs/18/release-18.html pg_upgrademantém estatísticas do planner, mas não estatísticas estendidas. https://www.postgresql.org/docs/18/release-18.html- Triggers AFTER são executados como o papel ativo quando o evento foi enfileirado. https://www.postgresql.org/docs/18/release-18.html
- I/O assíncrono (
io_method, padrãoworker), eeffective_io_concurrencypadrão é 16. https://www.postgresql.org/docs/18/runtime-config-resource.html
Padrões antigos
| Antigo | Atual |
|---|---|
Literais 'now' ou 'today' em padrões | now(), CURRENT_DATE (https://www.postgresql.org/docs/18/datatype-datetime.html) |
Senhas MD5, método de autenticação password | scram-sha-256 (https://www.postgresql.org/docs/18/auth-password.html) |