PostgreSQL Cheatsheet: Referência Rápida para Desenvolvedores

Referência rápida ao PostgreSQL

Conteúdo da página

Uma referência rápida para o dia a dia PostgreSQL de trabalho: conexões, sintaxe SQL, meta-comandos do psql, desempenho, JSON, funções de janela e muito mais.

Se você deseja uma revisão concisa entre bancos de dados antes de se aprofundar nos detalhes do Postgres, esta folha de referência SQL com os comandos SQL mais úteis é um companheiro útil.

postgresql logo

Conexão e Fundamentos

# Conectar
psql -h HOST -p 5432 -U USER -d DB
psql $DATABASE_URL

# Dentro do psql
\conninfo             -- mostrar conexão
\l[+]                 -- listar bancos de dados
\c DB                 -- conectar ao banco de dados
\dt[+] [schema.]pat   -- listar tabelas
\dv[+]                -- listar views
\ds[+]                -- listar sequências
\df[+] [pat]          -- listar funções
\d[S+] name           -- descrever tabela/view/seq
\dn[+]                -- listar schemas
\du[+]                -- listar roles
\timing               -- alternar tempo de consulta
\x                    -- exibição expandida
\e                    -- editar buffer no $EDITOR
\i file.sql           -- executar arquivo
\copy ...             -- COPY lado cliente
\! shell_cmd          -- executar comando shell

Tipos de Dados (comuns)

  • Numéricos: smallint, integer, bigint, decimal(p,s), numeric, real, double precision, serial, bigserial
  • Texto: text, varchar(n), char(n)
  • Booleano: boolean
  • Temporal: timestamp [with/without time zone], date, time, interval
  • UUID: uuid
  • JSON: json, jsonb (preferido)
  • Array: type[] e.g. text[]
  • Rede: inet, cidr, macaddr
  • Geométrico: point, line, polygon, etc.

Verificar versão do PostgreSQL

SELECT version();

Versão do Servidor PostgreSQL:

pg_config --version

Versão do Cliente PostgreSQL:

psql --version

DDL (Criar / Alterar)

-- Criar schema e tabela
CREATE SCHEMA IF NOT EXISTS app;
CREATE TABLE app.users (
  id           bigserial PRIMARY KEY,
  email        text NOT NULL UNIQUE,
  name         text,
  active       boolean NOT NULL DEFAULT true,
  created_at   timestamptz NOT NULL DEFAULT now(),
  profile      jsonb,
  tags         text[]
);

-- Alterar
ALTER TABLE app.users ADD COLUMN last_login timestamptz;
ALTER TABLE app.users ALTER COLUMN name SET NOT NULL;
ALTER TABLE app.users DROP COLUMN tags;

-- Constraints
ALTER TABLE app.users ADD CONSTRAINT email_lower_uk UNIQUE (lower(email));

-- Índices
CREATE INDEX ON app.users (email);
CREATE UNIQUE INDEX CONCURRENTLY users_email_uidx ON app.users (lower(email));
CREATE INDEX users_profile_gin ON app.users USING gin (profile);
CREATE INDEX users_created_at_idx ON app.users (created_at DESC);

DML (Inserir / Atualizar / Upsert / Deletar)

INSERT INTO app.users (email, name) VALUES
  ('a@x.com','A'), ('b@x.com','B')
RETURNING id;

-- Upsert (ON CONFLICT)
INSERT INTO app.users (email, name)
VALUES ('a@x.com','Alice')
ON CONFLICT (email)
DO UPDATE SET name = EXCLUDED.name, updated_at = now();

UPDATE app.users SET active = false WHERE last_login < now() - interval '1 year';
DELETE FROM app.users WHERE active = false AND last_login IS NULL;

Essenciais de Consulta

SELECT * FROM app.users ORDER BY created_at DESC LIMIT 20 OFFSET 40; -- paginação

-- Filtragem
SELECT * FROM app.users WHERE email ILIKE '%@example.%' AND active;

-- Agregados & GROUP BY
SELECT active, count(*) AS n
FROM app.users
GROUP BY active
HAVING count(*) > 10;

-- Joins
SELECT o.id, u.email, o.total
FROM app.orders o
JOIN app.users u ON u.id = o.user_id
LEFT JOIN app.discounts d ON d.id = o.discount_id;

-- DISTINCT ON (específico do Postgres)
SELECT DISTINCT ON (user_id) user_id, status, created_at
FROM app.events
ORDER BY user_id, created_at DESC;

-- CTEs
WITH recent AS (
  SELECT * FROM app.orders WHERE created_at > now() - interval '30 days'
)
SELECT count(*) FROM recent;

-- CTE Recursiva
WITH RECURSIVE t(n) AS (
  SELECT 1
  UNION ALL
  SELECT n+1 FROM t WHERE n < 10
)
SELECT sum(n) FROM t;

Funções de Janela

SELECT
  user_id,
  created_at,
  sum(total)      OVER (PARTITION BY user_id ORDER BY created_at) AS running_total,
  row_number()    OVER (PARTITION BY user_id ORDER BY created_at) AS rn,
  lag(total, 1)   OVER (PARTITION BY user_id ORDER BY created_at) AS prev_total
FROM app.orders;

JSON / JSONB

-- Extração
SELECT profile->>'company' AS company FROM app.users;
SELECT profile->'address'->>'city' FROM app.users;

-- Índice para consultas jsonb
CREATE INDEX users_profile_company_gin ON app.users USING gin ((profile->>'company'));

-- Existência / Contenção
SELECT * FROM app.users WHERE profile ? 'company';              -- chave existe
SELECT * FROM app.users WHERE profile @> '{"role":"admin"}'; -- contém

-- Atualizar jsonb
UPDATE app.users
SET profile = jsonb_set(COALESCE(profile,'{}'::jsonb), '{prefs,theme}', '"dark"', true);

Arrays

-- Membro e contenção
SELECT * FROM app.users WHERE 'vip' = ANY(tags);
SELECT * FROM app.users WHERE tags @> ARRAY['beta'];

-- Adicionar
UPDATE app.users SET tags = array_distinct(tags || ARRAY['vip']);

Tempo e Datas

SELECT now() AT TIME ZONE 'Australia/Melbourne';
SELECT date_trunc('day', created_at) AS d, count(*)
FROM app.users GROUP BY d ORDER BY d;

-- Intervalos
SELECT now() - interval '7 days';

Transações e Locks

BEGIN;
UPDATE app.accounts SET balance = balance - 100 WHERE id = 1;
UPDATE app.accounts SET balance = balance + 100 WHERE id = 2;
COMMIT; -- or ROLLBACK

-- Nível de isolamento
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;

-- Verificar locks
SELECT * FROM pg_locks l JOIN pg_stat_activity a USING (pid);

Roles e Permissões

-- Criar role/usuário
CREATE ROLE app_user LOGIN PASSWORD 'secret';
GRANT USAGE ON SCHEMA app TO app_user;
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA app TO app_user;
ALTER DEFAULT PRIVILEGES IN SCHEMA app GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO app_user;

Importar / Exportar

-- Lado do servidor (requer superusuário ou permissões adequadas)
COPY app.users TO '/tmp/users.csv' CSV HEADER;
COPY app.users(email,name) FROM '/tmp/users.csv' CSV HEADER;

-- Lado do cliente (psql)
\copy app.users TO 'users.csv' CSV HEADER
\copy app.users(email,name) FROM 'users.csv' CSV HEADER

Desempenho e Observabilidade

EXPLAIN (ANALYZE, BUFFERS, VERBOSE) SELECT ...;  -- tempo de execução real

-- Views de estatísticas
SELECT * FROM pg_stat_user_tables;
SELECT * FROM pg_stat_statements ORDER BY total_time DESC LIMIT 20; -- precisa de extensão

-- Manutenção
VACUUM [FULL] [VERBOSE] table_name;
ANALYZE table_name;
REINDEX TABLE table_name;

Para uma visão geral mais ampla das ferramentas essenciais de desenvolvedor, incluindo Docker, Git e PostgreSQL, veja Ferramentas de Desenvolvedor: O Guia Completo para Fluxos de Trabalho Modernos.

Habilite extensões conforme necessário:

CREATE EXTENSION IF NOT EXISTS pg_stat_statements;
CREATE EXTENSION IF NOT EXISTS btree_gin;
CREATE EXTENSION IF NOT EXISTS pg_trgm; -- busca por trigramas

Busca por Texto Completo (rápido)

ALTER TABLE app.docs ADD COLUMN tsv tsvector;
UPDATE app.docs SET tsv = to_tsvector('english', coalesce(title,'') || ' ' || coalesce(body,''));
CREATE INDEX docs_tsv_idx ON app.docs USING gin(tsv);
SELECT id FROM app.docs WHERE tsv @@ plainto_tsquery('english', 'quick brown fox');

Se você está decidindo quando a busca nativa do Postgres é suficiente versus quando executar uma stack de busca separada, esta comparação entre busca por texto completo do PostgreSQL e Elasticsearch cobre as compensações em profundidade.


Configurações Úteis do psql

\pset pager off       -- desativar pager
\pset null '∅'
\pset format aligned  -- outros: unaligned, csv
\set ON_ERROR_STOP on
\timing on

Consultas de Catálogo Úteis

-- Tamanho da tabela
SELECT relname, pg_size_pretty(pg_total_relation_size(relid)) AS size
FROM pg_catalog.pg_statio_user_tables ORDER BY pg_total_relation_size(relid) DESC;

-- Inchaço de índices (aprox.)
SELECT schemaname, relname, indexrelname, idx_scan
FROM pg_stat_user_indexes ORDER BY idx_scan ASC NULLS FIRST LIMIT 20;

Backup / Restauração

# Dump lógico
pg_dump -h HOST -U USER -d DB -F c -f db.dump        # formato customizado
pg_restore -h HOST -U USER -d NEW_DB -j 4 db.dump

# SQL puro
pg_dump -h HOST -U USER -d DB > dump.sql
psql -h HOST -U USER -d DB -f dump.sql

Para ferramentas de gerenciamento de banco de dados com interface gráfica, veja DBeaver vs Beekeeper - Ferramentas de Gerenciamento de Banco de Dados SQL e Instalar DBeaver no Linux - howto.


Replicação (visão geral)

  • Arquivos WAL fluem de primáriostandby
  • Configurações-chave: wal_level, max_wal_senders, hot_standby, primary_conninfo
  • Ferramentas: pg_basebackup, standby.signal (PG ≥12)

Armadilhas e Dicas

  • Sempre use jsonb, não json, para indexação e operadores.
  • Prefira timestamptz (consciente de fuso horário).
  • DISTINCT ON é ouro do Postgres para “top‑N por grupo”.
  • Use GENERATED ALWAYS AS IDENTITY em vez de serial.
  • Evite SELECT * em consultas de produção.
  • Crie índices para filtros seletivos e chaves de join.
  • Meça com EXPLAIN (ANALYZE) antes de otimizar.

Detalhes específicos de versão (≥v12+)

-- Identidade gerada
CREATE TABLE t (id bigINT GENERATED ALWAYS AS IDENTITY, ...);

-- UPSERT com índice parcial
CREATE UNIQUE INDEX ON t (key) WHERE is_active;

Assinar

Receba novos artigos sobre sistemas, infraestrutura e engenharia de IA.